summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu/icu-xetex/test/intltest
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/icu/icu-xetex/test/intltest')
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/Makefile.in114
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/aliastst.cpp287
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/aliastst.h30
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/allcoll.cpp212
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/allcoll.h57
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/apicoll.cpp2325
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/apicoll.h179
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/astrotst.cpp436
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/astrotst.h49
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/calcasts.cpp386
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/calcasts.h63
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/callimts.cpp135
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/callimts.h41
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/calregts.cpp2658
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/calregts.h92
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/caltest.cpp1994
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/caltest.h224
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/caltztst.cpp240
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/caltztst.h65
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/canittst.cpp330
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/canittst.h59
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/citrtest.cpp1185
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/citrtest.h46
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/cntabcol.cpp249
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/cntabcol.h41
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/convtest.cpp1423
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/convtest.h104
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/cpdtrtst.cpp442
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/cpdtrtst.h64
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/csdetest.cpp518
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/csdetest.h39
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/currcoll.cpp158
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/currcoll.h39
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dadrcal.cpp457
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dadrcal.h52
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dadrcoll.cpp290
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dadrcoll.h59
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dadrfmt.cpp318
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dadrfmt.h52
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dcfmapts.cpp419
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dcfmapts.h35
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/decoll.cpp146
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/decoll.h50
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtfmapts.cpp354
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtfmapts.h43
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtfmrgts.cpp1461
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtfmrgts.h59
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtfmtrtts.cpp558
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtfmtrtts.h96
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtfmttst.cpp2937
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtfmttst.h217
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtptngts.cpp442
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/dtptngts.h31
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/encoll.cpp334
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/encoll.h48
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/escoll.cpp116
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/escoll.h49
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ficoll.cpp102
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ficoll.h48
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/fldset.cpp351
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/fldset.h186
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/frcoll.cpp217
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/frcoll.h52
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/g7coll.cpp302
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/g7coll.h77
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/icusvtst.cpp1511
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/icusvtst.h62
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/idnaconf.cpp352
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/idnaconf.h49
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/idnaref.cpp1048
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/idnaref.h228
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/incaltst.cpp813
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/incaltst.h53
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/intltest.cpp1590
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/intltest.h250
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/intltest.vcproj1269
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itercoll.cpp647
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itercoll.h119
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itformat.cpp132
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itformat.h27
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itmajor.cpp203
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itmajor.h26
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itrbbi.cpp48
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itrbbi.h31
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itrbnf.cpp1938
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itrbnf.h147
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itrbnfp.cpp183
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itrbnfp.h48
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itrbnfrt.cpp364
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itrbnfrt.h99
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ittrans.cpp56
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ittrans.h31
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itutil.cpp66
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/itutil.h24
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/jacoll.cpp199
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/jacoll.h65
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/jamotest.cpp553
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/jamotest.h60
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/lcukocol.cpp88
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/lcukocol.h40
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/loctest.cpp2136
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/loctest.h167
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/miscdtfm.cpp378
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/miscdtfm.h37
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/mnkytst.cpp269
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/mnkytst.h54
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/msfmrgts.cpp966
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/msfmrgts.h55
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/nmfmapts.cpp409
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/nmfmapts.h33
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/nmfmtrt.cpp351
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/nmfmtrt.h77
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/normconf.cpp581
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/normconf.h105
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/nptrans.cpp289
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/nptrans.h164
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp2412
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.h219
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/numrgts.cpp2647
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/numrgts.h103
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/pptest.cpp227
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/pptest.h37
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/punyref.c302
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/punyref.h116
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/rbbiapts.cpp1118
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/rbbiapts.h97
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/rbbitst.cpp4287
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/rbbitst.h130
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/regcoll.cpp1215
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/regcoll.h244
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/regextst.cpp2127
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/regextst.h46
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/reptest.cpp322
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/reptest.h43
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/restest.cpp628
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/restest.h55
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/restsnew.cpp1180
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/restsnew.h59
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/rndmcoll.cpp176
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/rndmcoll.h29
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/sdtfmtts.cpp238
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/sdtfmtts.h31
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/sfwdchit.cpp120
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/sfwdchit.h77
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/srchtest.cpp2350
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/srchtest.h96
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/strcase.cpp542
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/strtest.cpp192
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/strtest.h38
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/svccoll.cpp586
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/svccoll.h46
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tchcfmt.cpp652
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tchcfmt.h55
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/testidn.cpp450
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/testidna.cpp1583
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/testidna.h120
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/testutil.cpp37
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/testutil.h34
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/textfile.cpp179
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/textfile.h72
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tfsmalls.cpp387
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tfsmalls.h27
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/thcoll.cpp459
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/thcoll.h80
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tmsgfmt.cpp1256
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tmsgfmt.h96
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tokiter.cpp107
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tokiter.h71
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/transapi.cpp984
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/transapi.h78
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/transrt.cpp1708
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/transrt.h49
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/transtst.cpp4652
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/transtst.h421
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/trcoll.cpp106
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/trcoll.h49
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/trnserr.cpp283
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/trnserr.h54
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tscoll.cpp513
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tscoll.h52
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsdate.cpp288
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsdate.h82
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsdcfmsy.cpp185
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsdcfmsy.h35
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsdtfmsy.cpp347
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsdtfmsy.h39
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsmthred.cpp1585
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsmthred.h46
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsnmfmt.cpp441
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsnmfmt.h89
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsputil.cpp565
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tsputil.h47
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tstnorm.cpp1798
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tstnorm.h84
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tstnrapi.cpp187
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzbdtest.cpp513
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzbdtest.h99
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzfmttst.cpp458
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzfmttst.h27
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzoffloc.cpp329
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzoffloc.h26
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzregts.cpp1219
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzregts.h61
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzrulets.cpp2087
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tzrulets.h50
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tztest.cpp1664
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/tztest.h101
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ucaconf.cpp265
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ucaconf.h52
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ucdtest.cpp217
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ucdtest.h45
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/uobjtest.cpp466
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/uobjtest.h42
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/usettest.cpp3773
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/usettest.h190
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ustrtest.cpp1703
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/ustrtest.h96
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/utxttest.cpp1400
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/utxttest.h61
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/uvectest.cpp200
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/uvectest.h34
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/v32test.cpp495
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/v32test.h32
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/wbnf.cpp1771
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/wbnf.h157
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/windttst.cpp197
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/windttst.h41
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/winnmtst.cpp323
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/winnmtst.h41
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/winutil.cpp81
-rw-r--r--Build/source/libs/icu/icu-xetex/test/intltest/winutil.h46
231 files changed, 103661 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/Makefile.in b/Build/source/libs/icu/icu-xetex/test/intltest/Makefile.in
new file mode 100644
index 00000000000..27a0424b3bd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/Makefile.in
@@ -0,0 +1,114 @@
+#******************************************************************************
+#
+# Copyright (C) 1999-2007, International Business Machines
+# Corporation and others. All Rights Reserved.
+#
+#******************************************************************************
+## Makefile.in for ICU - test/intltest
+
+## Source directory information
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+
+top_builddir = ../..
+
+## All the flags and other definitions are included here.
+include $(top_builddir)/icudefs.mk
+
+## Build directory information
+subdir = test/intltest
+
+## Extra files to remove for 'make clean'
+CLEANFILES = *~ $(DEPS)
+
+## Target information
+TARGET = intltest$(EXEEXT)
+
+BUILDDIR := $(CURR_SRCCODE_FULL_DIR)/../../
+# Simplify the path for Unix
+BUILDDIR := $(BUILDDIR:test/intltest/../../=)
+# Simplify the path for Windows
+BUILDDIR := $(BUILDDIR:test\\intltest/../../=)
+# Simplify the path for Windows 98
+BUILDDIR := $(BUILDDIR:TEST\\INTLTEST/../../=)
+
+ifneq ($(top_builddir),$(top_srcdir))
+CPPFLAGS += -I$(top_builddir)/common
+endif
+CPPFLAGS += -I$(top_srcdir)/common -I$(top_srcdir)/i18n -I$(top_srcdir)/tools/toolutil -I$(top_srcdir)/tools/ctestfw
+DEFS += -D'U_TOPSRCDIR="$(top_srcdir)/"' -D'U_TOPBUILDDIR="$(BUILDDIR)"'
+LIBS = $(LIBCTESTFW) $(LIBICUI18N) $(LIBICUUC) $(LIBICUTOOLUTIL) $(DEFAULT_LIBS) $(LIB_M) $(LIB_THREAD)
+
+OBJECTS = aliastst.o allcoll.o apicoll.o astrotst.o callimts.o calregts.o caltest.o \
+caltztst.o canittst.o citrtest.o cntabcol.o convtest.o currcoll.o \
+fldset.o dadrfmt.o dadrcal.o dadrcoll.o dcfmapts.o decoll.o dtfmapts.o dtfmrgts.o dtfmtrtts.o dtfmttst.o \
+dtptngts.o encoll.o escoll.o ficoll.o frcoll.o g7coll.o intltest.o \
+itercoll.o itformat.o itmajor.o itutil.o jacoll.o lcukocol.o \
+loctest.o miscdtfm.o mnkytst.o msfmrgts.o nmfmapts.o nmfmtrt.o \
+numfmtst.o numrgts.o pptest.o regcoll.o restest.o restsnew.o \
+sdtfmtts.o svccoll.o tchcfmt.o \
+tfsmalls.o tmsgfmt.o trcoll.o tscoll.o tsdate.o tsdcfmsy.o tsdtfmsy.o \
+tsmthred.o tsnmfmt.o tsputil.o tstnrapi.o tstnorm.o tzbdtest.o \
+tzregts.o tztest.o ucdtest.o usettest.o ustrtest.o strcase.o transtst.o strtest.o thcoll.o \
+itrbbi.o rbbiapts.o rbbitst.o ittrans.o transapi.o cpdtrtst.o \
+testutil.o transrt.o trnserr.o normconf.o sfwdchit.o \
+jamotest.o srchtest.o reptest.o regextst.o \
+itrbnf.o itrbnfrt.o itrbnfp.o ucaconf.o icusvtst.o \
+uobjtest.o idnaref.o idnaconf.o nptrans.o punyref.o testidn.o testidna.o incaltst.o \
+calcasts.o v32test.o uvectest.o textfile.o tokiter.o utxttest.o \
+windttst.o winnmtst.o winutil.o csdetest.o tzrulets.o tzoffloc.o tzfmttst.o
+
+
+DEPS = $(OBJECTS:.o=.d)
+
+-include Makefile.local
+
+## List of phony targets
+.PHONY : all all-local install install-local clean clean-local \
+distclean distclean-local dist dist-local check check-local
+
+## Clear suffix list
+.SUFFIXES :
+
+## List of standard targets
+all: all-local
+install: install-local
+clean: clean-local
+distclean : distclean-local
+dist: dist-local
+check: all check-local
+
+all-local: $(TARGET)
+
+install-local:
+
+dist-local:
+
+clean-local:
+ test -z "$(CLEANFILES)" || $(RMV) $(CLEANFILES)
+ $(RMV) $(OBJECTS) $(TARGET)
+
+distclean-local: clean-local
+ $(RMV) Makefile
+
+check-local: all-local
+ $(INVOKE) ./$(TARGET) $(INTLTEST_OPTS) || true
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) \
+ && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+$(TARGET) : $(OBJECTS)
+ $(LINK.cc) $(OUTOPT)$@ $^ $(LIBS)
+ $(POST_BUILD_STEP)
+
+ifeq (,$(MAKECMDGOALS))
+-include $(DEPS)
+else
+ifneq ($(patsubst %clean,,$(MAKECMDGOALS)),)
+ifneq ($(patsubst %install,,$(MAKECMDGOALS)),)
+-include $(DEPS)
+endif
+endif
+endif
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/aliastst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/aliastst.cpp
new file mode 100644
index 00000000000..3abb2959edb
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/aliastst.cpp
@@ -0,0 +1,287 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2005-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "aliastst.h"
+#include "unicode/calendar.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/datefmt.h"
+#include "unicode/unistr.h"
+#include "unicode/coll.h"
+#include "unicode/resbund.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+const char* _LOCALE_ALIAS[][2] = {
+ {"in", "id"},
+ {"in_ID", "id_ID"},
+ {"iw", "he"},
+ {"iw_IL", "he_IL"},
+ {"ji", "yi"},
+ {"en_BU", "en_MM"},
+ {"en_DY", "en_BJ"},
+ {"en_HV", "en_BF"},
+ {"en_NH", "en_VU"},
+ {"en_RH", "en_ZW"},
+ {"en_TP", "en_TL"},
+ {"en_ZR", "en_CD"}
+};
+
+const int _LOCALE_NUMBER = 12;
+
+void LocaleAliasTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ){
+ switch (index) {
+ TESTCASE(0, TestCalendar);
+ TESTCASE(1, TestDateFormat);
+ TESTCASE(2, TestCollation);
+ TESTCASE(3, TestULocale);
+ TESTCASE(4, TestUResourceBundle);
+ TESTCASE(5, TestDisplayName);
+ // keep the last index in sync with the condition in default:
+
+ default:
+ if (index <= 5) { // keep this in sync with the last index!
+ name = "(test omitted by !UCONFIG_NO_FORMATTING)";
+ } else {
+ name = "";
+ }
+ break; //needed to end loop
+ }
+}
+
+void LocaleAliasTest::TestCalendar() {
+#if !UCONFIG_NO_FORMATTING
+ UErrorCode status = U_ZERO_ERROR;
+ for (int i=0; i<_LOCALE_NUMBER; i++) {
+ Locale oldLoc(_LOCALE_ALIAS[i][0]);
+ Locale newLoc(_LOCALE_ALIAS[i][1]);
+ if(!isLocaleAvailable(_LOCALE_ALIAS[i][1])){
+ logln(UnicodeString(newLoc.getName())+" is not available. Skipping!");
+ continue;
+ }
+ logln("\nold locale:%s new locale:%s",oldLoc.getName(),newLoc.getName());
+ Calendar* c1 = Calendar::createInstance(oldLoc, status);
+ Calendar* c2 = Calendar::createInstance(newLoc, status);
+
+ //Test function "getLocale(ULocale.VALID_LOCALE)"
+ const char* l1 = c1->getLocaleID(ULOC_VALID_LOCALE, status);
+ const char* l2 = c2->getLocaleID(ULOC_VALID_LOCALE, status);
+ if (strcmp(newLoc.getName(), l1)!=0) {
+ errln("CalendarTest: newLoc!=l1: newLoc= "+UnicodeString(newLoc.getName()) +" l1= "+UnicodeString(l1));
+ }
+ if (strcmp(l1, l2)!=0) {
+ errln("CalendarTest: l1!=l2: l1= "+UnicodeString(l1) +" l2= "+UnicodeString(l2));
+ }
+ if(!(c1==c2)){
+ errln("CalendarTest: c1!=c2. newLoc= "+UnicodeString(newLoc.getName()) +" oldLoc= "+UnicodeString(oldLoc.getName()));
+ }
+ logln("Calendar(getLocale) old:"+UnicodeString(l1)+" new:"+UnicodeString(l2));
+ delete c1;
+ delete c2;
+ }
+#endif
+}
+void LocaleAliasTest::TestDateFormat() {
+#if !UCONFIG_NO_FORMATTING
+ UErrorCode status = U_ZERO_ERROR;
+ for (int i=0; i<_LOCALE_NUMBER; i++) {
+ Locale oldLoc(_LOCALE_ALIAS[i][0]);
+ Locale newLoc(_LOCALE_ALIAS[i][1]);
+ if(!isLocaleAvailable(_LOCALE_ALIAS[i][1])){
+ logln(UnicodeString(newLoc.getName())+" is not available. Skipping!");
+ continue;
+ }
+ logln("\nold locale:%s new locale:%s",oldLoc.getName(),newLoc.getName());
+
+ DateFormat* df1 = DateFormat::createDateInstance(DateFormat::FULL, oldLoc);
+ DateFormat* df2 = DateFormat::createDateInstance(DateFormat::FULL, newLoc);
+
+ //Test function "getLocale"
+ const char* l1 = df1->getLocaleID(ULOC_VALID_LOCALE, status);
+ const char* l2 = df2->getLocaleID(ULOC_VALID_LOCALE, status);
+ if (strcmp(newLoc.getName(), l1)!=0) {
+ errln("CalendarTest: newLoc!=l1: newLoc= "+UnicodeString(newLoc.getName()) +" l1= "+UnicodeString(l1));
+ }
+ if (strcmp(l1, l2)!=0) {
+ errln("TestDateFormat: l1!=l2: l1= "+UnicodeString(l1) +" l2= "+UnicodeString(l2));
+ }
+ if(!(df1==df2)){
+ errln("TestDateFormat: c1!=c2. newLoc= "+UnicodeString(newLoc.getName()) +" oldLoc= "+UnicodeString(oldLoc.getName()));
+ }
+ logln("DateFormat(getLocale) old:%s new:%s",l1,l2);
+
+ delete df1;
+ delete df2;
+ }
+#endif
+}
+void LocaleAliasTest::TestCollation() {
+#if !UCONFIG_NO_COLLATION
+ UErrorCode status = U_ZERO_ERROR;
+ for (int i=0; i<_LOCALE_NUMBER; i++) {
+ Locale oldLoc(_LOCALE_ALIAS[i][0]);
+ Locale newLoc(_LOCALE_ALIAS[i][1]);
+ if(!isLocaleAvailable(_LOCALE_ALIAS[i][1])){
+ logln(UnicodeString(newLoc.getName())+" is not available. Skipping!");
+ continue;
+ }
+ logln("\nold locale:%s new locale:%s",oldLoc.getName(),newLoc.getName());
+
+ Collator* c1 = Collator::createInstance(oldLoc, status);
+ Collator* c2 = Collator::createInstance(newLoc, status);
+
+ Locale l1 = c1->getLocale(ULOC_VALID_LOCALE, status);
+ Locale l2 = c2->getLocale(ULOC_VALID_LOCALE, status);
+
+ if (strcmp(newLoc.getName(), l1.getName())!=0) {
+ errln("CalendarTest: newLoc!=l1: newLoc= "+UnicodeString(newLoc.getName()) +" l1= "+UnicodeString(l1.getName()));
+ }
+ if (strcmp(l1.getName(), l2.getName())!=0) {
+ errln("CollationTest: l1!=l2: l1= "+UnicodeString(l1.getName()) +" l2= "+UnicodeString(l2.getName()));
+ }
+ if(!(c1==c2)){
+ errln("CollationTest: c1!=c2. newLoc= "+UnicodeString(newLoc.getName()) +" oldLoc= "+UnicodeString(oldLoc.getName()));
+ }
+ logln("Collator(getLocale) old:%s new:%s", l1.getName(), l2.getName());
+ delete c1;
+ delete c2;
+ }
+#endif
+}
+void LocaleAliasTest::TestULocale() {
+ for (int i=0; i<_LOCALE_NUMBER; i++) {
+ Locale oldLoc(_LOCALE_ALIAS[i][0]);
+ Locale newLoc(_LOCALE_ALIAS[i][1]);
+ if(!isLocaleAvailable(_LOCALE_ALIAS[i][1])){
+ logln(UnicodeString(newLoc.getName())+" is not available. Skipping!");
+ continue;
+ }
+ logln("\nold locale:%s new locale:%s",oldLoc.getName(),newLoc.getName());
+
+ UnicodeString name1, name2;
+ oldLoc.getDisplayName(name1);
+ newLoc.getDisplayName(name2);
+ if (name1!=name2) {
+ errln("DisplayNames are not equal. newLoc= "+UnicodeString(newLoc.getName()) +" oldLoc= "+UnicodeString(oldLoc.getName()));
+ }
+ log("ULocale(getDisplayName) old:");
+ log(name1);
+ log(" new:");
+ logln(name2);
+ }
+}
+LocaleAliasTest::LocaleAliasTest(){
+ UErrorCode status = U_ZERO_ERROR;
+ resIndex = ures_open(NULL,"res_index", &status);
+ if(U_FAILURE(status)){
+ errln("Could not open res_index.res. Exiting. Error: %s\n", u_errorName(status));
+ resIndex=NULL;
+ }
+ defLocale = Locale::getDefault();
+ Locale::setDefault(Locale::getUS(), status);
+}
+LocaleAliasTest::~LocaleAliasTest(){
+ /* reset the default locale */
+ UErrorCode status = U_ZERO_ERROR;
+ Locale::setDefault(defLocale, status);
+ ures_close(resIndex);
+ if(U_FAILURE(status)){
+ errln("Could not reset the default locale. Exiting. Error: %s\n", u_errorName(status));
+ }
+}
+UBool LocaleAliasTest::isLocaleAvailable(const char* loc){
+ if(resIndex==NULL){
+ return FALSE;
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len = 0;
+ ures_getStringByKey(resIndex, loc,&len, &status);
+ if(U_FAILURE(status)){
+ return FALSE;
+ }
+ return TRUE;
+}
+void LocaleAliasTest::TestDisplayName() {
+ int32_t availableNum =0;
+ const Locale* available = Locale::getAvailableLocales(availableNum);
+ for (int i=0; i<_LOCALE_NUMBER; i++) {
+ Locale oldLoc(_LOCALE_ALIAS[i][0]);
+ Locale newLoc(_LOCALE_ALIAS[i][1]);
+ if(!isLocaleAvailable(_LOCALE_ALIAS[i][1])){
+ logln(UnicodeString(newLoc.getName())+" is not available. Skipping!");
+ continue;
+ }
+ for(int j=0; j<availableNum; j++){
+ UnicodeString dipLocName = UnicodeString(available[j].getName());
+ const UnicodeString oldCountry = oldLoc.getDisplayCountry(dipLocName);
+ const UnicodeString newCountry = newLoc.getDisplayCountry(dipLocName);
+ const UnicodeString oldLang = oldLoc.getDisplayLanguage(dipLocName);
+ const UnicodeString newLang = newLoc.getDisplayLanguage(dipLocName);
+
+ // is there display name for the current country ID
+ if(newCountry != newLoc.getCountry()){
+ if(oldCountry!=newCountry){
+ errln("getCountry() failed for "+ UnicodeString(oldLoc.getName()) +" oldCountry= "+ prettify(oldCountry) +" newCountry = "+prettify(newCountry)+ " in display locale "+ UnicodeString(available[j].getName()));
+ }
+ }
+ //there is a display name for the current lang ID
+ if(newLang != newLoc.getLanguage()){
+ if(oldLang != newLang){
+ errln("getLanguage() failed for " + UnicodeString(oldLoc.getName()) + " oldLang = "+ prettify(oldLang) +" newLang = "+prettify(newLang)+ " in display locale "+UnicodeString(available[j].getName()));
+ }
+ }
+ }
+ }
+}
+void LocaleAliasTest::TestUResourceBundle() {
+
+ UErrorCode status = U_ZERO_ERROR;
+ for (int i=0; i<_LOCALE_NUMBER; i++) {
+ Locale oldLoc(_LOCALE_ALIAS[i][0]);
+ Locale newLoc(_LOCALE_ALIAS[i][1]);
+ if(!isLocaleAvailable(_LOCALE_ALIAS[i][1])){
+ logln(UnicodeString(newLoc.getName())+" is not available. Skipping!");
+ continue;
+ }
+ logln("\nold locale:%s new locale:%s",oldLoc.getName(),newLoc.getName());
+
+ ResourceBundle* rb1 = NULL;
+ ResourceBundle* rb2 = NULL;
+
+ const char* testdatapath=loadTestData(status);
+
+ UnicodeString us1("NULL");
+ UnicodeString us2("NULL");
+ rb1 = new ResourceBundle(testdatapath, oldLoc, status);
+ if (U_FAILURE(U_ZERO_ERROR)) {
+
+ } else {
+ us1 = rb1->getStringEx("locale", status);
+ }
+ rb2 = new ResourceBundle(testdatapath, newLoc, status);
+ if (U_FAILURE(U_ZERO_ERROR)){
+
+ } else {
+ us2 = rb2->getStringEx("locale", status);
+ }
+ UnicodeString uNewLoc(newLoc.getName());
+ if (us1.compare(uNewLoc)!=0 || us1.compare(us2)!=0 || status!=U_ZERO_ERROR) {
+
+ }
+ log("UResourceBundle(getStringEx) old:");
+ log(us1);
+ log(" new:");
+ logln(us2);
+
+ if (rb1!=NULL) {
+ delete rb1;
+ }
+ if (rb2!=NULL) {
+ delete rb2;
+ }
+ }
+
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/aliastst.h b/Build/source/libs/icu/icu-xetex/test/intltest/aliastst.h
new file mode 100644
index 00000000000..e9a0db4638d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/aliastst.h
@@ -0,0 +1,30 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2005-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+#ifndef _ALIASTST
+#define _ALIASTST
+
+#include "intltest.h"
+#include "unicode/locid.h"
+#include "unicode/ures.h"
+
+class LocaleAliasTest: public IntlTest {
+public:
+ void TestCalendar();
+ void TestDateFormat();
+ void TestCollation();
+ void TestULocale();
+ void TestUResourceBundle();
+ void TestDisplayName();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+ LocaleAliasTest();
+ virtual ~LocaleAliasTest();
+private:
+ UResourceBundle* resIndex;
+ UBool isLocaleAvailable(const char*);
+ Locale defLocale;
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/allcoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/allcoll.cpp
new file mode 100644
index 00000000000..f7518f03078
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/allcoll.cpp
@@ -0,0 +1,212 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2004, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/unistr.h"
+#include "unicode/sortkey.h"
+#include "allcoll.h"
+#include "sfwdchit.h"
+#include "../cintltst/calldata.h"
+
+
+CollationDummyTest::CollationDummyTest()
+: myCollation(0)
+{
+ /*UErrorCode status = U_ZERO_ERROR;
+ UnicodeString rules(TRUE, DEFAULTRULEARRAY, sizeof(DEFAULTRULEARRAY)/sizeof(DEFAULTRULEARRAY[0]));
+ UnicodeString newRules("& C < ch, cH, Ch, CH & Five, 5 & Four, 4 & one, 1 & Ampersand; '&' & Two, 2 ");
+ rules += newRules;
+ myCollation = new RuleBasedCollator(rules, status);
+ */
+
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString ruleset("& C < ch, cH, Ch, CH & Five, 5 & Four, 4 & one, 1 & Ampersand; '&' & Two, 2 ");
+ if (myCollation != NULL)
+ {
+ delete myCollation;
+ }
+ myCollation = new RuleBasedCollator(ruleset, status);
+ if(U_FAILURE(status)){
+ errln("ERROR: in creation of rule based collator from ruleset");
+ delete myCollation;
+ myCollation = 0;
+ }
+}
+
+CollationDummyTest::~CollationDummyTest()
+{
+ delete myCollation;
+}
+
+const Collator::EComparisonResult CollationDummyTest::results[] = {
+ Collator::LESS,
+ Collator::LESS, /*Collator::GREATER,*/
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::GREATER,
+ Collator::LESS, /* 10 */
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS,
+ /* test primary > 17 */
+ Collator::EQUAL,
+ Collator::EQUAL,
+ Collator::EQUAL, /* 20 */
+ Collator::LESS,
+ Collator::LESS,
+ Collator::EQUAL,
+ Collator::EQUAL,
+ Collator::EQUAL,
+ Collator::LESS,
+ /* test secondary > 26 */
+ Collator::EQUAL,
+ Collator::EQUAL,
+ Collator::EQUAL,
+ Collator::EQUAL,
+ Collator::EQUAL, /* 30 */
+ Collator::EQUAL,
+ Collator::LESS,
+ Collator::EQUAL, /* 34 */
+ Collator::EQUAL,
+ Collator::EQUAL,
+ Collator::LESS
+};
+
+
+void CollationDummyTest::TestTertiary(/* char* par */)
+{
+ int32_t i = 0;
+ myCollation->setStrength(Collator::TERTIARY);
+ for (i = 0; i < 17 ; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+void CollationDummyTest::TestPrimary(/* char* par */)
+{
+ /* problem in strcollinc for unfinshed contractions */
+ UErrorCode status = U_ZERO_ERROR;
+
+ myCollation->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ myCollation->setStrength(Collator::PRIMARY);
+
+ if (U_FAILURE(status))
+ {
+ errln("Failure in setting attribute for normalization mode\n");
+ }
+
+ for (int i = 17; i < 26 ; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+
+void CollationDummyTest::TestSecondary(/* char* par */)
+{
+ int32_t i;
+ myCollation->setStrength(Collator::SECONDARY);
+ for (i = 26; i < 34; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+
+void CollationDummyTest::TestExtra(/* char* par */)
+{
+ int32_t i, j;
+ myCollation->setStrength(Collator::TERTIARY);
+ for (i = 0; i < COUNT_TEST_CASES-1; i++)
+ {
+ for (j = i + 1; j < COUNT_TEST_CASES; j += 1)
+ {
+ doTest(myCollation, testCases[i], testCases[j], Collator::LESS);
+ }
+ }
+}
+
+void CollationDummyTest::TestIdentical()
+{
+ int32_t i;
+ myCollation->setStrength(Collator::IDENTICAL);
+ for (i= 34; i<37; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+
+void CollationDummyTest::TestJB581(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ UnicodeString source("THISISATEST.");
+ UnicodeString target("Thisisatest.");
+
+ Collator *coll = Collator::createInstance("en_US", status);
+ if (U_FAILURE(status)){
+ errln("ERROR: Failed to create the collator for : en_US\n");
+ return;
+ }
+
+ Collator::EComparisonResult result = coll->compare(source, target);
+ /* result is 1, secondary differences only for ignorable space characters*/
+ if (result != 1)
+ {
+ errln("Comparing two strings with only secondary differences in C failed.\n");
+ }
+ /* To compare them with just primary differences */
+ coll->setStrength(Collator::PRIMARY);
+ result = coll->compare(source, target);
+ /* result is 0 */
+ if (result != 0)
+ {
+ errln("Comparing two strings with no differences in C failed.\n");
+ }
+ /* Now, do the same comparison with keys */
+ CollationKey sourceKeyOut,
+ targetKeyOut;
+ coll->getCollationKey(source, sourceKeyOut, status);
+ coll->getCollationKey(target, targetKeyOut, status);
+ result = sourceKeyOut.compareTo(targetKeyOut);
+ if (result != 0)
+ {
+ errln("Comparing two strings with sort keys in C failed.\n");
+ }
+ delete coll;
+}
+
+void CollationDummyTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CollationDummyTest: ");
+ if(myCollation) {
+ switch (index) {
+ case 0: name = "TestPrimary"; if (exec) TestPrimary(/* par */); break;
+ case 1: name = "TestSecondary"; if (exec) TestSecondary(/* par */); break;
+ case 2: name = "TestTertiary"; if (exec) TestTertiary(/* par */); break;
+ case 3: name = "TestExtra"; if (exec) TestExtra(/* par */); break;
+ case 4: name = "TestIdentical"; if (exec) TestIdentical(/* par */); break;
+ case 5: name = "TestJB581"; if (exec) TestJB581(/* par */); break;
+ default: name = ""; break;
+ }
+ } else {
+ errln("Collator couldn't be instantiated!");
+ name = "";
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/allcoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/allcoll.h
new file mode 100644
index 00000000000..040a7501f56
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/allcoll.h
@@ -0,0 +1,57 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2004, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+/**
+ * CollationDummyTest is a third level test class. This tests creation of
+ * a customized collator object. For example, number 1 to be sorted
+ * equlivalent to word 'one'.
+ */
+
+#ifndef _ALLCOLL
+#define _ALLCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/tblcoll.h"
+#include "tscoll.h"
+
+class CollationDummyTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationDummyTest();
+ virtual ~CollationDummyTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par = NULL */);
+
+ // perform test with strength PRIMARY
+ void TestPrimary(/* char* par */);
+
+ // perform test with strength SECONDARY
+ void TestSecondary(/* char* par */);
+
+ // perform test with strength tertiary
+ void TestTertiary(/* char* par */);
+
+ // perform extra tests
+ void TestExtra(/* char* par */);
+
+ void TestIdentical();
+
+ void TestJB581();
+
+private:
+ static const Collator::EComparisonResult results[];
+
+ RuleBasedCollator *myCollation;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/apicoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/apicoll.cpp
new file mode 100644
index 00000000000..0150f1a9198
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/apicoll.cpp
@@ -0,0 +1,2325 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+//===============================================================================
+//
+// File apitest.cpp
+//
+//
+//
+// Created by: Helena Shih
+//
+// Modification History:
+//
+// Date Name Description
+// 2/5/97 aliu Added streamIn and streamOut methods. Added
+// constructor which reads RuleBasedCollator object from
+// a binary file. Added writeToFile method which streams
+// RuleBasedCollator out to a binary file. The streamIn
+// and streamOut methods use istream and ostream objects
+// in binary mode.
+// 6/30/97 helena Added tests for CollationElementIterator::setText, getOffset
+// setOffset and DecompositionIterator::getOffset, setOffset.
+// DecompositionIterator is made public so add class scope
+// testing.
+// 02/10/98 damiba Added test for compare(UnicodeString&, UnicodeString&, int32_t)
+//===============================================================================
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "unicode/sortkey.h"
+#include "apicoll.h"
+#include "unicode/chariter.h"
+#include "unicode/schriter.h"
+#include "unicode/ustring.h"
+#include "unicode/ucol.h"
+
+#include "sfwdchit.h"
+#include "cmemory.h"
+#include <stdlib.h>
+
+void
+CollationAPITest::doAssert(UBool condition, const char *message)
+{
+ if (!condition) {
+ errln(UnicodeString("ERROR : ") + message);
+ }
+}
+
+#ifdef U_USE_COLLATION_OBSOLETE_2_6
+/*
+ * Test Collator::createInstance(... version...) for some locale. Called by TestProperty().
+ */
+static void
+TestOpenVersion(IntlTest &test, const Locale &locale) {
+ UVersionInfo version1, version2;
+ Collator *collator1, *collator2;
+ UErrorCode errorCode;
+
+ errorCode=U_ZERO_ERROR;
+ collator1=Collator::createInstance(locale, errorCode);
+ if(U_SUCCESS(errorCode)) {
+ /* get the current version */
+ collator1->getVersion(version1);
+ delete collator1;
+
+ /* try to get that same version again */
+ collator2=Collator::createInstance(locale, version1, errorCode);
+ if(U_SUCCESS(errorCode)) {
+ collator2->getVersion(version2);
+ if(0!=uprv_memcmp(version1, version2, sizeof(UVersionInfo))) {
+ test.errln("error: Collator::createInstance(\"%s\", (%s collator)->getVersion()) returns a different collator\n", locale.getName(), locale.getName());
+ }
+ delete collator2;
+ } else {
+ test.errln("error: Collator::createInstance(\"%s\", (%s collator)->getVersion()) fails: %s\n", locale.getName(), locale.getName(), u_errorName(errorCode));
+ }
+ }
+}
+#endif
+
+// Collator Class Properties
+// ctor, dtor, createInstance, compare, getStrength/setStrength
+// getDecomposition/setDecomposition, getDisplayName
+void
+CollationAPITest::TestProperty(/* char* par */)
+{
+ UErrorCode success = U_ZERO_ERROR;
+ Collator *col = 0;
+ /*
+ All the collations have the same version in an ICU
+ version.
+ ICU 2.0 currVersionArray = {0x18, 0xC0, 0x02, 0x02};
+ ICU 2.1 currVersionArray = {0x19, 0x00, 0x03, 0x03};
+ ICU 2.2 currVersionArray = {0x21, 0x40, 0x04, 0x04};
+ ICU 2.4 currVersionArray = {0x21, 0x40, 0x04, 0x04};
+ ICU 2.6 currVersionArray = {0x21, 0x40, 0x03, 0x03};
+ ICU 2.8 currVersionArray = {0x29, 0x80, 0x00, 0x04};
+ ICU 3.4 currVersionArray = {0x31, 0xC0, 0x00, 0x04};
+ */
+ UVersionInfo currVersionArray = {0x31, 0xC0, 0x00, 0x05};
+ UVersionInfo versionArray;
+ int i = 0;
+
+ logln("The property tests begin : ");
+ logln("Test ctors : ");
+ col = Collator::createInstance(Locale::getEnglish(), success);
+
+ if (U_FAILURE(success))
+ {
+ errln("Default Collator creation failed.");
+ return;
+ }
+
+ col->getVersion(versionArray);
+ for (i=0; i<4; ++i) {
+ if (versionArray[i] != currVersionArray[i]) {
+ errln("Testing ucol_getVersion() - unexpected result: %d.%d.%d.%d",
+ versionArray[0], versionArray[1], versionArray[2], versionArray[3]);
+ break;
+ }
+ }
+
+ doAssert((col->compare("ab", "abc") == Collator::LESS), "ab < abc comparison failed");
+ doAssert((col->compare("ab", "AB") == Collator::LESS), "ab < AB comparison failed");
+ doAssert((col->compare("blackbird", "black-bird") == Collator::GREATER), "black-bird > blackbird comparison failed");
+ doAssert((col->compare("black bird", "black-bird") == Collator::LESS), "black bird > black-bird comparison failed");
+ doAssert((col->compare("Hello", "hello") == Collator::GREATER), "Hello > hello comparison failed");
+
+
+ /*start of update [Bertrand A. D. 02/10/98]*/
+ doAssert((col->compare("ab", "abc", 2) == Collator::EQUAL), "ab = abc with length 2 comparison failed");
+ doAssert((col->compare("ab", "AB", 2) == Collator::LESS), "ab < AB with length 2 comparison failed");
+ doAssert((col->compare("ab", "Aa", 1) == Collator::LESS), "ab < Aa with length 1 comparison failed");
+ doAssert((col->compare("ab", "Aa", 2) == Collator::GREATER), "ab > Aa with length 2 comparison failed");
+ doAssert((col->compare("black-bird", "blackbird", 5) == Collator::EQUAL), "black-bird = blackbird with length of 5 comparison failed");
+ doAssert((col->compare("black bird", "black-bird", 10) == Collator::LESS), "black bird < black-bird with length 10 comparison failed");
+ doAssert((col->compare("Hello", "hello", 5) == Collator::GREATER), "Hello > hello with length 5 comparison failed");
+ /*end of update [Bertrand A. D. 02/10/98]*/
+
+
+ logln("Test ctors ends.");
+ logln("testing Collator::getStrength() method ...");
+ doAssert((col->getStrength() == Collator::TERTIARY), "collation object has the wrong strength");
+ doAssert((col->getStrength() != Collator::PRIMARY), "collation object's strength is primary difference");
+
+
+ logln("testing Collator::setStrength() method ...");
+ col->setStrength(Collator::SECONDARY);
+ doAssert((col->getStrength() != Collator::TERTIARY), "collation object's strength is secondary difference");
+ doAssert((col->getStrength() != Collator::PRIMARY), "collation object's strength is primary difference");
+ doAssert((col->getStrength() == Collator::SECONDARY), "collation object has the wrong strength");
+
+ UnicodeString name;
+
+ logln("Get display name for the US English collation in German : ");
+ logln(Collator::getDisplayName(Locale::getUS(), Locale::getGerman(), name));
+ doAssert((name == UnicodeString("Englisch (Vereinigte Staaten)")), "getDisplayName failed");
+
+ logln("Get display name for the US English collation in English : ");
+ logln(Collator::getDisplayName(Locale::getUS(), Locale::getEnglish(), name));
+ doAssert((name == UnicodeString("English (United States)")), "getDisplayName failed");
+#if 0
+ // weiv : this test is bogus if we're running on any machine that has different default locale than English.
+ // Therefore, it is banned!
+ logln("Get display name for the US English in default locale language : ");
+ logln(Collator::getDisplayName(Locale::US, name));
+ doAssert((name == UnicodeString("English (United States)")), "getDisplayName failed if this is an English machine");
+#endif
+ delete col; col = 0;
+ RuleBasedCollator *rcol = (RuleBasedCollator *)Collator::createInstance("da_DK",
+ success);
+ doAssert(rcol->getRules().length() != 0, "da_DK rules does not have length 0");
+ delete rcol;
+
+ col = Collator::createInstance(Locale::getFrench(), success);
+ if (U_FAILURE(success))
+ {
+ errln("Creating French collation failed.");
+ return;
+ }
+
+ col->setStrength(Collator::PRIMARY);
+ logln("testing Collator::getStrength() method again ...");
+ doAssert((col->getStrength() != Collator::TERTIARY), "collation object has the wrong strength");
+ doAssert((col->getStrength() == Collator::PRIMARY), "collation object's strength is not primary difference");
+
+ logln("testing French Collator::setStrength() method ...");
+ col->setStrength(Collator::TERTIARY);
+ doAssert((col->getStrength() == Collator::TERTIARY), "collation object's strength is not tertiary difference");
+ doAssert((col->getStrength() != Collator::PRIMARY), "collation object's strength is primary difference");
+ doAssert((col->getStrength() != Collator::SECONDARY), "collation object's strength is secondary difference");
+
+ logln("Create junk collation: ");
+ Locale abcd("ab", "CD", "");
+ success = U_ZERO_ERROR;
+ Collator *junk = 0;
+ junk = Collator::createInstance(abcd, success);
+
+ if (U_FAILURE(success))
+ {
+ errln("Junk collation creation failed, should at least return default.");
+ delete col;
+ return;
+ }
+
+ delete col;
+ col = Collator::createInstance(success);
+ if (U_FAILURE(success))
+ {
+ errln("Creating default collator failed.");
+ delete junk;
+ return;
+ }
+
+ doAssert(((RuleBasedCollator *)col)->getRules() == ((RuleBasedCollator *)junk)->getRules(),
+ "The default collation should be returned.");
+ Collator *frCol = Collator::createInstance(Locale::getFrance(), success);
+ if (U_FAILURE(success))
+ {
+ errln("Creating French collator failed.");
+ delete col;
+ delete junk;
+ return;
+ }
+
+ // If the default locale isn't French, the French and non-French collators
+ // should be different
+ if (frCol->getLocale(ULOC_ACTUAL_LOCALE, success) != Locale::getFrench()) {
+ doAssert((*frCol != *junk), "The junk is the same as the French collator.");
+ }
+ Collator *aFrCol = frCol->clone();
+ doAssert((*frCol == *aFrCol), "The cloning of a French collator failed.");
+ logln("Collator property test ended.");
+
+ delete col;
+ delete frCol;
+ delete aFrCol;
+ delete junk;
+
+#ifdef U_USE_COLLATION_OBSOLETE_2_6
+ /* test Collator::createInstance(...version...) */
+ TestOpenVersion(*this, "");
+ TestOpenVersion(*this, "da");
+ TestOpenVersion(*this, "fr");
+ TestOpenVersion(*this, "ja");
+
+ /* try some bogus version */
+ versionArray[0]=0;
+ versionArray[1]=0x99;
+ versionArray[2]=0xc7;
+ versionArray[3]=0xfe;
+ col=Collator::createInstance(Locale(), versionArray, success);
+ if(U_SUCCESS(success)) {
+ errln("error: ucol_openVersion(bogus version) succeeded");
+ delete col;
+ }
+#endif
+}
+
+void
+CollationAPITest::TestRuleBasedColl()
+{
+ RuleBasedCollator *col1, *col2, *col3, *col4;
+ UErrorCode status = U_ZERO_ERROR;
+
+ UnicodeString ruleset1("&9 < a, A < b, B < c, C; ch, cH, Ch, CH < d, D, e, E");
+ UnicodeString ruleset2("&9 < a, A < b, B < c, C < d, D, e, E");
+
+ col1 = new RuleBasedCollator(ruleset1, status);
+ if (U_FAILURE(status)) {
+ errln("RuleBased Collator creation failed.\n");
+ return;
+ }
+ else {
+ logln("PASS: RuleBased Collator creation passed\n");
+ }
+
+ status = U_ZERO_ERROR;
+ col2 = new RuleBasedCollator(ruleset2, status);
+ if (U_FAILURE(status)) {
+ errln("RuleBased Collator creation failed.\n");
+ return;
+ }
+ else {
+ logln("PASS: RuleBased Collator creation passed\n");
+ }
+
+ status = U_ZERO_ERROR;
+ Locale locale("aa", "AA");
+ col3 = (RuleBasedCollator *)Collator::createInstance(locale, status);
+ if (U_FAILURE(status)) {
+ errln("Fallback Collator creation failed.: %s\n");
+ return;
+ }
+ else {
+ logln("PASS: Fallback Collator creation passed\n");
+ }
+ delete col3;
+
+ status = U_ZERO_ERROR;
+ col3 = (RuleBasedCollator *)Collator::createInstance(status);
+ if (U_FAILURE(status)) {
+ errln("Default Collator creation failed.: %s\n");
+ return;
+ }
+ else {
+ logln("PASS: Default Collator creation passed\n");
+ }
+
+ UnicodeString rule1 = col1->getRules();
+ UnicodeString rule2 = col2->getRules();
+ UnicodeString rule3 = col3->getRules();
+
+ doAssert(rule1 != rule2, "Default collator getRules failed");
+ doAssert(rule2 != rule3, "Default collator getRules failed");
+ doAssert(rule1 != rule3, "Default collator getRules failed");
+
+ col4 = new RuleBasedCollator(rule2, status);
+ if (U_FAILURE(status)) {
+ errln("RuleBased Collator creation failed.\n");
+ return;
+ }
+
+ UnicodeString rule4 = col4->getRules();
+ doAssert(rule2 == rule4, "Default collator getRules failed");
+ int32_t length4 = 0;
+ uint8_t *clonedrule4 = col4->cloneRuleData(length4, status);
+ if (U_FAILURE(status)) {
+ errln("Cloned rule data failed.\n");
+ return;
+ }
+
+ // free(clonedrule4); BAD API!!!!
+ uprv_free(clonedrule4);
+
+
+ delete col1;
+ delete col2;
+ delete col3;
+ delete col4;
+}
+
+void
+CollationAPITest::TestRules()
+{
+ RuleBasedCollator *coll;
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString rules;
+
+ coll = (RuleBasedCollator *)Collator::createInstance(Locale::getEnglish(), status);
+ if (U_FAILURE(status)) {
+ errln("English Collator creation failed.\n");
+ return;
+ }
+ else {
+ logln("PASS: RuleBased Collator creation passed\n");
+ }
+
+ coll->getRules(UCOL_TAILORING_ONLY, rules);
+ if (rules.length() != 0x0a) {
+ errln("English tailored rules failed - length is 0x%x expected 0x%x", rules.length(), 0x0e);
+ }
+
+ coll->getRules(UCOL_FULL_RULES, rules);
+ if (rules.length() < 0) {
+ errln("English full rules failed");
+ }
+ delete coll;
+}
+
+void
+CollationAPITest::TestDecomposition() {
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *en_US = Collator::createInstance("en_US", status),
+ *el_GR = Collator::createInstance("el_GR", status),
+ *vi_VN = Collator::createInstance("vi_VN", status);
+
+ if (U_FAILURE(status)) {
+ errln("ERROR: collation creation failed.\n");
+ return;
+ }
+
+ /* there is no reason to have canonical decomposition in en_US OR default locale */
+ if (vi_VN->getAttribute(UCOL_NORMALIZATION_MODE, status) != UCOL_ON)
+ {
+ errln("ERROR: vi_VN collation did not have canonical decomposition for normalization!\n");
+ }
+
+ if (el_GR->getAttribute(UCOL_NORMALIZATION_MODE, status) != UCOL_ON)
+ {
+ errln("ERROR: el_GR collation did not have canonical decomposition for normalization!\n");
+ }
+
+ if (en_US->getAttribute(UCOL_NORMALIZATION_MODE, status) != UCOL_OFF)
+ {
+ errln("ERROR: en_US collation had canonical decomposition for normalization!\n");
+ }
+
+ delete en_US;
+ delete el_GR;
+ delete vi_VN;
+}
+
+void
+CollationAPITest::TestSafeClone() {
+ static const int CLONETEST_COLLATOR_COUNT = 3;
+ Collator *someCollators [CLONETEST_COLLATOR_COUNT];
+ Collator *col;
+ UErrorCode err = U_ZERO_ERROR;
+ int index;
+
+ UnicodeString test1("abCda");
+ UnicodeString test2("abcda");
+
+ /* one default collator & two complex ones */
+ someCollators[0] = Collator::createInstance("en_US", err);
+ someCollators[1] = Collator::createInstance("ko", err);
+ someCollators[2] = Collator::createInstance("ja_JP", err);
+ if(U_FAILURE(err)) {
+ errln("Couldn't instantiate collators. Error: %s", u_errorName(err));
+ delete someCollators[0];
+ delete someCollators[1];
+ delete someCollators[2];
+ return;
+ }
+
+ /* change orig & clone & make sure they are independent */
+
+ for (index = 0; index < CLONETEST_COLLATOR_COUNT; index++)
+ {
+ col = someCollators[index]->safeClone();
+ if (col == 0) {
+ errln("SafeClone of collator should not return null\n");
+ break;
+ }
+ col->setStrength(Collator::TERTIARY);
+ someCollators[index]->setStrength(Collator::PRIMARY);
+ col->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, err);
+ someCollators[index]->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, err);
+
+ doAssert(col->greater(test1, test2), "Result should be \"abCda\" >>> \"abcda\" ");
+ doAssert(someCollators[index]->equals(test1, test2), "Result should be \"abcda\" == \"abCda\"");
+ delete col;
+ delete someCollators[index];
+ }
+}
+
+void
+CollationAPITest::TestHashCode(/* char* par */)
+{
+ logln("hashCode tests begin.");
+ UErrorCode success = U_ZERO_ERROR;
+ Collator *col1 = 0;
+ col1 = Collator::createInstance(Locale::getEnglish(), success);
+ if (U_FAILURE(success))
+ {
+ errln("Default collation creation failed.");
+ return;
+ }
+
+ Collator *col2 = 0;
+ Locale dk("da", "DK", "");
+ col2 = Collator::createInstance(dk, success);
+ if (U_FAILURE(success))
+ {
+ errln("Danish collation creation failed.");
+ return;
+ }
+
+ Collator *col3 = 0;
+ col3 = Collator::createInstance(Locale::getEnglish(), success);
+ if (U_FAILURE(success))
+ {
+ errln("2nd default collation creation failed.");
+ return;
+ }
+
+ logln("Collator::hashCode() testing ...");
+
+ doAssert(col1->hashCode() != col2->hashCode(), "Hash test1 result incorrect" );
+ doAssert(!(col1->hashCode() == col2->hashCode()), "Hash test2 result incorrect" );
+ doAssert(col1->hashCode() == col3->hashCode(), "Hash result not equal" );
+
+ logln("hashCode tests end.");
+ delete col1;
+ delete col2;
+
+ UnicodeString test1("Abcda");
+ UnicodeString test2("abcda");
+
+ CollationKey sortk1, sortk2, sortk3;
+ UErrorCode status = U_ZERO_ERROR;
+
+ col3->getCollationKey(test1, sortk1, status);
+ col3->getCollationKey(test2, sortk2, status);
+ col3->getCollationKey(test2, sortk3, status);
+
+ doAssert(sortk1.hashCode() != sortk2.hashCode(), "Hash test1 result incorrect");
+ doAssert(sortk2.hashCode() == sortk3.hashCode(), "Hash result not equal" );
+
+ delete col3;
+}
+
+//----------------------------------------------------------------------------
+// CollationKey -- Tests the CollationKey methods
+//
+void
+CollationAPITest::TestCollationKey(/* char* par */)
+{
+ logln("testing CollationKey begins...");
+ Collator *col = 0;
+ UErrorCode success=U_ZERO_ERROR;
+ col = Collator::createInstance(Locale::getEnglish(), success);
+ if (U_FAILURE(success))
+ {
+ errln("Default collation creation failed.");
+ return;
+ }
+ col->setStrength(Collator::TERTIARY);
+
+ CollationKey sortk1, sortk2;
+ UnicodeString test1("Abcda"), test2("abcda");
+ UErrorCode key1Status = U_ZERO_ERROR, key2Status = U_ZERO_ERROR;
+
+ logln("Testing weird arguments");
+ col->getCollationKey(NULL, 0, sortk1, key1Status);
+ // key gets reset here
+ int32_t length;
+ sortk1.getByteArray(length);
+ doAssert(sortk1.isBogus() == FALSE && length == 0,
+ "Empty string should return an empty collation key");
+ // bogus key returned here
+ key1Status = U_ILLEGAL_ARGUMENT_ERROR;
+ col->getCollationKey(NULL, 0, sortk1, key1Status);
+ doAssert(sortk1.getByteArray(length) == NULL && length == 0,
+ "Error code should return bogus collation key");
+
+ key1Status = U_ZERO_ERROR;
+ logln("Use tertiary comparison level testing ....");
+
+ col->getCollationKey(test1, sortk1, key1Status);
+ doAssert((sortk1.compareTo(col->getCollationKey(test2, sortk2, key2Status)))
+ == Collator::GREATER,
+ "Result should be \"Abcda\" >>> \"abcda\"");
+
+ CollationKey sortk3(sortk2), sortkNew, sortkEmpty;
+
+
+ sortkNew = sortk1;
+ doAssert((sortk1 != sortk2), "The sort keys should be different");
+ doAssert((sortk1.hashCode() != sortk2.hashCode()), "sort key hashCode() failed");
+ doAssert((sortk2 == sortk3), "The sort keys should be the same");
+ doAssert((sortk1 == sortkNew), "The sort keys assignment failed");
+ doAssert((sortk1.hashCode() == sortkNew.hashCode()), "sort key hashCode() failed");
+ doAssert((sortkNew != sortk3), "The sort keys should be different");
+ doAssert(sortk1.compareTo(sortk3) == Collator::GREATER, "Result should be \"Abcda\" >>> \"abcda\"");
+ doAssert(sortk2.compareTo(sortk3) == Collator::EQUAL, "Result should be \"abcda\" == \"abcda\"");
+ doAssert(sortkEmpty.compareTo(sortk1) == Collator::LESS, "Result should be (empty key) <<< \"Abcda\"");
+ doAssert(sortk1.compareTo(sortkEmpty) == Collator::GREATER, "Result should be \"Abcda\" >>> (empty key)");
+ doAssert(sortkEmpty.compareTo(sortkEmpty) == Collator::EQUAL, "Result should be (empty key) == (empty key)");
+ doAssert(sortk1.compareTo(sortk3, success) == UCOL_GREATER, "Result should be \"Abcda\" >>> \"abcda\"");
+ doAssert(sortk2.compareTo(sortk3, success) == UCOL_EQUAL, "Result should be \"abcda\" == \"abcda\"");
+ doAssert(sortkEmpty.compareTo(sortk1, success) == UCOL_LESS, "Result should be (empty key) <<< \"Abcda\"");
+ doAssert(sortk1.compareTo(sortkEmpty, success) == UCOL_GREATER, "Result should be \"Abcda\" >>> (empty key)");
+ doAssert(sortkEmpty.compareTo(sortkEmpty, success) == UCOL_EQUAL, "Result should be (empty key) == (empty key)");
+
+ int32_t cnt1, cnt2, cnt3, cnt4;
+
+ const uint8_t* byteArray1 = sortk1.getByteArray(cnt1);
+ const uint8_t* byteArray2 = sortk2.getByteArray(cnt2);
+
+ /*
+ this is a bad test since it is dependent on the version of uca data,
+ which changes
+ will remove it.
+ const char sortk2_compat[] = {
+ // this is a 1.8 sortkey
+ 0x17, 0x19, 0x1B, 0x1D, 0x17, 0x01, 0x08, 0x01, 0x08, 0x00
+ };
+ */
+
+ const uint8_t* byteArray3 = 0;
+ byteArray3 = sortk1.getByteArray(cnt3);
+
+ const uint8_t* byteArray4 = 0;
+ byteArray4 = sortk2.getByteArray(cnt4);
+
+ CollationKey sortk4(byteArray1, cnt1), sortk5(byteArray2, cnt2);
+ CollationKey sortk6(byteArray3, cnt3), sortk7(byteArray4, cnt4);
+
+ /*
+ doAssert(memcmp(byteArray2, sortk2_compat, strlen(sortk2_compat)) == 0,
+ "Binary format for 'abcda' sortkey different!");
+ */
+ doAssert(sortk1.compareTo(sortk4) == Collator::EQUAL, "CollationKey::toByteArray(sortk1) Failed.");
+ doAssert(sortk2.compareTo(sortk5) == Collator::EQUAL, "CollationKey::toByteArray(sortk2) Failed.");
+ doAssert(sortk4.compareTo(sortk5) == Collator::GREATER, "sortk4 >>> sortk5 Failed");
+ doAssert(sortk1.compareTo(sortk6) == Collator::EQUAL, "CollationKey::getByteArray(sortk1) Failed.");
+ doAssert(sortk2.compareTo(sortk7) == Collator::EQUAL, "CollationKey::getByteArray(sortk2) Failed.");
+ doAssert(sortk6.compareTo(sortk7) == Collator::GREATER, "sortk6 >>> sortk7 Failed");
+
+ logln("Equality tests : ");
+ doAssert(sortk1 == sortk4, "sortk1 == sortk4 Failed.");
+ doAssert(sortk2 == sortk5, "sortk2 == sortk5 Failed.");
+ doAssert(sortk1 != sortk5, "sortk1 != sortk5 Failed.");
+ doAssert(sortk1 == sortk6, "sortk1 == sortk6 Failed.");
+ doAssert(sortk2 == sortk7, "sortk2 == sortk7 Failed.");
+ doAssert(sortk1 != sortk7, "sortk1 != sortk7 Failed.");
+
+ byteArray1 = 0;
+ byteArray2 = 0;
+
+ sortk3 = sortk1;
+ doAssert(sortk1 == sortk3, "sortk1 = sortk3 assignment Failed.");
+ doAssert(sortk2 != sortk3, "sortk2 != sortk3 Failed.");
+ logln("testing sortkey ends...");
+
+ col->setStrength(Collator::SECONDARY);
+ doAssert(col->getCollationKey(test1, sortk1, key1Status).compareTo(
+ col->getCollationKey(test2, sortk2, key2Status))
+ == Collator::EQUAL,
+ "Result should be \"Abcda\" == \"abcda\"");
+ delete col;
+}
+
+//----------------------------------------------------------------------------
+// Tests the CollatorElementIterator class.
+// ctor, RuleBasedCollator::createCollationElementIterator(), operator==, operator!=
+//
+void
+CollationAPITest::TestElemIter(/* char* par */)
+{
+ logln("testing sortkey begins...");
+ Collator *col = 0;
+ UErrorCode success = U_ZERO_ERROR;
+ col = Collator::createInstance(Locale::getEnglish(), success);
+ if (U_FAILURE(success))
+ {
+ errln("Default collation creation failed.");
+ return;
+ }
+
+ UnicodeString testString1("XFILE What subset of all possible test cases has the highest probability of detecting the most errors?");
+ UnicodeString testString2("Xf_ile What subset of all possible test cases has the lowest probability of detecting the least errors?");
+ logln("Constructors and comparison testing....");
+ CollationElementIterator *iterator1 = ((RuleBasedCollator*)col)->createCollationElementIterator(testString1);
+
+ CharacterIterator *chariter=new StringCharacterIterator(testString1);
+ CollationElementIterator *coliter=((RuleBasedCollator*)col)->createCollationElementIterator(*chariter);
+
+ // copy ctor
+ CollationElementIterator *iterator2 = ((RuleBasedCollator*)col)->createCollationElementIterator(testString1);
+ CollationElementIterator *iterator3 = ((RuleBasedCollator*)col)->createCollationElementIterator(testString2);
+
+ int32_t offset = iterator1->getOffset();
+ if (offset != 0) {
+ errln("Error in getOffset for collation element iterator\n");
+ return;
+ }
+ iterator1->setOffset(6, success);
+ if (U_FAILURE(success)) {
+ errln("Error in setOffset for collation element iterator\n");
+ return;
+ }
+ iterator1->setOffset(0, success);
+ int32_t order1, order2, order3;
+ doAssert((*iterator1 == *iterator2), "The two iterators should be the same");
+ doAssert((*iterator1 != *iterator3), "The two iterators should be different");
+
+ doAssert((*coliter == *iterator1), "The two iterators should be the same");
+ doAssert((*coliter == *iterator2), "The two iterators should be the same");
+ doAssert((*coliter != *iterator3), "The two iterators should be different");
+
+ order1 = iterator1->next(success);
+ if (U_FAILURE(success))
+ {
+ errln("Somehow ran out of memory stepping through the iterator.");
+ return;
+ }
+
+ doAssert((*iterator1 != *iterator2), "The first iterator advance failed");
+ order2 = iterator2->getOffset();
+ doAssert((order1 != order2), "The order result should not be the same");
+ order2 = iterator2->next(success);
+ if (U_FAILURE(success))
+ {
+ errln("Somehow ran out of memory stepping through the iterator.");
+ return;
+ }
+
+ doAssert((*iterator1 == *iterator2), "The second iterator advance failed");
+ doAssert((order1 == order2), "The order result should be the same");
+ order3 = iterator3->next(success);
+ if (U_FAILURE(success))
+ {
+ errln("Somehow ran out of memory stepping through the iterator.");
+ return;
+ }
+
+ doAssert((CollationElementIterator::primaryOrder(order1) ==
+ CollationElementIterator::primaryOrder(order3)), "The primary orders should be the same");
+ doAssert((CollationElementIterator::secondaryOrder(order1) ==
+ CollationElementIterator::secondaryOrder(order3)), "The secondary orders should be the same");
+ doAssert((CollationElementIterator::tertiaryOrder(order1) ==
+ CollationElementIterator::tertiaryOrder(order3)), "The tertiary orders should be the same");
+
+ order1 = iterator1->next(success); order3 = iterator3->next(success);
+ if (U_FAILURE(success))
+ {
+ errln("Somehow ran out of memory stepping through the iterator.");
+ return;
+ }
+
+ doAssert((CollationElementIterator::primaryOrder(order1) ==
+ CollationElementIterator::primaryOrder(order3)), "The primary orders should be identical");
+ doAssert((CollationElementIterator::tertiaryOrder(order1) !=
+ CollationElementIterator::tertiaryOrder(order3)), "The tertiary orders should be different");
+
+ order1 = iterator1->next(success);
+ order3 = iterator3->next(success);
+ /* NO! Secondary orders of two CEs are not related, especially in the case of '_' vs 'I' */
+ /*
+ doAssert((CollationElementIterator::secondaryOrder(order1) !=
+ CollationElementIterator::secondaryOrder(order3)), "The secondary orders should not be the same");
+ */
+ doAssert((order1 != CollationElementIterator::NULLORDER), "Unexpected end of iterator reached");
+
+ iterator1->reset(); iterator2->reset(); iterator3->reset();
+ order1 = iterator1->next(success);
+ if (U_FAILURE(success))
+ {
+ errln("Somehow ran out of memory stepping through the iterator.");
+ return;
+ }
+
+ doAssert((*iterator1 != *iterator2), "The first iterator advance failed");
+
+ order2 = iterator2->next(success);
+ if (U_FAILURE(success))
+ {
+ errln("Somehow ran out of memory stepping through the iterator.");
+ return;
+ }
+
+ doAssert((*iterator1 == *iterator2), "The second iterator advance failed");
+ doAssert((order1 == order2), "The order result should be the same");
+
+ order3 = iterator3->next(success);
+ if (U_FAILURE(success))
+ {
+ errln("Somehow ran out of memory stepping through the iterator.");
+ return;
+ }
+
+ doAssert((CollationElementIterator::primaryOrder(order1) ==
+ CollationElementIterator::primaryOrder(order3)), "The primary orders should be the same");
+ doAssert((CollationElementIterator::secondaryOrder(order1) ==
+ CollationElementIterator::secondaryOrder(order3)), "The secondary orders should be the same");
+ doAssert((CollationElementIterator::tertiaryOrder(order1) ==
+ CollationElementIterator::tertiaryOrder(order3)), "The tertiary orders should be the same");
+
+ order1 = iterator1->next(success); order2 = iterator2->next(success); order3 = iterator3->next(success);
+ if (U_FAILURE(success))
+ {
+ errln("Somehow ran out of memory stepping through the iterator.");
+ return;
+ }
+
+ doAssert((CollationElementIterator::primaryOrder(order1) ==
+ CollationElementIterator::primaryOrder(order3)), "The primary orders should be identical");
+ doAssert((CollationElementIterator::tertiaryOrder(order1) !=
+ CollationElementIterator::tertiaryOrder(order3)), "The tertiary orders should be different");
+
+ order1 = iterator1->next(success); order3 = iterator3->next(success);
+ if (U_FAILURE(success))
+ {
+ errln("Somehow ran out of memory stepping through the iterator.");
+ return;
+ }
+
+ /* NO! Secondary orders of two CEs are not related, especially in the case of '_' vs 'I' */
+ /*
+ doAssert((CollationElementIterator::secondaryOrder(order1) !=
+ CollationElementIterator::secondaryOrder(order3)), "The secondary orders should not be the same");
+ */
+ doAssert((order1 != CollationElementIterator::NULLORDER), "Unexpected end of iterator reached");
+ doAssert((*iterator2 != *iterator3), "The iterators should be different");
+
+
+ //test error values
+ success=U_UNSUPPORTED_ERROR;
+ Collator *colerror=NULL;
+ colerror=Collator::createInstance(Locale::getEnglish(), success);
+ if (colerror != 0 || success == U_ZERO_ERROR){
+ errln("Error: createInstance(UErrorCode != U_ZERO_ERROR) should just return and not create an instance\n");
+ }
+ int32_t position=coliter->previous(success);
+ if(position != CollationElementIterator::NULLORDER){
+ errln((UnicodeString)"Expected NULLORDER got" + position);
+ }
+ coliter->reset();
+ coliter->setText(*chariter, success);
+ if(!U_FAILURE(success)){
+ errln("Expeceted error");
+ }
+ iterator1->setText((UnicodeString)"hello there", success);
+ if(!U_FAILURE(success)){
+ errln("Expeceted error");
+ }
+
+ delete chariter;
+ delete coliter;
+ delete iterator1;
+ delete iterator2;
+ delete iterator3;
+ delete col;
+
+
+
+ logln("testing CollationElementIterator ends...");
+}
+
+// Test RuleBasedCollator ctor, dtor, operator==, operator!=, clone, copy, and getRules
+void
+CollationAPITest::TestOperators(/* char* par */)
+{
+ UErrorCode success = U_ZERO_ERROR;
+ UnicodeString ruleset1("< a, A < b, B < c, C; ch, cH, Ch, CH < d, D, e, E");
+ UnicodeString ruleset2("< a, A < b, B < c, C < d, D, e, E");
+ RuleBasedCollator *col1 = new RuleBasedCollator(ruleset1, success);
+ if (U_FAILURE(success)) {
+ errln("RuleBasedCollator creation failed.");
+ return;
+ }
+ success = U_ZERO_ERROR;
+ RuleBasedCollator *col2 = new RuleBasedCollator(ruleset2, success);
+ if (U_FAILURE(success)) {
+ errln("The RuleBasedCollator constructor failed when building with the 2nd rule set.");
+ return;
+ }
+ logln("The operator tests begin : ");
+ logln("testing operator==, operator!=, clone methods ...");
+ doAssert((*col1 != *col2), "The two different table collations compared equal");
+ *col1 = *col2;
+ doAssert((*col1 == *col2), "Collator objects not equal after assignment (operator=)");
+
+ success = U_ZERO_ERROR;
+ Collator *col3 = Collator::createInstance(Locale::getEnglish(), success);
+ if (U_FAILURE(success)) {
+ errln("Default collation creation failed.");
+ return;
+ }
+ doAssert((*col1 != *col3), "The two different table collations compared equal");
+ Collator* col4 = col1->clone();
+ Collator* col5 = col3->clone();
+ doAssert((*col1 == *col4), "Cloned collation objects not equal");
+ doAssert((*col3 != *col4), "Two different table collations compared equal");
+ doAssert((*col3 == *col5), "Cloned collation objects not equal");
+ doAssert((*col4 != *col5), "Two cloned collations compared equal");
+
+ const UnicodeString& defRules = ((RuleBasedCollator*)col3)->getRules();
+ RuleBasedCollator* col6 = new RuleBasedCollator(defRules, success);
+ if (U_FAILURE(success)) {
+ errln("Creating default collation with rules failed.");
+ return;
+ }
+ doAssert((((RuleBasedCollator*)col3)->getRules() == col6->getRules()), "Default collator getRules failed");
+
+ success = U_ZERO_ERROR;
+ RuleBasedCollator *col7 = new RuleBasedCollator(ruleset2, Collator::TERTIARY, success);
+ if (U_FAILURE(success)) {
+ errln("The RuleBasedCollator constructor failed when building with the 2nd rule set with tertiary strength.");
+ return;
+ }
+ success = U_ZERO_ERROR;
+ RuleBasedCollator *col8 = new RuleBasedCollator(ruleset2, UCOL_OFF, success);
+ if (U_FAILURE(success)) {
+ errln("The RuleBasedCollator constructor failed when building with the 2nd rule set with Normalizer::NO_OP.");
+ return;
+ }
+ success = U_ZERO_ERROR;
+ RuleBasedCollator *col9 = new RuleBasedCollator(ruleset2, Collator::PRIMARY, UCOL_ON, success);
+ if (U_FAILURE(success)) {
+ errln("The RuleBasedCollator constructor failed when building with the 2nd rule set with tertiary strength and Normalizer::NO_OP.");
+ return;
+ }
+ // doAssert((*col7 == *col8), "The two equal table collations compared different");
+ doAssert((*col7 != *col9), "The two different table collations compared equal");
+ doAssert((*col8 != *col9), "The two different table collations compared equal");
+
+ logln("operator tests ended.");
+ delete col1;
+ delete col2;
+ delete col3;
+ delete col4;
+ delete col5;
+ delete col6;
+ delete col7;
+ delete col8;
+ delete col9;
+}
+
+// test clone and copy
+void
+CollationAPITest::TestDuplicate(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *col1 = Collator::createInstance(Locale::getEnglish(), status);
+ if (U_FAILURE(status)) {
+ logln("Default collator creation failed.");
+ return;
+ }
+ Collator *col2 = col1->clone();
+ doAssert((*col1 == *col2), "Cloned object is not equal to the orginal");
+ UnicodeString *ruleset = new UnicodeString("< a, A < b, B < c, C < d, D, e, E");
+ RuleBasedCollator *col3 = new RuleBasedCollator(*ruleset, status);
+ doAssert((*col1 != *col3), "Cloned object is equal to some dummy");
+ *col3 = *((RuleBasedCollator*)col1);
+ doAssert((*col1 == *col3), "Copied object is not equal to the orginal");
+
+ if (U_FAILURE(status)) {
+ logln("Collation tailoring failed.");
+ return;
+ }
+
+ UCollationResult res;
+ UnicodeString first((UChar)0x0061);
+ UnicodeString second((UChar)0x0062);
+ UnicodeString copiedEnglishRules(((RuleBasedCollator*)col1)->getRules());
+
+ delete col1;
+ delete ruleset;
+
+ // Try using the cloned collators after deleting the original data
+ res = col2->compare(first, second, status);
+ if(res != UCOL_LESS) {
+ errln("a should be less then b after tailoring");
+ }
+ if (((RuleBasedCollator*)col2)->getRules() != copiedEnglishRules) {
+ errln(UnicodeString("English rule difference. ")
+ + copiedEnglishRules + UnicodeString("\ngetRules=") + ((RuleBasedCollator*)col2)->getRules());
+ }
+ res = col3->compare(first, second, status);
+ if(res != UCOL_LESS) {
+ errln("a should be less then b after tailoring");
+ }
+ if (col3->getRules() != copiedEnglishRules) {
+ errln(UnicodeString("English rule difference. ")
+ + copiedEnglishRules + UnicodeString("\ngetRules=") + col3->getRules());
+ }
+
+ delete col2;
+ delete col3;
+}
+
+void
+CollationAPITest::TestCompare(/* char* par */)
+{
+ logln("The compare tests begin : ");
+ Collator *col = 0;
+ UErrorCode success = U_ZERO_ERROR;
+ col = Collator::createInstance(Locale::getEnglish(), success);
+ if (U_FAILURE(success)) {
+ errln("Default collation creation failed.");
+ return;
+ }
+ UnicodeString test1("Abcda"), test2("abcda");
+ logln("Use tertiary comparison level testing ....");
+
+ doAssert((!col->equals(test1, test2) ), "Result should be \"Abcda\" != \"abcda\"");
+ doAssert((col->greater(test1, test2) ), "Result should be \"Abcda\" >>> \"abcda\"");
+ doAssert((col->greaterOrEqual(test1, test2) ), "Result should be \"Abcda\" >>> \"abcda\"");
+
+ col->setStrength(Collator::SECONDARY);
+ logln("Use secondary comparison level testing ....");
+
+ doAssert((col->equals(test1, test2) ), "Result should be \"Abcda\" == \"abcda\"");
+ doAssert((!col->greater(test1, test2) ), "Result should be \"Abcda\" == \"abcda\"");
+ doAssert((col->greaterOrEqual(test1, test2) ), "Result should be \"Abcda\" == \"abcda\"");
+
+ col->setStrength(Collator::PRIMARY);
+ logln("Use primary comparison level testing ....");
+
+ doAssert((col->equals(test1, test2) ), "Result should be \"Abcda\" == \"abcda\"");
+ doAssert((!col->greater(test1, test2) ), "Result should be \"Abcda\" == \"abcda\"");
+ doAssert((col->greaterOrEqual(test1, test2) ), "Result should be \"Abcda\" == \"abcda\"");
+
+ // Test different APIs
+ const UChar* t1 = test1.getBuffer();
+ int32_t t1Len = test1.length();
+ const UChar* t2 = test2.getBuffer();
+ int32_t t2Len = test2.length();
+
+ doAssert((col->compare(test1, test2) == Collator::EQUAL), "Problem");
+ doAssert((col->compare(test1, test2, success) == UCOL_EQUAL), "Problem");
+ doAssert((col->compare(t1, t1Len, t2, t2Len) == Collator::EQUAL), "Problem");
+ doAssert((col->compare(t1, t1Len, t2, t2Len, success) == UCOL_EQUAL), "Problem");
+ doAssert((col->compare(test1, test2, t1Len) == Collator::EQUAL), "Problem");
+ doAssert((col->compare(test1, test2, t1Len, success) == UCOL_EQUAL), "Problem");
+
+ col->setAttribute(UCOL_STRENGTH, UCOL_TERTIARY, success);
+ doAssert((col->compare(test1, test2) == Collator::GREATER), "Problem");
+ doAssert((col->compare(test1, test2, success) == UCOL_GREATER), "Problem");
+ doAssert((col->compare(t1, t1Len, t2, t2Len) == Collator::GREATER), "Problem");
+ doAssert((col->compare(t1, t1Len, t2, t2Len, success) == UCOL_GREATER), "Problem");
+ doAssert((col->compare(test1, test2, t1Len) == Collator::GREATER), "Problem");
+ doAssert((col->compare(test1, test2, t1Len, success) == UCOL_GREATER), "Problem");
+
+
+
+ logln("The compare tests end.");
+ delete col;
+}
+
+void
+CollationAPITest::TestGetAll(/* char* par */)
+{
+ int32_t count1, count2;
+ UErrorCode status = U_ZERO_ERROR;
+
+ logln("Trying Collator::getAvailableLocales(int&)");
+
+ const Locale* list = Collator::getAvailableLocales(count1);
+ for (int32_t i = 0; i < count1; ++i) {
+ UnicodeString dispName;
+ logln(UnicodeString("Locale name: ")
+ + UnicodeString(list[i].getName())
+ + UnicodeString(" , the display name is : ")
+ + UnicodeString(list[i].getDisplayName(dispName)));
+ }
+
+ if (count1 == 0 || list == NULL) {
+ errln("getAvailableLocales(int&) returned an empty list");
+ }
+
+ logln("Trying Collator::getAvailableLocales()");
+ StringEnumeration* localeEnum = Collator::getAvailableLocales();
+ const UnicodeString* locStr;
+ const char *locCStr;
+ count2 = 0;
+
+ if (localeEnum == NULL) {
+ errln("getAvailableLocales() returned NULL");
+ return;
+ }
+
+ while ((locStr = localeEnum->snext(status)) != NULL)
+ {
+ logln(UnicodeString("Locale name is: ") + *locStr);
+ count2++;
+ }
+ if (count1 != count2) {
+ errln("getAvailableLocales(int&) returned %d and getAvailableLocales() returned %d", count1, count2);
+ }
+
+ logln("Trying Collator::getAvailableLocales() clone");
+ count1 = 0;
+ StringEnumeration* localeEnum2 = localeEnum->clone();
+ localeEnum2->reset(status);
+ while ((locCStr = localeEnum2->next(NULL, status)) != NULL)
+ {
+ logln(UnicodeString("Locale name is: ") + UnicodeString(locCStr));
+ count1++;
+ }
+ if (count1 != count2) {
+ errln("getAvailableLocales(3rd time) returned %d and getAvailableLocales(2nd time) returned %d", count1, count2);
+ }
+ if (localeEnum->count(status) != count1) {
+ errln("localeEnum->count() returned %d and getAvailableLocales() returned %d", localeEnum->count(status), count1);
+ }
+ delete localeEnum;
+ delete localeEnum2;
+}
+
+void CollationAPITest::TestSortKey()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ /*
+ this is supposed to open default date format, but later on it treats
+ it like it is "en_US"
+ - very bad if you try to run the tests on machine where default
+ locale is NOT "en_US"
+ */
+ Collator *col = Collator::createInstance(Locale::getEnglish(), status);
+ if (U_FAILURE(status)) {
+ errln("ERROR: Default collation creation failed.: %s\n", u_errorName(status));
+ return;
+ }
+
+ if (col->getStrength() != Collator::TERTIARY)
+ {
+ errln("ERROR: default collation did not have UCOL_DEFAULT_STRENGTH !\n");
+ }
+
+ /* Need to use identical strength */
+ col->setAttribute(UCOL_STRENGTH, UCOL_IDENTICAL, status);
+
+ uint8_t key2compat[] = {
+ /* 3.6 key, from UCA 5.0 */
+ 0x29, 0x2b, 0x2d, 0x2f, 0x29, 0x01,
+ 0x09, 0x01, 0x09, 0x01, 0x28, 0x01,
+ 0x92, 0x93, 0x94, 0x95, 0x92, 0x00
+
+ /* 3.4 key, from UCA 4.1 */
+ /*
+ 0x28, 0x2a, 0x2c, 0x2e, 0x28, 0x01,
+ 0x09, 0x01, 0x09, 0x01, 0x27, 0x01,
+ 0x92, 0x93, 0x94, 0x95, 0x92, 0x00
+ */
+ /* 2.6.1 key */
+ /*
+ 0x26, 0x28, 0x2A, 0x2C, 0x26, 0x01,
+ 0x09, 0x01, 0x09, 0x01, 0x25, 0x01,
+ 0x92, 0x93, 0x94, 0x95, 0x92, 0x00
+ */
+ /* 2.2 key */
+ /*
+ 0x1D, 0x1F, 0x21, 0x23, 0x1D, 0x01,
+ 0x09, 0x01, 0x09, 0x01, 0x1C, 0x01,
+ 0x92, 0x93, 0x94, 0x95, 0x92, 0x00
+ */
+ /* 2.0 key */
+ /*
+ 0x19, 0x1B, 0x1D, 0x1F, 0x19,
+ 0x01, 0x09, 0x01, 0x09, 0x01,
+ 0x18, 0x01,
+ 0x92, 0x93, 0x94, 0x95, 0x92,
+ 0x00
+ */
+ /* 1.8.1 key.*/
+ /*
+ 0x19, 0x1B, 0x1D, 0x1F, 0x19,
+ 0x01, 0x0A, 0x01, 0x0A, 0x01,
+ 0x92, 0x93, 0x94, 0x95, 0x92,
+ 0x00
+ */
+ };
+
+ UChar test1[6] = {0x41, 0x62, 0x63, 0x64, 0x61, 0},
+ test2[6] = {0x61, 0x62, 0x63, 0x64, 0x61, 0},
+ test3[6] = {0x61, 0x62, 0x63, 0x64, 0x61, 0};
+
+ uint8_t sortkey1[64];
+ uint8_t sortkey2[64];
+ uint8_t sortkey3[64];
+
+ logln("Use tertiary comparison level testing ....\n");
+
+ CollationKey key1;
+ col->getCollationKey(test1, u_strlen(test1), key1, status);
+
+ CollationKey key2;
+ col->getCollationKey(test2, u_strlen(test2), key2, status);
+
+ CollationKey key3;
+ col->getCollationKey(test3, u_strlen(test3), key3, status);
+
+ doAssert(key1.compareTo(key2) == Collator::GREATER,
+ "Result should be \"Abcda\" > \"abcda\"");
+ doAssert(key2.compareTo(key1) == Collator::LESS,
+ "Result should be \"abcda\" < \"Abcda\"");
+ doAssert(key2.compareTo(key3) == Collator::EQUAL,
+ "Result should be \"abcda\" == \"abcda\"");
+
+ int32_t keylength = 0;
+ doAssert(strcmp((const char *)(key2.getByteArray(keylength)),
+ (const char *)key2compat) == 0,
+ "Binary format for 'abcda' sortkey different!");
+
+ col->getSortKey(test1, sortkey1, 64);
+ col->getSortKey(test2, sortkey2, 64);
+ col->getSortKey(test3, sortkey3, 64);
+
+ const uint8_t *tempkey = key1.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey1, keylength) == 0,
+ "Test1 string should have the same collation key and sort key");
+ tempkey = key2.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey2, keylength) == 0,
+ "Test2 string should have the same collation key and sort key");
+ tempkey = key3.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey3, keylength) == 0,
+ "Test3 string should have the same collation key and sort key");
+
+ col->getSortKey(test1, 5, sortkey1, 64);
+ col->getSortKey(test2, 5, sortkey2, 64);
+ col->getSortKey(test3, 5, sortkey3, 64);
+
+ tempkey = key1.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey1, keylength) == 0,
+ "Test1 string should have the same collation key and sort key");
+ tempkey = key2.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey2, keylength) == 0,
+ "Test2 string should have the same collation key and sort key");
+ tempkey = key3.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey3, keylength) == 0,
+ "Test3 string should have the same collation key and sort key");
+
+ UnicodeString strtest1(test1);
+ col->getSortKey(strtest1, sortkey1, 64);
+ UnicodeString strtest2(test2);
+ col->getSortKey(strtest2, sortkey2, 64);
+ UnicodeString strtest3(test3);
+ col->getSortKey(strtest3, sortkey3, 64);
+
+ tempkey = key1.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey1, keylength) == 0,
+ "Test1 string should have the same collation key and sort key");
+ tempkey = key2.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey2, keylength) == 0,
+ "Test2 string should have the same collation key and sort key");
+ tempkey = key3.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey3, keylength) == 0,
+ "Test3 string should have the same collation key and sort key");
+
+ logln("Use secondary comparision level testing ...\n");
+ col->setStrength(Collator::SECONDARY);
+
+ col->getCollationKey(test1, u_strlen(test1), key1, status);
+ col->getCollationKey(test2, u_strlen(test2), key2, status);
+ col->getCollationKey(test3, u_strlen(test3), key3, status);
+
+ doAssert(key1.compareTo(key2) == Collator::EQUAL,
+ "Result should be \"Abcda\" == \"abcda\"");
+ doAssert(key2.compareTo(key3) == Collator::EQUAL,
+ "Result should be \"abcda\" == \"abcda\"");
+
+ tempkey = key2.getByteArray(keylength);
+ doAssert(memcmp(tempkey, key2compat, keylength - 1) == 0,
+ "Binary format for 'abcda' sortkey different!");
+
+ col->getSortKey(test1, sortkey1, 64);
+ col->getSortKey(test2, sortkey2, 64);
+ col->getSortKey(test3, sortkey3, 64);
+
+ tempkey = key1.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey1, keylength) == 0,
+ "Test1 string should have the same collation key and sort key");
+ tempkey = key2.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey2, keylength) == 0,
+ "Test2 string should have the same collation key and sort key");
+ tempkey = key3.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey3, keylength) == 0,
+ "Test3 string should have the same collation key and sort key");
+
+ col->getSortKey(test1, 5, sortkey1, 64);
+ col->getSortKey(test2, 5, sortkey2, 64);
+ col->getSortKey(test3, 5, sortkey3, 64);
+
+ tempkey = key1.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey1, keylength) == 0,
+ "Test1 string should have the same collation key and sort key");
+ tempkey = key2.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey2, keylength) == 0,
+ "Test2 string should have the same collation key and sort key");
+ tempkey = key3.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey3, keylength) == 0,
+ "Test3 string should have the same collation key and sort key");
+
+ col->getSortKey(strtest1, sortkey1, 64);
+ col->getSortKey(strtest2, sortkey2, 64);
+ col->getSortKey(strtest3, sortkey3, 64);
+
+ tempkey = key1.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey1, keylength) == 0,
+ "Test1 string should have the same collation key and sort key");
+ tempkey = key2.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey2, keylength) == 0,
+ "Test2 string should have the same collation key and sort key");
+ tempkey = key3.getByteArray(keylength);
+ doAssert(memcmp(tempkey, sortkey3, keylength) == 0,
+ "Test3 string should have the same collation key and sort key");
+
+ logln("testing sortkey ends...");
+ delete col;
+}
+
+void CollationAPITest::TestMaxExpansion()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UChar ch = 0;
+ UChar32 unassigned = 0xEFFFD;
+ uint32_t sorder = 0;
+ uint32_t temporder = 0;
+
+ UnicodeString rule("&a < ab < c/aba < d < z < ch");
+ RuleBasedCollator coll(rule, status);
+ if(U_FAILURE(status)) {
+ errln("Collator creation failed with error %s", u_errorName(status));
+ return;
+ }
+ UnicodeString str(ch);
+ CollationElementIterator *iter =
+ coll.createCollationElementIterator(str);
+
+ while (ch < 0xFFFF && U_SUCCESS(status)) {
+ int count = 1;
+ uint32_t order;
+ int32_t size = 0;
+
+ ch ++;
+
+ str.setCharAt(0, ch);
+ iter->setText(str, status);
+ order = iter->previous(status);
+
+ /* thai management */
+ if (order == 0)
+ order = iter->previous(status);
+
+ while (U_SUCCESS(status) && iter->previous(status) != UCOL_NULLORDER) {
+ count ++;
+ }
+
+ size = coll.getMaxExpansion(order);
+ if (U_FAILURE(status) || size < count) {
+ errln("Failure at codepoint %d, maximum expansion count < %d\n",
+ ch, count);
+ }
+ }
+
+ /* testing for exact max expansion */
+ ch = 0;
+ while (ch < 0x61) {
+ uint32_t order;
+ int32_t size;
+ str.setCharAt(0, ch);
+ iter->setText(str, status);
+ order = iter->previous(status);
+ size = coll.getMaxExpansion(order);
+ if (U_FAILURE(status) || size != 1) {
+ errln("Failure at codepoint %d, maximum expansion count < %d\n",
+ ch, 1);
+ }
+ ch ++;
+ }
+
+ ch = 0x63;
+ str.setTo(ch);
+ iter->setText(str, status);
+ temporder = iter->previous(status);
+
+ if (U_FAILURE(status) || coll.getMaxExpansion(temporder) != 3) {
+ errln("Failure at codepoint %d, maximum expansion count != %d\n",
+ ch, 3);
+ }
+
+ ch = 0x64;
+ str.setTo(ch);
+ iter->setText(str, status);
+ temporder = iter->previous(status);
+
+ if (U_FAILURE(status) || coll.getMaxExpansion(temporder) != 1) {
+ errln("Failure at codepoint %d, maximum expansion count != %d\n",
+ ch, 3);
+ }
+
+ str.setTo(unassigned);
+ iter->setText(str, status);
+ sorder = iter->previous(status);
+
+ if (U_FAILURE(status) || coll.getMaxExpansion(sorder) != 2) {
+ errln("Failure at supplementary codepoints, maximum expansion count < %d\n",
+ 2);
+ }
+
+ /* testing jamo */
+ ch = 0x1165;
+ str.setTo(ch);
+ iter->setText(str, status);
+ temporder = iter->previous(status);
+ if (U_FAILURE(status) || coll.getMaxExpansion(temporder) > 3) {
+ errln("Failure at codepoint %d, maximum expansion count > %d\n",
+ ch, 3);
+ }
+
+ delete iter;
+
+ /* testing special jamo &a<\u1160 */
+ rule = CharsToUnicodeString("\\u0026\\u0071\\u003c\\u1165\\u002f\\u0071\\u0071\\u0071\\u0071");
+
+ RuleBasedCollator jamocoll(rule, status);
+ iter = jamocoll.createCollationElementIterator(str);
+ temporder = iter->previous(status);
+ if (U_FAILURE(status) || iter->getMaxExpansion(temporder) != 6) {
+ errln("Failure at codepoint %d, maximum expansion count > %d\n",
+ ch, 5);
+ }
+
+ delete iter;
+}
+
+void CollationAPITest::TestDisplayName()
+{
+ UErrorCode error = U_ZERO_ERROR;
+ Collator *coll = Collator::createInstance("en_US", error);
+ if (U_FAILURE(error)) {
+ errln("Failure creating english collator");
+ return;
+ }
+ UnicodeString name;
+ UnicodeString result;
+ coll->getDisplayName(Locale::getCanadaFrench(), result);
+ Locale::getCanadaFrench().getDisplayName(name);
+ if (result.compare(name)) {
+ errln("Failure getting the correct name for locale en_US");
+ }
+
+ coll->getDisplayName(Locale::getSimplifiedChinese(), result);
+ Locale::getSimplifiedChinese().getDisplayName(name);
+ if (result.compare(name)) {
+ errln("Failure getting the correct name for locale zh_SG");
+ }
+ delete coll;
+}
+
+void CollationAPITest::TestAttribute()
+{
+ UErrorCode error = U_ZERO_ERROR;
+ Collator *coll = Collator::createInstance(error);
+
+ if (U_FAILURE(error)) {
+ errln("Creation of default collator failed");
+ return;
+ }
+
+ coll->setAttribute(UCOL_FRENCH_COLLATION, UCOL_OFF, error);
+ if (coll->getAttribute(UCOL_FRENCH_COLLATION, error) != UCOL_OFF ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the french collation failed");
+ }
+
+ coll->setAttribute(UCOL_FRENCH_COLLATION, UCOL_ON, error);
+ if (coll->getAttribute(UCOL_FRENCH_COLLATION, error) != UCOL_ON ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the french collation failed");
+ }
+
+ coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, error);
+ if (coll->getAttribute(UCOL_ALTERNATE_HANDLING, error) != UCOL_SHIFTED ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the alternate handling failed");
+ }
+
+ coll->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, error);
+ if (coll->getAttribute(UCOL_ALTERNATE_HANDLING, error) != UCOL_NON_IGNORABLE ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the alternate handling failed");
+ }
+
+ coll->setAttribute(UCOL_CASE_FIRST, UCOL_LOWER_FIRST, error);
+ if (coll->getAttribute(UCOL_CASE_FIRST, error) != UCOL_LOWER_FIRST ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the case first attribute failed");
+ }
+
+ coll->setAttribute(UCOL_CASE_FIRST, UCOL_UPPER_FIRST, error);
+ if (coll->getAttribute(UCOL_CASE_FIRST, error) != UCOL_UPPER_FIRST ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the case first attribute failed");
+ }
+
+ coll->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, error);
+ if (coll->getAttribute(UCOL_CASE_LEVEL, error) != UCOL_ON ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the case level attribute failed");
+ }
+
+ coll->setAttribute(UCOL_CASE_LEVEL, UCOL_OFF, error);
+ if (coll->getAttribute(UCOL_CASE_LEVEL, error) != UCOL_OFF ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the case level attribute failed");
+ }
+
+ coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, error);
+ if (coll->getAttribute(UCOL_NORMALIZATION_MODE, error) != UCOL_ON ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the normalization on/off attribute failed");
+ }
+
+ coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_OFF, error);
+ if (coll->getAttribute(UCOL_NORMALIZATION_MODE, error) != UCOL_OFF ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the normalization on/off attribute failed");
+ }
+
+ coll->setAttribute(UCOL_STRENGTH, UCOL_PRIMARY, error);
+ if (coll->getAttribute(UCOL_STRENGTH, error) != UCOL_PRIMARY ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the collation strength failed");
+ }
+
+ coll->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, error);
+ if (coll->getAttribute(UCOL_STRENGTH, error) != UCOL_SECONDARY ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the collation strength failed");
+ }
+
+ coll->setAttribute(UCOL_STRENGTH, UCOL_TERTIARY, error);
+ if (coll->getAttribute(UCOL_STRENGTH, error) != UCOL_TERTIARY ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the collation strength failed");
+ }
+
+ coll->setAttribute(UCOL_STRENGTH, UCOL_QUATERNARY, error);
+ if (coll->getAttribute(UCOL_STRENGTH, error) != UCOL_QUATERNARY ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the collation strength failed");
+ }
+
+ coll->setAttribute(UCOL_STRENGTH, UCOL_IDENTICAL, error);
+ if (coll->getAttribute(UCOL_STRENGTH, error) != UCOL_IDENTICAL ||
+ U_FAILURE(error)) {
+ errln("Setting and retrieving of the collation strength failed");
+ }
+
+ delete coll;
+}
+
+void CollationAPITest::TestVariableTopSetting() {
+ UErrorCode status = U_ZERO_ERROR;
+
+ UChar vt[256] = { 0 };
+
+ Collator *coll = Collator::createInstance(status);
+ if(U_FAILURE(status)) {
+ delete coll;
+ errln("Collator creation failed with error %s", u_errorName(status));
+ return;
+ }
+
+ uint32_t oldVarTop = coll->getVariableTop(status);
+
+ vt[0] = 0x0041;
+
+ uint32_t newVarTop = coll->setVariableTop(vt, 1, status);
+
+ if((newVarTop & 0xFFFF0000) != (coll->getVariableTop(status) & 0xFFFF0000)) {
+ errln("Didn't set vartop properly\n");
+ }
+
+ coll->setVariableTop(oldVarTop, status);
+
+ uint32_t newerVarTop = coll->setVariableTop(UnicodeString(vt, 1), status);
+
+ if((newVarTop & 0xFFFF0000) != (newerVarTop & 0xFFFF0000)) {
+ errln("Didn't set vartop properly from UnicodeString!\n");
+ }
+
+ delete coll;
+
+}
+
+void CollationAPITest::TestGetLocale() {
+ UErrorCode status = U_ZERO_ERROR;
+ const char *rules = "&a<x<y<z";
+ UChar rlz[256] = {0};
+
+ Collator *coll = NULL;
+ Locale locale;
+
+ int32_t i = 0;
+
+ static const struct {
+ const char* requestedLocale;
+ const char* validLocale;
+ const char* actualLocale;
+ } testStruct[] = {
+ { "sr_YU", "sr_YU", "root" },
+ { "sh_YU", "sh_YU", "sh" },
+ { "en_US_CALIFORNIA", "en_US", "root" },
+ { "fr_FR_NONEXISTANT", "fr_FR", "fr" }
+ };
+
+ u_unescape(rules, rlz, 256);
+
+ /* test opening collators for different locales */
+ for(i = 0; i<(int32_t)(sizeof(testStruct)/sizeof(testStruct[0])); i++) {
+ status = U_ZERO_ERROR;
+ coll = Collator::createInstance(testStruct[i].requestedLocale, status);
+ if(U_FAILURE(status)) {
+ log("Failed to open collator for %s with %s\n", testStruct[i].requestedLocale, u_errorName(status));
+ delete coll;
+ continue;
+ }
+ locale = coll->getLocale(ULOC_REQUESTED_LOCALE, status);
+ if(locale != testStruct[i].requestedLocale) {
+ log("[Coll %s]: Error in requested locale, expected %s, got %s\n", testStruct[i].requestedLocale, testStruct[i].requestedLocale, locale.getName());
+ }
+ locale = coll->getLocale(ULOC_VALID_LOCALE, status);
+ if(locale != testStruct[i].validLocale) {
+ log("[Coll %s]: Error in valid locale, expected %s, got %s\n", testStruct[i].requestedLocale, testStruct[i].validLocale, locale.getName());
+ }
+ locale = coll->getLocale(ULOC_ACTUAL_LOCALE, status);
+ if(locale != testStruct[i].actualLocale) {
+ log("[Coll %s]: Error in actual locale, expected %s, got %s\n", testStruct[i].requestedLocale, testStruct[i].actualLocale, locale.getName());
+ }
+ delete coll;
+ }
+
+ /* completely non-existant locale for collator should get a default collator */
+ {
+ Collator *defaultColl = Collator::createInstance((const Locale)NULL, status);
+ coll = Collator::createInstance("blahaha", status);
+ if(U_FAILURE(status)) {
+ log("Failed to open collator with %s\n", u_errorName(status));
+ delete coll;
+ delete defaultColl;
+ return;
+ }
+ if(coll->getLocale(ULOC_REQUESTED_LOCALE, status) != "blahaha") {
+ log("Nonexisting locale didn't preserve the requested locale\n");
+ }
+ if(coll->getLocale(ULOC_VALID_LOCALE, status) !=
+ defaultColl->getLocale(ULOC_VALID_LOCALE, status)) {
+ log("Valid locale for nonexisting locale locale collator differs "
+ "from valid locale for default collator\n");
+ }
+ if(coll->getLocale(ULOC_ACTUAL_LOCALE, status) !=
+ defaultColl->getLocale(ULOC_ACTUAL_LOCALE, status)) {
+ log("Actual locale for nonexisting locale locale collator differs "
+ "from actual locale for default collator\n");
+ }
+ delete coll;
+ delete defaultColl;
+ }
+
+
+
+ /* collator instantiated from rules should have all three locales NULL */
+ coll = new RuleBasedCollator(rlz, status);
+ locale = coll->getLocale(ULOC_REQUESTED_LOCALE, status);
+ if(!locale.isBogus()) {
+ log("For collator instantiated from rules, requested locale %s is not bogus\n", locale.getName());
+ }
+ locale = coll->getLocale(ULOC_VALID_LOCALE, status);
+ if(!locale.isBogus()) {
+ log("For collator instantiated from rules, valid locale %s is not bogus\n", locale.getName());
+ }
+ locale = coll->getLocale(ULOC_ACTUAL_LOCALE, status);
+ if(!locale.isBogus()) {
+ log("For collator instantiated from rules, actual locale %s is not bogus\n", locale.getName());
+ }
+ delete coll;
+}
+
+struct teststruct {
+ const char *original;
+ uint8_t key[256];
+};
+
+
+
+U_CDECL_BEGIN
+static int U_CALLCONV
+compare_teststruct(const void *string1, const void *string2) {
+ return(strcmp((const char *)((struct teststruct *)string1)->key, (const char *)((struct teststruct *)string2)->key));
+}
+U_CDECL_END
+
+
+void CollationAPITest::TestBounds(void) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ Collator *coll = Collator::createInstance(Locale("sh"), status);
+ if(U_FAILURE(status)) {
+ delete coll;
+ errln("Collator creation failed with %s", u_errorName(status));
+ return;
+ }
+
+ uint8_t sortkey[512], lower[512], upper[512];
+ UChar buffer[512];
+
+ static const char * const test[] = {
+ "John Smith",
+ "JOHN SMITH",
+ "john SMITH",
+ "j\\u00F6hn sm\\u00EFth",
+ "J\\u00F6hn Sm\\u00EFth",
+ "J\\u00D6HN SM\\u00CFTH",
+ "john smithsonian",
+ "John Smithsonian"
+ };
+
+ struct teststruct tests[] = {
+ {"\\u010CAKI MIHALJ", {0}},
+ {"\\u010CAKI MIHALJ", {0}},
+ {"\\u010CAKI PIRO\\u0160KA", {0}},
+ {"\\u010CABAI ANDRIJA", {0}},
+ {"\\u010CABAI LAJO\\u0160", {0}},
+ {"\\u010CABAI MARIJA", {0}},
+ {"\\u010CABAI STEVAN", {0}},
+ {"\\u010CABAI STEVAN", {0}},
+ {"\\u010CABARKAPA BRANKO", {0}},
+ {"\\u010CABARKAPA MILENKO", {0}},
+ {"\\u010CABARKAPA MIROSLAV", {0}},
+ {"\\u010CABARKAPA SIMO", {0}},
+ {"\\u010CABARKAPA STANKO", {0}},
+ {"\\u010CABARKAPA TAMARA", {0}},
+ {"\\u010CABARKAPA TOMA\\u0160", {0}},
+ {"\\u010CABDARI\\u0106 NIKOLA", {0}},
+ {"\\u010CABDARI\\u0106 ZORICA", {0}},
+ {"\\u010CABI NANDOR", {0}},
+ {"\\u010CABOVI\\u0106 MILAN", {0}},
+ {"\\u010CABRADI AGNEZIJA", {0}},
+ {"\\u010CABRADI IVAN", {0}},
+ {"\\u010CABRADI JELENA", {0}},
+ {"\\u010CABRADI LJUBICA", {0}},
+ {"\\u010CABRADI STEVAN", {0}},
+ {"\\u010CABRDA MARTIN", {0}},
+ {"\\u010CABRILO BOGDAN", {0}},
+ {"\\u010CABRILO BRANISLAV", {0}},
+ {"\\u010CABRILO LAZAR", {0}},
+ {"\\u010CABRILO LJUBICA", {0}},
+ {"\\u010CABRILO SPASOJA", {0}},
+ {"\\u010CADE\\u0160 ZDENKA", {0}},
+ {"\\u010CADESKI BLAGOJE", {0}},
+ {"\\u010CADOVSKI VLADIMIR", {0}},
+ {"\\u010CAGLJEVI\\u0106 TOMA", {0}},
+ {"\\u010CAGOROVI\\u0106 VLADIMIR", {0}},
+ {"\\u010CAJA VANKA", {0}},
+ {"\\u010CAJI\\u0106 BOGOLJUB", {0}},
+ {"\\u010CAJI\\u0106 BORISLAV", {0}},
+ {"\\u010CAJI\\u0106 RADOSLAV", {0}},
+ {"\\u010CAK\\u0160IRAN MILADIN", {0}},
+ {"\\u010CAKAN EUGEN", {0}},
+ {"\\u010CAKAN EVGENIJE", {0}},
+ {"\\u010CAKAN IVAN", {0}},
+ {"\\u010CAKAN JULIJAN", {0}},
+ {"\\u010CAKAN MIHAJLO", {0}},
+ {"\\u010CAKAN STEVAN", {0}},
+ {"\\u010CAKAN VLADIMIR", {0}},
+ {"\\u010CAKAN VLADIMIR", {0}},
+ {"\\u010CAKAN VLADIMIR", {0}},
+ {"\\u010CAKARA ANA", {0}},
+ {"\\u010CAKAREVI\\u0106 MOMIR", {0}},
+ {"\\u010CAKAREVI\\u0106 NEDELJKO", {0}},
+ {"\\u010CAKI \\u0160ANDOR", {0}},
+ {"\\u010CAKI AMALIJA", {0}},
+ {"\\u010CAKI ANDRA\\u0160", {0}},
+ {"\\u010CAKI LADISLAV", {0}},
+ {"\\u010CAKI LAJO\\u0160", {0}},
+ {"\\u010CAKI LASLO", {0}}
+ };
+
+
+
+ int32_t i = 0, j = 0, k = 0, buffSize = 0, skSize = 0, lowerSize = 0, upperSize = 0;
+ int32_t arraySize = sizeof(tests)/sizeof(tests[0]);
+
+ for(i = 0; i<arraySize; i++) {
+ buffSize = u_unescape(tests[i].original, buffer, 512);
+ skSize = coll->getSortKey(buffer, buffSize, tests[i].key, 512);
+ }
+
+ qsort(tests, arraySize, sizeof(struct teststruct), compare_teststruct);
+
+ for(i = 0; i < arraySize-1; i++) {
+ for(j = i+1; j < arraySize; j++) {
+ lowerSize = coll->getBound(tests[i].key, -1, UCOL_BOUND_LOWER, 1, lower, 512, status);
+ upperSize = coll->getBound(tests[j].key, -1, UCOL_BOUND_UPPER, 1, upper, 512, status);
+ for(k = i; k <= j; k++) {
+ if(strcmp((const char *)lower, (const char *)tests[k].key) > 0) {
+ errln("Problem with lower! j = %i (%s vs %s)", k, tests[k].original, tests[i].original);
+ }
+ if(strcmp((const char *)upper, (const char *)tests[k].key) <= 0) {
+ errln("Problem with upper! j = %i (%s vs %s)", k, tests[k].original, tests[j].original);
+ }
+ }
+ }
+ }
+
+
+ for(i = 0; i<(int32_t)(sizeof(test)/sizeof(test[0])); i++) {
+ buffSize = u_unescape(test[i], buffer, 512);
+ skSize = coll->getSortKey(buffer, buffSize, sortkey, 512);
+ lowerSize = ucol_getBound(sortkey, skSize, UCOL_BOUND_LOWER, 1, lower, 512, &status);
+ upperSize = ucol_getBound(sortkey, skSize, UCOL_BOUND_UPPER_LONG, 1, upper, 512, &status);
+ for(j = i+1; j<(int32_t)(sizeof(test)/sizeof(test[0])); j++) {
+ buffSize = u_unescape(test[j], buffer, 512);
+ skSize = coll->getSortKey(buffer, buffSize, sortkey, 512);
+ if(strcmp((const char *)lower, (const char *)sortkey) > 0) {
+ errln("Problem with lower! i = %i, j = %i (%s vs %s)", i, j, test[i], test[j]);
+ }
+ if(strcmp((const char *)upper, (const char *)sortkey) <= 0) {
+ errln("Problem with upper! i = %i, j = %i (%s vs %s)", i, j, test[i], test[j]);
+ }
+ }
+ }
+ delete coll;
+}
+
+
+void CollationAPITest::TestGetTailoredSet()
+{
+ struct {
+ const char *rules;
+ const char *tests[20];
+ int32_t testsize;
+ } setTest[] = {
+ { "&a < \\u212b", { "\\u212b", "A\\u030a", "\\u00c5" }, 3},
+ { "& S < \\u0161 <<< \\u0160", { "\\u0161", "s\\u030C", "\\u0160", "S\\u030C" }, 4}
+ };
+
+ uint32_t i = 0, j = 0;
+ UErrorCode status = U_ZERO_ERROR;
+
+ RuleBasedCollator *coll = NULL;
+ UnicodeString buff;
+ UnicodeSet *set = NULL;
+
+ for(i = 0; i < sizeof(setTest)/sizeof(setTest[0]); i++) {
+ buff = UnicodeString(setTest[i].rules, "").unescape();
+ coll = new RuleBasedCollator(buff, status);
+ if(U_SUCCESS(status)) {
+ set = coll->getTailoredSet(status);
+ if(set->size() != setTest[i].testsize) {
+ errln("Tailored set size different (%d) than expected (%d)", set->size(), setTest[i].testsize);
+ }
+ for(j = 0; j < (uint32_t)setTest[i].testsize; j++) {
+ buff = UnicodeString(setTest[i].tests[j], "").unescape();
+ if(!set->contains(buff)) {
+ errln("Tailored set doesn't contain %s... It should", setTest[i].tests[j]);
+ }
+ }
+ delete set;
+ } else {
+ errln("Couldn't open collator with rules %s\n", setTest[i].rules);
+ }
+ delete coll;
+ }
+}
+
+void CollationAPITest::TestUClassID()
+{
+ char id = *((char *)RuleBasedCollator::getStaticClassID());
+ if (id != 0) {
+ errln("Static class id for RuleBasedCollator should be 0");
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *coll
+ = (RuleBasedCollator *)Collator::createInstance(status);
+ if(U_FAILURE(status)) {
+ delete coll;
+ errln("Collator creation failed with %s", u_errorName(status));
+ return;
+ }
+ id = *((char *)coll->getDynamicClassID());
+ if (id != 0) {
+ errln("Dynamic class id for RuleBasedCollator should be 0");
+ }
+ id = *((char *)CollationKey::getStaticClassID());
+ if (id != 0) {
+ errln("Static class id for CollationKey should be 0");
+ }
+ CollationKey *key = new CollationKey();
+ id = *((char *)key->getDynamicClassID());
+ if (id != 0) {
+ errln("Dynamic class id for CollationKey should be 0");
+ }
+ id = *((char *)CollationElementIterator::getStaticClassID());
+ if (id != 0) {
+ errln("Static class id for CollationElementIterator should be 0");
+ }
+ UnicodeString str("testing");
+ CollationElementIterator *iter = coll->createCollationElementIterator(str);
+ id = *((char *)iter->getDynamicClassID());
+ if (id != 0) {
+ errln("Dynamic class id for CollationElementIterator should be 0");
+ }
+ delete key;
+ delete iter;
+ delete coll;
+}
+
+class TestCollator : public Collator
+{
+public:
+ virtual Collator* clone(void) const;
+
+ // dang, markus says we can't use 'using' in ICU. I hate doing this for
+ // deprecated methods...
+
+ // using Collator::compare;
+
+ virtual EComparisonResult compare(const UnicodeString& source,
+ const UnicodeString& target) const
+ {
+ return Collator::compare(source, target);
+ }
+
+ virtual EComparisonResult compare(const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length) const
+ {
+ return Collator::compare(source, target, length);
+ }
+
+ virtual EComparisonResult compare(const UChar* source,
+ int32_t sourceLength,
+ const UChar* target,
+ int32_t targetLength) const
+ {
+ return Collator::compare(source, sourceLength, target, targetLength);
+ }
+
+
+ virtual UCollationResult compare(const UnicodeString& source,
+ const UnicodeString& target,
+ UErrorCode& status) const;
+ virtual UCollationResult compare(const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length,
+ UErrorCode& status) const;
+ virtual UCollationResult compare(const UChar* source,
+ int32_t sourceLength,
+ const UChar* target,
+ int32_t targetLength,
+ UErrorCode& status) const;
+ virtual CollationKey& getCollationKey(const UnicodeString& source,
+ CollationKey& key,
+ UErrorCode& status) const;
+ virtual CollationKey& getCollationKey(const UChar*source,
+ int32_t sourceLength,
+ CollationKey& key,
+ UErrorCode& status) const;
+ virtual int32_t hashCode(void) const;
+ virtual const Locale getLocale(ULocDataLocaleType type,
+ UErrorCode& status) const;
+ virtual ECollationStrength getStrength(void) const;
+ virtual void setStrength(ECollationStrength newStrength);
+ virtual UClassID getDynamicClassID(void) const;
+ virtual void getVersion(UVersionInfo info) const;
+ virtual void setAttribute(UColAttribute attr, UColAttributeValue value,
+ UErrorCode &status);
+ virtual UColAttributeValue getAttribute(UColAttribute attr,
+ UErrorCode &status);
+ virtual uint32_t setVariableTop(const UChar *varTop, int32_t len,
+ UErrorCode &status);
+ virtual uint32_t setVariableTop(const UnicodeString varTop,
+ UErrorCode &status);
+ virtual void setVariableTop(const uint32_t varTop, UErrorCode &status);
+ virtual uint32_t getVariableTop(UErrorCode &status) const;
+ virtual Collator* safeClone(void);
+ virtual int32_t getSortKey(const UnicodeString& source,
+ uint8_t* result,
+ int32_t resultLength) const;
+ virtual int32_t getSortKey(const UChar*source, int32_t sourceLength,
+ uint8_t*result, int32_t resultLength) const;
+ virtual UnicodeSet *getTailoredSet(UErrorCode &status) const;
+ virtual UBool operator!=(const Collator& other) const;
+ virtual void setLocales(const Locale& requestedLocale, const Locale& validLocale);
+ TestCollator() : Collator() {};
+ TestCollator(UCollationStrength collationStrength,
+ UNormalizationMode decompositionMode) : Collator(collationStrength, decompositionMode) {};
+};
+
+inline UBool TestCollator::operator!=(const Collator& other) const {
+ return Collator::operator!=(other);
+}
+
+#define returnEComparisonResult(data) \
+ if (data < 0) return Collator::LESS;\
+ if (data > 0) return Collator::GREATER;\
+ return Collator::EQUAL;
+
+Collator* TestCollator::clone() const
+{
+ return new TestCollator();
+}
+
+UCollationResult TestCollator::compare(const UnicodeString& source,
+ const UnicodeString& target,
+ UErrorCode& status) const
+{
+ if(U_SUCCESS(status)) {
+ return UCollationResult(source.compare(target));
+ } else {
+ return UCOL_EQUAL;
+ }
+}
+
+UCollationResult TestCollator::compare(const UnicodeString& source,
+ const UnicodeString& target,
+ int32_t length,
+ UErrorCode& status) const
+{
+ if(U_SUCCESS(status)) {
+ return UCollationResult(source.compare(0, length, target));
+ } else {
+ return UCOL_EQUAL;
+ }
+}
+
+UCollationResult TestCollator::compare(const UChar* source,
+ int32_t sourceLength,
+ const UChar* target,
+ int32_t targetLength,
+ UErrorCode& status) const
+{
+ UnicodeString s(source, sourceLength);
+ UnicodeString t(target, targetLength);
+ return compare(s, t, status);
+}
+
+CollationKey& TestCollator::getCollationKey(const UnicodeString& source,
+ CollationKey& key,
+ UErrorCode& status) const
+{
+ char temp[100];
+ int length = 100;
+ length = source.extract(temp, length, NULL, status);
+ temp[length] = 0;
+ CollationKey tempkey((uint8_t*)temp, length);
+ key = tempkey;
+ return key;
+}
+
+CollationKey& TestCollator::getCollationKey(const UChar*source,
+ int32_t sourceLength,
+ CollationKey& key,
+ UErrorCode& status) const
+{
+ //s tack allocation used since collationkey does not keep the unicodestring
+ UnicodeString str(source, sourceLength);
+ return getCollationKey(str, key, status);
+}
+
+int32_t TestCollator::getSortKey(const UnicodeString& source, uint8_t* result,
+ int32_t resultLength) const
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t length = source.extract((char *)result, resultLength, NULL,
+ status);
+ result[length] = 0;
+ return length;
+}
+
+int32_t TestCollator::getSortKey(const UChar*source, int32_t sourceLength,
+ uint8_t*result, int32_t resultLength) const
+{
+ UnicodeString str(source, sourceLength);
+ return getSortKey(str, result, resultLength);
+}
+
+int32_t TestCollator::hashCode() const
+{
+ return 0;
+}
+
+const Locale TestCollator::getLocale(ULocDataLocaleType type,
+ UErrorCode& status) const
+{
+ // api not used, this is to make the compiler happy
+ if (U_FAILURE(status)) {
+ type = ULOC_DATA_LOCALE_TYPE_LIMIT;
+ }
+ return NULL;
+}
+
+Collator::ECollationStrength TestCollator::getStrength() const
+{
+ return TERTIARY;
+}
+
+void TestCollator::setStrength(Collator::ECollationStrength newStrength)
+{
+ // api not used, this is to make the compiler happy
+ newStrength = TERTIARY;
+}
+
+UClassID TestCollator::getDynamicClassID(void) const
+{
+ return 0;
+}
+
+void TestCollator::getVersion(UVersionInfo info) const
+{
+ // api not used, this is to make the compiler happy
+ memset(info, 0, U_MAX_VERSION_LENGTH);
+}
+
+void TestCollator::setAttribute(UColAttribute attr, UColAttributeValue value,
+ UErrorCode &status)
+{
+ // api not used, this is to make the compiler happy
+ if (U_FAILURE(status)) {
+ attr = UCOL_ATTRIBUTE_COUNT;
+ value = UCOL_OFF;
+ }
+}
+
+UColAttributeValue TestCollator::getAttribute(UColAttribute attr,
+ UErrorCode &status)
+{
+ // api not used, this is to make the compiler happy
+ if (U_FAILURE(status) || attr == UCOL_ATTRIBUTE_COUNT) {
+ return UCOL_OFF;
+ }
+ return UCOL_DEFAULT;
+}
+
+uint32_t TestCollator::setVariableTop(const UChar *varTop, int32_t len,
+ UErrorCode &status)
+{
+ // api not used, this is to make the compiler happy
+ if (U_SUCCESS(status) && (varTop == 0 || len < -1)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return 0;
+}
+
+uint32_t TestCollator::setVariableTop(const UnicodeString varTop,
+ UErrorCode &status)
+{
+ // api not used, this is to make the compiler happy
+ if (U_SUCCESS(status) && varTop.length() == 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return 0;
+}
+
+void TestCollator::setVariableTop(const uint32_t varTop, UErrorCode &status)
+{
+ // api not used, this is to make the compiler happy
+ if (U_SUCCESS(status) && varTop == 0) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+}
+
+uint32_t TestCollator::getVariableTop(UErrorCode &status) const
+{
+
+ // api not used, this is to make the compiler happy
+ if (U_SUCCESS(status)) {
+ return 0;
+ }
+ return (uint32_t)(0xFFFFFFFFu);
+}
+
+Collator* TestCollator::safeClone(void)
+{
+ return new TestCollator();
+}
+
+UnicodeSet * TestCollator::getTailoredSet(UErrorCode &status) const
+{
+ return Collator::getTailoredSet(status);
+}
+
+void TestCollator::setLocales(const Locale& requestedLocale, const Locale& validLocale)
+{
+ Collator::setLocales(requestedLocale, validLocale);
+}
+
+
+void CollationAPITest::TestSubclass()
+{
+ TestCollator col1;
+ TestCollator col2;
+ doAssert(col1 != col2, "2 instance of TestCollator should be different");
+ if (col1.hashCode() != col2.hashCode()) {
+ errln("Every TestCollator has the same hashcode");
+ }
+ UnicodeString abc("abc", 3);
+ UnicodeString bcd("bcd", 3);
+ if (col1.compare(abc, bcd) != abc.compare(bcd)) {
+ errln("TestCollator compare should be the same as the default "
+ "string comparison");
+ }
+ CollationKey key;
+ UErrorCode status = U_ZERO_ERROR;
+ col1.getCollationKey(abc, key, status);
+ int32_t length = 0;
+ const char* bytes = (const char *)key.getByteArray(length);
+ UnicodeString keyarray(bytes, length, NULL, status);
+ if (abc != keyarray) {
+ errln("TestCollator collationkey API is returning wrong values");
+ }
+
+ UnicodeSet expectedset(0, 0x10FFFF);
+ UnicodeSet *defaultset = col1.getTailoredSet(status);
+ if (!defaultset->containsAll(expectedset)
+ || !expectedset.containsAll(*defaultset)) {
+ errln("Error: expected default tailoring to be 0 to 0x10ffff");
+ }
+ delete defaultset;
+
+ // use base class implementation
+ Locale loc1 = Locale::getGermany();
+ Locale loc2 = Locale::getFrance();
+ col1.setLocales(loc1, loc2); // default implementation has no effect
+
+ UnicodeString displayName;
+ col1.getDisplayName(loc1, loc2, displayName); // de_DE collator in fr_FR locale
+
+ TestCollator col3(UCOL_TERTIARY, UNORM_NONE);
+ UnicodeString a("a");
+ UnicodeString b("b");
+ Collator::EComparisonResult result = Collator::EComparisonResult(a.compare(b));
+ if(col1.compare(a, b) != result) {
+ errln("Collator doesn't give default result");
+ }
+ if(col1.compare(a, b, 1) != result) {
+ errln("Collator doesn't give default result");
+ }
+ if(col1.compare(a.getBuffer(), a.length(), b.getBuffer(), b.length()) != result) {
+ errln("Collator doesn't give default result");
+ }
+}
+
+void CollationAPITest::TestNULLCharTailoring()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UChar buf[256] = {0};
+ int32_t len = u_unescape("&a < '\\u0000'", buf, 256);
+ UnicodeString first((UChar)0x0061);
+ UnicodeString second((UChar)0);
+ RuleBasedCollator *coll = new RuleBasedCollator(UnicodeString(buf, len), status);
+ if(U_FAILURE(status)) {
+ errln("Failed to open collator");
+ }
+ UCollationResult res = coll->compare(first, second, status);
+ if(res != UCOL_LESS) {
+ errln("a should be less then NULL after tailoring");
+ }
+ delete coll;
+}
+
+void CollationAPITest::TestClone() {
+ logln("\ninit c0");
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator* c0 = (RuleBasedCollator*)Collator::createInstance(status);
+
+ if (U_FAILURE(status)) {
+ errln("Collator::CreateInstance(status) failed with %s", u_errorName(status));
+ return;
+ }
+
+ c0->setStrength(Collator::TERTIARY);
+ dump("c0", c0, status);
+
+ logln("\ninit c1");
+ RuleBasedCollator* c1 = (RuleBasedCollator*)Collator::createInstance(status);
+ c1->setStrength(Collator::TERTIARY);
+ UColAttributeValue val = c1->getAttribute(UCOL_CASE_FIRST, status);
+ if(val == UCOL_LOWER_FIRST){
+ c1->setAttribute(UCOL_CASE_FIRST, UCOL_UPPER_FIRST, status);
+ }else{
+ c1->setAttribute(UCOL_CASE_FIRST, UCOL_LOWER_FIRST, status);
+ }
+ dump("c0", c0, status);
+ dump("c1", c1, status);
+
+ logln("\ninit c2");
+ RuleBasedCollator* c2 = (RuleBasedCollator*)c1->clone();
+ val = c2->getAttribute(UCOL_CASE_FIRST, status);
+ if(val == UCOL_LOWER_FIRST){
+ c2->setAttribute(UCOL_CASE_FIRST, UCOL_UPPER_FIRST, status);
+ }else{
+ c2->setAttribute(UCOL_CASE_FIRST, UCOL_LOWER_FIRST, status);
+ }
+ if(U_FAILURE(status)){
+ errln("set and get attributes of collator failed. %s\n", u_errorName(status));
+ return;
+ }
+ dump("c0", c0, status);
+ dump("c1", c1, status);
+ dump("c2", c2, status);
+ if(*c1 == *c2){
+ errln("The cloned objects refer to same data");
+ }
+ delete c0;
+ delete c1;
+ delete c2;
+}
+
+ void CollationAPITest::dump(UnicodeString msg, RuleBasedCollator* c, UErrorCode& status) {
+ const char* bigone = "One";
+ const char* littleone = "one";
+
+ logln(msg + " " + c->compare(bigone, littleone) +
+ " s: " + c->getStrength() +
+ " u: " + c->getAttribute(UCOL_CASE_FIRST, status));
+}
+void CollationAPITest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par */)
+{
+ if (exec) logln("TestSuite CollationAPITest: ");
+ switch (index) {
+ case 0: name = "TestProperty"; if (exec) TestProperty(/* par */); break;
+ case 1: name = "TestOperators"; if (exec) TestOperators(/* par */); break;
+ case 2: name = "TestDuplicate"; if (exec) TestDuplicate(/* par */); break;
+ case 3: name = "TestCompare"; if (exec) TestCompare(/* par */); break;
+ case 4: name = "TestHashCode"; if (exec) TestHashCode(/* par */); break;
+ case 5: name = "TestCollationKey"; if (exec) TestCollationKey(/* par */); break;
+ case 6: name = "TestElemIter"; if (exec) TestElemIter(/* par */); break;
+ case 7: name = "TestGetAll"; if (exec) TestGetAll(/* par */); break;
+ case 8: name = "TestRuleBasedColl"; if (exec) TestRuleBasedColl(/* par */); break;
+ case 9: name = "TestDecomposition"; if (exec) TestDecomposition(/* par */); break;
+ case 10: name = "TestSafeClone"; if (exec) TestSafeClone(/* par */); break;
+ case 11: name = "TestSortKey"; if (exec) TestSortKey(); break;
+ case 12: name = "TestMaxExpansion"; if (exec) TestMaxExpansion(); break;
+ case 13: name = "TestDisplayName"; if (exec) TestDisplayName(); break;
+ case 14: name = "TestAttribute"; if (exec) TestAttribute(); break;
+ case 15: name = "TestVariableTopSetting"; if (exec) TestVariableTopSetting(); break;
+ case 16: name = "TestRules"; if (exec) TestRules(); break;
+ case 17: name = "TestGetLocale"; if (exec) TestGetLocale(); break;
+ case 18: name = "TestBounds"; if (exec) TestBounds(); break;
+ case 19: name = "TestGetTailoredSet"; if (exec) TestGetTailoredSet(); break;
+ case 20: name = "TestUClassID"; if (exec) TestUClassID(); break;
+ case 21: name = "TestSubclass"; if (exec) TestSubclass(); break;
+ case 22: name = "TestNULLCharTailoring"; if (exec) TestNULLCharTailoring(); break;
+ case 23: name = "TestClone"; if (exec) TestClone(); break;
+ default: name = ""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/apicoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/apicoll.h
new file mode 100644
index 00000000000..f3a4d2a7fda
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/apicoll.h
@@ -0,0 +1,179 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+/**
+ * CollationAPITest is a third level test class. This test performs API
+ * related tests for the Collation framework.
+ */
+
+#ifndef _APICOLL
+#define _APICOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/tblcoll.h"
+#include "tscoll.h"
+
+class CollationAPITest: public IntlTestCollator {
+public:
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par = NULL */);
+ void doAssert(UBool condition, const char *message);
+
+ /**
+ * This tests the properties of a collator object.
+ * - constructor/destructor
+ * - factory method createInstance
+ * - compare and getCollationKey
+ * - get/set decomposition mode and comparison level
+ * - displayable name in the desired locale
+ */
+ void TestProperty(/* char* par */);
+
+ /**
+ * This tests the RuleBasedCollator
+ * - constructor/destructor
+ * - getRules
+ */
+ void TestRuleBasedColl(/* char* par */);
+
+ /**
+ * This tests the RuleBasedCollator
+ * - getRules
+ */
+ void TestRules(/* char* par */);
+
+ /**
+ * Tests decomposition setting
+ */
+ void TestDecomposition();
+
+ /**
+ * SafeClone test
+ */
+ void TestSafeClone();
+
+ /**
+ * This tests the properties of a rule based collator object.
+ * - constructor/destructor
+ * - == and != operators
+ * - clone and copy
+ * - collation rules access
+ */
+ void TestOperators(/* char* par */);
+
+ /**
+ * This tests the duplication of a collator object.
+ */
+ void TestDuplicate(/* char* par */);
+
+ /**
+ * This tests the comparison convenience methods of a collator object.
+ * - greater than
+ * - greater than or equal to
+ * - equal to
+ */
+ void TestCompare(/* char* par */);
+
+ /**
+ * This tests the hashCode method of a collator object.
+ */
+ void TestHashCode(/* char* par */);
+
+ /**
+ * This tests the collation key related APIs.
+ * - constructor/destructor
+ * - Collator::getCollationKey
+ * - == and != operators
+ * - comparison between collation keys
+ * - creating collation key with a byte array and vice versa
+ */
+ void TestCollationKey(/* char* par */);
+
+ /**
+ * This tests the CollationElementIterator related APIs.
+ * - creation of a CollationElementIterator object
+ * - == and != operators
+ * - iterating forward
+ * - reseting the iterator index
+ * - requesting the order properties(primary, secondary or tertiary)
+ */
+ void TestElemIter(/* char* par */);
+
+ /**
+ * This tests the list the all available locales.
+ */
+ void TestGetAll(/* char* par */);
+
+ /**
+ * This tests the sort keys generated by collator
+ */
+ void TestSortKey();
+
+ /**
+ * This tests getMaxExpansion
+ */
+ void TestMaxExpansion();
+
+ /**
+ * Tests the retrieval of names given a locale
+ */
+ void TestDisplayName();
+
+ /**
+ * Tests the collator attributes
+ */
+ void TestAttribute();
+
+ /**
+ * Tests the setters and getters of variable top
+ */
+ void TestVariableTopSetting();
+
+ /**
+ * Tests GetLocale for a Collator
+ */
+ void TestGetLocale();
+
+ /**
+ * Tests bounds API
+ */
+ void TestBounds();
+
+ /**
+ * Tests getTailoredSet API
+ */
+ void TestGetTailoredSet();
+
+ /**
+ * Tests the subclassability
+ */
+ void TestSubclass();
+
+ /**
+ * Tests the dynamic and static ids of collation classes
+ */
+ void TestUClassID();
+
+ /**
+ * Test NULL
+ */
+ void TestNULLCharTailoring();
+
+ void TestClone();
+private:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ void dump(UnicodeString msg, RuleBasedCollator* c, UErrorCode& status);
+
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/astrotst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/astrotst.cpp
new file mode 100644
index 00000000000..ba7b5711396
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/astrotst.cpp
@@ -0,0 +1,436 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1996-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/* Test CalendarAstronomer for C++ */
+
+#include "unicode/utypes.h"
+#include "string.h"
+#include "unicode/locid.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "astro.h"
+#include "astrotst.h"
+#include "gregoimp.h" // for Math
+#include "unicode/simpletz.h"
+
+
+static const double DAY_MS = 24.*60.*60.*1000.;
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
+
+AstroTest::AstroTest(): astro(NULL), gc(NULL) {
+}
+
+void AstroTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite AstroTest");
+ switch (index) {
+ // CASE(0,FooTest);
+ CASE(0,TestSolarLongitude);
+ CASE(1,TestLunarPosition);
+ CASE(2,TestCoordinates);
+ CASE(3,TestCoverage);
+ CASE(4,TestSunriseTimes);
+ CASE(5,TestBasics);
+ default: name = ""; break;
+ }
+}
+
+#undef CASE
+
+#define ASSERT_OK(x) if(U_FAILURE(x)) { errln("%s:%d: %s\n", __FILE__, __LINE__, u_errorName(x)); return; }
+
+
+void AstroTest::initAstro(UErrorCode &status) {
+ if(U_FAILURE(status)) return;
+
+ if((astro != NULL) || (gc != NULL)) {
+ errln("Err: initAstro() called twice!");
+ closeAstro(status);
+ if(U_SUCCESS(status)) {
+ status = U_INTERNAL_PROGRAM_ERROR;
+ }
+ }
+
+ if(U_FAILURE(status)) return;
+
+ astro = new CalendarAstronomer();
+ gc = Calendar::createInstance(TimeZone::getGMT()->clone(), status);
+}
+
+void AstroTest::closeAstro(UErrorCode &/*status*/) {
+ if(astro != NULL) {
+ delete astro;
+ astro = NULL;
+ }
+ if(gc != NULL) {
+ delete gc;
+ gc = NULL;
+ }
+}
+
+void AstroTest::TestSolarLongitude(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ initAstro(status);
+ ASSERT_OK(status);
+
+ struct {
+ int32_t d[5]; double f ;
+ } tests[] = {
+ { { 1980, 7, 27, 0, 00 }, 124.114347 },
+ { { 1988, 7, 27, 00, 00 }, 124.187732 }
+ };
+
+ logln("");
+ for (uint32_t i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
+ gc->clear();
+ gc->set(tests[i].d[0], tests[i].d[1]-1, tests[i].d[2], tests[i].d[3], tests[i].d[4]);
+
+ astro->setDate(gc->getTime(status));
+
+ double longitude = astro->getSunLongitude();
+ //longitude = 0;
+ CalendarAstronomer::Equatorial result;
+ astro->getSunPosition(result);
+ logln((UnicodeString)"Sun position is " + result.toString() + (UnicodeString)"; " /* + result.toHmsString()*/ + " Sun longitude is " + longitude );
+ }
+ closeAstro(status);
+ ASSERT_OK(status);
+}
+
+
+
+void AstroTest::TestLunarPosition(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ initAstro(status);
+ ASSERT_OK(status);
+
+ static const double tests[][7] = {
+ { 1979, 2, 26, 16, 00, 0, 0 }
+ };
+ logln("");
+
+ for (int32_t i = 0; i < (int32_t)(sizeof(tests)/sizeof(tests[0])); i++) {
+ gc->clear();
+ gc->set((int32_t)tests[i][0], (int32_t)tests[i][1]-1, (int32_t)tests[i][2], (int32_t)tests[i][3], (int32_t)tests[i][4]);
+ astro->setDate(gc->getTime(status));
+
+ const CalendarAstronomer::Equatorial& result = astro->getMoonPosition();
+ logln((UnicodeString)"Moon position is " + result.toString() + (UnicodeString)"; " /* + result->toHmsString()*/);
+ }
+
+ closeAstro(status);
+ ASSERT_OK(status);
+}
+
+
+
+void AstroTest::TestCoordinates(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ initAstro(status);
+ ASSERT_OK(status);
+
+ CalendarAstronomer::Equatorial result;
+ astro->eclipticToEquatorial(result, 139.686111 * CalendarAstronomer::PI / 180.0, 4.875278* CalendarAstronomer::PI / 180.0);
+ logln((UnicodeString)"result is " + result.toString() + (UnicodeString)"; " /* + result.toHmsString()*/ );
+ closeAstro(status);
+ ASSERT_OK(status);
+}
+
+
+
+void AstroTest::TestCoverage(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ initAstro(status);
+ ASSERT_OK(status);
+ GregorianCalendar *cal = new GregorianCalendar(1958, UCAL_AUGUST, 15,status);
+ UDate then = cal->getTime(status);
+ CalendarAstronomer *myastro = new CalendarAstronomer(then);
+ ASSERT_OK(status);
+
+ //Latitude: 34 degrees 05' North
+ //Longitude: 118 degrees 22' West
+ double laLat = 34 + 5./60, laLong = 360 - (118 + 22./60);
+ CalendarAstronomer *myastro2 = new CalendarAstronomer(laLong, laLat);
+
+ double eclLat = laLat * CalendarAstronomer::PI / 360;
+ double eclLong = laLong * CalendarAstronomer::PI / 360;
+
+ CalendarAstronomer::Ecliptic ecl(eclLat, eclLong);
+ CalendarAstronomer::Equatorial eq;
+ CalendarAstronomer::Horizon hor;
+
+ logln("ecliptic: " + ecl.toString());
+ CalendarAstronomer *myastro3 = new CalendarAstronomer();
+ myastro3->setJulianDay((4713 + 2000) * 365.25);
+
+ CalendarAstronomer *astronomers[] = {
+ myastro, myastro2, myastro3, myastro2 // check cache
+ };
+
+ for (uint32_t i = 0; i < sizeof(astronomers)/sizeof(astronomers[0]); ++i) {
+ CalendarAstronomer *anAstro = astronomers[i];
+
+ //logln("astro: " + astro);
+ logln((UnicodeString)" date: " + anAstro->getTime());
+ logln((UnicodeString)" cent: " + anAstro->getJulianCentury());
+ logln((UnicodeString)" gw sidereal: " + anAstro->getGreenwichSidereal());
+ logln((UnicodeString)" loc sidereal: " + anAstro->getLocalSidereal());
+ logln((UnicodeString)" equ ecl: " + (anAstro->eclipticToEquatorial(eq,ecl)).toString());
+ logln((UnicodeString)" equ long: " + (anAstro->eclipticToEquatorial(eq, eclLong)).toString());
+ logln((UnicodeString)" horiz: " + (anAstro->eclipticToHorizon(hor, eclLong)).toString());
+ logln((UnicodeString)" sunrise: " + (anAstro->getSunRiseSet(TRUE)));
+ logln((UnicodeString)" sunset: " + (anAstro->getSunRiseSet(FALSE)));
+ logln((UnicodeString)" moon phase: " + anAstro->getMoonPhase());
+ logln((UnicodeString)" moonrise: " + (anAstro->getMoonRiseSet(TRUE)));
+ logln((UnicodeString)" moonset: " + (anAstro->getMoonRiseSet(FALSE)));
+ logln((UnicodeString)" prev summer solstice: " + (anAstro->getSunTime(CalendarAstronomer::SUMMER_SOLSTICE(), FALSE)));
+ logln((UnicodeString)" next summer solstice: " + (anAstro->getSunTime(CalendarAstronomer::SUMMER_SOLSTICE(), TRUE)));
+ logln((UnicodeString)" prev full moon: " + (anAstro->getMoonTime(CalendarAstronomer::FULL_MOON(), FALSE)));
+ logln((UnicodeString)" next full moon: " + (anAstro->getMoonTime(CalendarAstronomer::FULL_MOON(), TRUE)));
+ }
+
+ delete myastro2;
+ delete myastro3;
+ delete myastro;
+ delete cal;
+
+ closeAstro(status);
+ ASSERT_OK(status);
+}
+
+
+
+void AstroTest::TestSunriseTimes(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ initAstro(status);
+ ASSERT_OK(status);
+
+ // logln("Sunrise/Sunset times for San Jose, California, USA");
+ // CalendarAstronomer *astro2 = new CalendarAstronomer(-121.55, 37.20);
+ // TimeZone *tz = TimeZone::createTimeZone("America/Los_Angeles");
+
+ // We'll use a table generated by the UNSO website as our reference
+ // From: http://aa.usno.navy.mil/
+ //-Location: W079 25, N43 40
+ //-Rise and Set for the Sun for 2001
+ //-Zone: 4h West of Greenwich
+ int32_t USNO[] = {
+ 6,59, 19,45,
+ 6,57, 19,46,
+ 6,56, 19,47,
+ 6,54, 19,48,
+ 6,52, 19,49,
+ 6,50, 19,51,
+ 6,48, 19,52,
+ 6,47, 19,53,
+ 6,45, 19,54,
+ 6,43, 19,55,
+ 6,42, 19,57,
+ 6,40, 19,58,
+ 6,38, 19,59,
+ 6,36, 20, 0,
+ 6,35, 20, 1,
+ 6,33, 20, 3,
+ 6,31, 20, 4,
+ 6,30, 20, 5,
+ 6,28, 20, 6,
+ 6,27, 20, 7,
+ 6,25, 20, 8,
+ 6,23, 20,10,
+ 6,22, 20,11,
+ 6,20, 20,12,
+ 6,19, 20,13,
+ 6,17, 20,14,
+ 6,16, 20,16,
+ 6,14, 20,17,
+ 6,13, 20,18,
+ 6,11, 20,19,
+ };
+
+ logln("Sunrise/Sunset times for Toronto, Canada");
+ // long = 79 25", lat = 43 40"
+ CalendarAstronomer *astro3 = new CalendarAstronomer(-(79+25/60), 43+40/60);
+
+ // As of ICU4J 2.8 the ICU4J time zones implement pass-through
+ // to the underlying JDK. Because of variation in the
+ // underlying JDKs, we have to use a fixed-offset
+ // SimpleTimeZone to get consistent behavior between JDKs.
+ // The offset we want is [-18000000, 3600000] (raw, dst).
+ // [aliu 10/15/03]
+
+ // TimeZone tz = TimeZone.getTimeZone("America/Montreal");
+ TimeZone *tz = new SimpleTimeZone(-18000000 + 3600000, "Montreal(FIXED)");
+
+ GregorianCalendar *cal = new GregorianCalendar(tz->clone(), Locale::getUS(), status);
+ GregorianCalendar *cal2 = new GregorianCalendar(tz->clone(), Locale::getUS(), status);
+ cal->clear();
+ cal->set(UCAL_YEAR, 2001);
+ cal->set(UCAL_MONTH, UCAL_APRIL);
+ cal->set(UCAL_DAY_OF_MONTH, 1);
+ cal->set(UCAL_HOUR_OF_DAY, 12); // must be near local noon for getSunRiseSet to work
+
+ DateFormat *df_t = DateFormat::createTimeInstance(DateFormat::MEDIUM,Locale::getUS());
+ DateFormat *df_d = DateFormat::createDateInstance(DateFormat::MEDIUM,Locale::getUS());
+ DateFormat *df_dt = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::MEDIUM, Locale::getUS());
+ if(!df_t || !df_d || !df_dt) {
+ errln("couldn't create dateformats.");
+ return;
+ }
+ df_t->adoptTimeZone(tz->clone());
+ df_d->adoptTimeZone(tz->clone());
+ df_dt->adoptTimeZone(tz->clone());
+
+ for (int32_t i=0; i < 30; i++) {
+ logln("setDate\n");
+ astro3->setDate(cal->getTime(status));
+ logln("getRiseSet(TRUE)\n");
+ UDate sunrise = astro3->getSunRiseSet(TRUE);
+ logln("getRiseSet(FALSE)\n");
+ UDate sunset = astro3->getSunRiseSet(FALSE);
+ logln("end of getRiseSet\n");
+
+ cal2->setTime(cal->getTime(status), status);
+ cal2->set(UCAL_SECOND, 0);
+ cal2->set(UCAL_MILLISECOND, 0);
+
+ cal2->set(UCAL_HOUR_OF_DAY, USNO[4*i+0]);
+ cal2->set(UCAL_MINUTE, USNO[4*i+1]);
+ UDate exprise = cal2->getTime(status);
+ cal2->set(UCAL_HOUR_OF_DAY, USNO[4*i+2]);
+ cal2->set(UCAL_MINUTE, USNO[4*i+3]);
+ UDate expset = cal2->getTime(status);
+ // Compute delta of what we got to the USNO data, in seconds
+ int32_t deltarise = (int32_t)uprv_fabs((sunrise - exprise) / 1000);
+ int32_t deltaset = (int32_t)uprv_fabs((sunset - expset) / 1000);
+
+ // Allow a deviation of 0..MAX_DEV seconds
+ // It would be nice to get down to 60 seconds, but at this
+ // point that appears to be impossible without a redo of the
+ // algorithm using something more advanced than Duffett-Smith.
+ int32_t MAX_DEV = 180;
+ UnicodeString s1, s2, s3, s4, s5;
+ if (deltarise > MAX_DEV || deltaset > MAX_DEV) {
+ if (deltarise > MAX_DEV) {
+ errln("FAIL: (rise) " + df_d->format(cal->getTime(status),s1) +
+ ", Sunrise: " + df_dt->format(sunrise, s2) +
+ " (USNO " + df_t->format(exprise,s3) +
+ " d=" + deltarise + "s)");
+ } else {
+ logln(df_d->format(cal->getTime(status),s1) +
+ ", Sunrise: " + df_dt->format(sunrise,s2) +
+ " (USNO " + df_t->format(exprise,s3) + ")");
+ }
+ s1.remove(); s2.remove(); s3.remove(); s4.remove(); s5.remove();
+ if (deltaset > MAX_DEV) {
+ errln("FAIL: (set) " + df_d->format(cal->getTime(status),s1) +
+ ", Sunset: " + df_dt->format(sunset,s2) +
+ " (USNO " + df_t->format(expset,s3) +
+ " d=" + deltaset + "s)");
+ } else {
+ logln(df_d->format(cal->getTime(status),s1) +
+ ", Sunset: " + df_dt->format(sunset,s2) +
+ " (USNO " + df_t->format(expset,s3) + ")");
+ }
+ } else {
+ logln(df_d->format(cal->getTime(status),s1) +
+ ", Sunrise: " + df_dt->format(sunrise,s2) +
+ " (USNO " + df_t->format(exprise,s3) + ")" +
+ ", Sunset: " + df_dt->format(sunset,s4) +
+ " (USNO " + df_t->format(expset,s5) + ")");
+ }
+ cal->add(UCAL_DATE, 1, status);
+ }
+
+ // CalendarAstronomer a = new CalendarAstronomer(-(71+5/60), 42+37/60);
+ // cal.clear();
+ // cal.set(cal.YEAR, 1986);
+ // cal.set(cal.MONTH, cal.MARCH);
+ // cal.set(cal.DATE, 10);
+ // cal.set(cal.YEAR, 1988);
+ // cal.set(cal.MONTH, cal.JULY);
+ // cal.set(cal.DATE, 27);
+ // a.setDate(cal.getTime());
+ // long r = a.getSunRiseSet2(true);
+ delete astro3;
+ delete tz;
+ delete cal;
+ delete cal2;
+ delete df_t;
+ delete df_d;
+ delete df_dt;
+ closeAstro(status);
+ ASSERT_OK(status);
+}
+
+
+
+void AstroTest::TestBasics(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ initAstro(status);
+ ASSERT_OK(status);
+
+ // Check that our JD computation is the same as the book's (p. 88)
+ GregorianCalendar *cal3 = new GregorianCalendar(TimeZone::getGMT()->clone(), Locale::getUS(), status);
+ DateFormat *d3 = DateFormat::createDateTimeInstance(DateFormat::MEDIUM,DateFormat::MEDIUM,Locale::getUS());
+ d3->setTimeZone(*TimeZone::getGMT());
+ cal3->clear();
+ cal3->set(UCAL_YEAR, 1980);
+ cal3->set(UCAL_MONTH, UCAL_JULY);
+ cal3->set(UCAL_DATE, 2);
+ logln("cal3[a]=%.1lf, d=%d\n", cal3->getTime(status), cal3->get(UCAL_JULIAN_DAY,status));
+ {
+ UnicodeString s;
+ logln(UnicodeString("cal3[a] = ") + d3->format(cal3->getTime(status),s));
+ }
+ cal3->clear();
+ cal3->set(UCAL_YEAR, 1980);
+ cal3->set(UCAL_MONTH, UCAL_JULY);
+ cal3->set(UCAL_DATE, 27);
+ logln("cal3=%.1lf, d=%d\n", cal3->getTime(status), cal3->get(UCAL_JULIAN_DAY,status));
+
+ ASSERT_OK(status);
+ {
+ UnicodeString s;
+ logln(UnicodeString("cal3 = ") + d3->format(cal3->getTime(status),s));
+ }
+ astro->setTime(cal3->getTime(status));
+ double jd = astro->getJulianDay() - 2447891.5;
+ double exp = -3444.;
+ if (jd == exp) {
+ UnicodeString s;
+ logln(d3->format(cal3->getTime(status),s) + " => " + jd);
+ } else {
+ UnicodeString s;
+ errln("FAIL: " + d3->format(cal3->getTime(status), s) + " => " + jd +
+ ", expected " + exp);
+ }
+
+ // cal3.clear();
+ // cal3.set(cal3.YEAR, 1990);
+ // cal3.set(cal3.MONTH, Calendar.JANUARY);
+ // cal3.set(cal3.DATE, 1);
+ // cal3.add(cal3.DATE, -1);
+ // astro.setDate(cal3.getTime());
+ // astro.foo();
+
+ delete cal3;
+ delete d3;
+ ASSERT_OK(status);
+ closeAstro(status);
+ ASSERT_OK(status);
+
+}
+
+
+// TODO: try finding next new moon after 07/28/1984 16:00 GMT
+
+
+#endif
+
+
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/astrotst.h b/Build/source/libs/icu/icu-xetex/test/intltest/astrotst.h
new file mode 100644
index 00000000000..2ca062cf9ea
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/astrotst.h
@@ -0,0 +1,49 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef __AstroTest__
+#define __AstroTest__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "unicode/smpdtfmt.h"
+#include "astro.h"
+#include "caltztst.h"
+
+class AstroTest: public CalendarTimeZoneTest {
+public:
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+ AstroTest();
+
+ void TestSolarLongitude(void);
+
+ void TestLunarPosition(void);
+
+ void TestCoordinates(void);
+
+ void TestCoverage(void);
+
+ void TestSunriseTimes(void);
+
+ void TestBasics(void);
+ private:
+ void initAstro(UErrorCode&);
+ void closeAstro(UErrorCode&);
+
+ CalendarAstronomer *astro;
+ Calendar *gc;
+
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __AstroTest__
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/calcasts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/calcasts.cpp
new file mode 100644
index 00000000000..5246808b194
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/calcasts.cpp
@@ -0,0 +1,386 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ********************************************************************
+ * Calendar Case Test is a type of CalendarTest which compares the
+ * behavior of a calendar to a certain set of 'test cases', involving
+ * conversion between julian-day to fields and vice versa.
+ ********************************************************************/
+
+#include "calcasts.h"
+
+#if !UCONFIG_NO_FORMATTING
+// ======= 'Main' ===========================
+
+#include "hebrwcal.h" // for Eras
+#include "indiancal.h"
+#include "unicode/datefmt.h"
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
+
+
+void CalendarCaseTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CalendarCaseTest");
+ switch (index) {
+ CASE(0,IslamicCivil);
+ CASE(1,Hebrew);
+ CASE(2,Indian);
+ default: name = ""; break;
+ }
+}
+
+#undef CASE
+
+// ======= Utility functions =================
+
+void CalendarCaseTest::doTestCases(const TestCase *cases, Calendar *cal) {
+ static const int32_t ONE_SECOND = 1000;
+ static const int32_t ONE_MINUTE = 60*ONE_SECOND;
+ static const int32_t ONE_HOUR = 60*ONE_MINUTE;
+ static const double ONE_DAY = 24*ONE_HOUR;
+ static const double JULIAN_EPOCH = -210866760000000.; // 1/1/4713 BC 12:00
+ int32_t i;
+ UErrorCode status = U_ZERO_ERROR;
+ cal->adoptTimeZone(TimeZone::getGMT()->clone());
+ for(i=0;cases[i].era>=0;i++) {
+ UDate t = (JULIAN_EPOCH+(ONE_DAY*cases[i].julian));
+
+ logln("Test case %d: julianday%f -> date %f\n", i, cases[i].julian, t);
+
+ // Millis -> fields
+ cal->setTime(t, status);
+
+ logln(calToStr(*cal));
+
+ checkField(cal, UCAL_ERA, cases[i].era, status);
+ checkField(cal, UCAL_YEAR, cases[i].year,status);
+ checkField(cal, UCAL_MONTH, cases[i].month - 1,status);
+ checkField(cal, UCAL_DATE, cases[i].day,status);
+ checkField(cal, UCAL_DAY_OF_WEEK, cases[i].dayOfWeek,status);
+ checkField(cal, UCAL_HOUR, cases[i].hour,status);
+ checkField(cal, UCAL_MINUTE, cases[i].min,status);
+ checkField(cal, UCAL_SECOND, cases[i].sec,status);
+
+ // Fields -> millis
+ cal->clear();
+
+ cal->set(UCAL_ERA, cases[i].era);
+ cal->set(UCAL_YEAR, cases[i].year);
+ cal->set(UCAL_MONTH, cases[i].month - 1);
+ cal->set(UCAL_DATE, cases[i].day);
+ cal->set(UCAL_DAY_OF_WEEK, cases[i].dayOfWeek);
+ cal->set(UCAL_HOUR, cases[i].hour);
+ cal->set(UCAL_MINUTE, cases[i].min);
+ cal->set(UCAL_SECOND, cases[i].sec);
+
+ UDate t2 = cal->getTime(status);
+
+ if(t != t2) {
+ errln("Field->millis: Expected %.0f but got %.0f\n", t, t2);
+ logln(calToStr(*cal));
+ }
+ }
+}
+
+UBool CalendarCaseTest::checkField(Calendar *cal, UCalendarDateFields field, int32_t value, UErrorCode &status)
+{
+ if(U_FAILURE(status)) return FALSE;
+ int32_t res = cal->get(field, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"Checking field " + fieldName(field) + " and got " + u_errorName(status));
+ return FALSE;
+ }
+ if(res != value) {
+ errln((UnicodeString)"FAIL: Checking field " + fieldName(field) + " expected " + value + " and got " + res + UnicodeString("\n"));
+ return FALSE;
+ } else {
+ logln((UnicodeString)"Checking field " + fieldName(field) + " == " + value + UnicodeString("\n"));
+ }
+ return TRUE;
+}
+
+// =========== Test Cases =====================
+enum { SUN=UCAL_SUNDAY,
+ MON=UCAL_MONDAY,
+ TUE=UCAL_TUESDAY,
+ WED=UCAL_WEDNESDAY,
+ THU=UCAL_THURSDAY,
+ FRI=UCAL_FRIDAY,
+ SAT=UCAL_SATURDAY};
+
+void CalendarCaseTest::IslamicCivil()
+{
+ static const TestCase tests[] = {
+ //
+ // Most of these test cases were taken from the back of
+ // "Calendrical Calculations", with some extras added to help
+ // debug a few of the problems that cropped up in development.
+ //
+ // The months in this table are 1-based rather than 0-based,
+ // because it's easier to edit that way.
+ // Islamic
+ // Julian Day Era Year Month Day WkDay Hour Min Sec
+ { 1507231.5, 0, -1245, 12, 9, SUN, 0, 0, 0},
+ { 1660037.5, 0, -813, 2, 23, WED, 0, 0, 0},
+ { 1746893.5, 0, -568, 4, 1, WED, 0, 0, 0},
+ { 1770641.5, 0, -501, 4, 6, SUN, 0, 0, 0},
+ { 1892731.5, 0, -157, 10, 17, WED, 0, 0, 0},
+ { 1931579.5, 0, -47, 6, 3, MON, 0, 0, 0},
+ { 1974851.5, 0, 75, 7, 13, SAT, 0, 0, 0},
+ { 2091164.5, 0, 403, 10, 5, SUN, 0, 0, 0},
+ { 2121509.5, 0, 489, 5, 22, SUN, 0, 0, 0},
+ { 2155779.5, 0, 586, 2, 7, FRI, 0, 0, 0},
+ { 2174029.5, 0, 637, 8, 7, SAT, 0, 0, 0},
+ { 2191584.5, 0, 687, 2, 20, FRI, 0, 0, 0},
+ { 2195261.5, 0, 697, 7, 7, SUN, 0, 0, 0},
+ { 2229274.5, 0, 793, 7, 1, SUN, 0, 0, 0},
+ { 2245580.5, 0, 839, 7, 6, WED, 0, 0, 0},
+ { 2266100.5, 0, 897, 6, 1, SAT, 0, 0, 0},
+ { 2288542.5, 0, 960, 9, 30, SAT, 0, 0, 0},
+ { 2290901.5, 0, 967, 5, 27, SAT, 0, 0, 0},
+ { 2323140.5, 0, 1058, 5, 18, WED, 0, 0, 0},
+ { 2334848.5, 0, 1091, 6, 2, SUN, 0, 0, 0},
+ { 2348020.5, 0, 1128, 8, 4, FRI, 0, 0, 0},
+ { 2366978.5, 0, 1182, 2, 3, SUN, 0, 0, 0},
+ { 2385648.5, 0, 1234, 10, 10, MON, 0, 0, 0},
+ { 2392825.5, 0, 1255, 1, 11, WED, 0, 0, 0},
+ { 2416223.5, 0, 1321, 1, 21, SUN, 0, 0, 0},
+ { 2425848.5, 0, 1348, 3, 19, SUN, 0, 0, 0},
+ { 2430266.5, 0, 1360, 9, 8, MON, 0, 0, 0},
+ { 2430833.5, 0, 1362, 4, 13, MON, 0, 0, 0},
+ { 2431004.5, 0, 1362, 10, 7, THU, 0, 0, 0},
+ { 2448698.5, 0, 1412, 9, 13, TUE, 0, 0, 0},
+ { 2450138.5, 0, 1416, 10, 5, SUN, 0, 0, 0},
+ { 2465737.5, 0, 1460, 10, 12, WED, 0, 0, 0},
+ { 2486076.5, 0, 1518, 3, 5, SUN, 0, 0, 0},
+ { -1,-1,-1,-1,-1,-1,-1,-1,-1 }
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *c = Calendar::createInstance("ar@calendar=islamic-civil", status);
+ c->setLenient(TRUE);
+ doTestCases(tests, c);
+
+ static const UChar expectedUChars[] = {
+ 0x0627, 0x0644, 0x062e, 0x0645, 0x064a, 0x0633, 0x002c, 0x0020, 0x0662, 0x0662,
+ 0x0020, 0x0634, 0x0648, 0x0627, 0x0644, 0x002c, 0x0020, 0x0661, 0x0663, 0x0668,
+ 0x0669, 0
+ };
+ UnicodeString result;
+ DateFormat *fmt = DateFormat::createDateInstance(DateFormat::kFull, Locale("ar_JO@calendar=islamic-civil"));
+ if (fmt == NULL) {
+ dataerrln("Error calling DateFormat::createDateInstance");
+ delete c;
+ delete fmt;
+ return;
+ }
+
+ fmt->setTimeZone(*TimeZone::getGMT());
+ fmt->format((UDate)2486076.5, result);
+ if (result != expectedUChars) {
+ errln((UnicodeString)"FAIL: DateFormatting failed. Got " + result + " and expected " + UnicodeString(expectedUChars) + UnicodeString("\n"));
+ errln("Maybe the resource aliasing isn't working");
+ }
+ delete fmt;
+ delete c;
+}
+
+void CalendarCaseTest::Hebrew() {
+ static const int32_t TISHRI = HebrewCalendar::TISHRI;
+ //static const int32_t HESHVAN = HebrewCalendar::HESHVAN;
+ //static const int32_t KISLEV = HebrewCalendar::KISLEV;
+ //static const int32_t TEVET = HebrewCalendar::TEVET;
+ //static const int32_t SHEVAT = HebrewCalendar::SHEVAT;
+ //static const int32_t ADAR_1 = HebrewCalendar::ADAR_1;
+ //static const int32_t ADAR = HebrewCalendar::ADAR;
+ //static const int32_t NISAN = HebrewCalendar::NISAN;
+ //static const int32_t IYAR = HebrewCalendar::IYAR;
+ //static const int32_t SIVAN = HebrewCalendar::SIVAN;
+ //static const int32_t TAMUZ = HebrewCalendar::TAMUZ;
+ static const int32_t AV = HebrewCalendar::AV;
+ static const int32_t ELUL = HebrewCalendar::ELUL;
+
+ static const TestCase tests[] = {
+ //
+ // Most of these test cases were taken from the back of
+ // "Calendrical Calculations", with some extras added to help
+ // debug a few of the problems that cropped up in development.
+ //
+ // The months in this table are 1-based rather than 0-based,
+ // because it's easier to edit that way.
+ //
+ // Julian Day Era Year Month Day WkDay Hour Min Sec
+ {1507231.5, 0, 3174, 12, 10, SUN, 0, 0, 0},
+ {1660037.5, 0, 3593, 3, 25, WED, 0, 0, 0},
+ {1746893.5, 0, 3831, 1, 3, WED, 0, 0, 0},
+ {1770641.5, 0, 3896, 1, 9, SUN, 0, 0, 0},
+ {1892731.5, 0, 4230, 4, 18, WED, 0, 0, 0},
+ {1931579.5, 0, 4336, 10, 4, MON, 0, 0, 0},
+ {1974851.5, 0, 4455, 2, 13, SAT, 0, 0, 0},
+ {2091164.5, 0, 4773, 9, 6, SUN, 0, 0, 0},
+ {2121509.5, 0, 4856, 9, 23, SUN, 0, 0, 0},
+ {2155779.5, 0, 4950, 8, 7, FRI, 0, 0, 0},
+ {2174029.5, 0, 5000, 7, 8, SAT, 0, 0, 0},
+ {2191584.5, 0, 5048, 8, 21, FRI, 0, 0, 0},
+ {2195261.5, 0, 5058, 9, 7, SUN, 0, 0, 0},
+ {2229274.5, 0, 5151, 11, 1, SUN, 0, 0, 0},
+ {2245580.5, 0, 5196, 5, 7, WED, 0, 0, 0},
+ {2266100.5, 0, 5252, 8, 3, SAT, 0, 0, 0},
+ {2288542.5, 0, 5314, 1, 1, SAT, 0, 0, 0},
+ {2290901.5, 0, 5320, 6, 27, SAT, 0, 0, 0},
+ {2323140.5, 0, 5408, 10, 20, WED, 0, 0, 0},
+ {2334551.5, 0, 5440, 1, 1, THU, 0, 0, 0},
+ {2334581.5, 0, 5440, 2, 1, SAT, 0, 0, 0},
+ {2334610.5, 0, 5440, 3, 1, SUN, 0, 0, 0},
+ {2334639.5, 0, 5440, 4, 1, MON, 0, 0, 0},
+ {2334668.5, 0, 5440, 5, 1, TUE, 0, 0, 0},
+ {2334698.5, 0, 5440, 6, 1, THU, 0, 0, 0},
+ {2334728.5, 0, 5440, 7, 1, SAT, 0, 0, 0},
+ {2334757.5, 0, 5440, 8, 1, SUN, 0, 0, 0},
+ {2334787.5, 0, 5440, 9, 1, TUE, 0, 0, 0},
+ {2334816.5, 0, 5440, 10, 1, WED, 0, 0, 0},
+ {2334846.5, 0, 5440, 11, 1, FRI, 0, 0, 0},
+ {2334848.5, 0, 5440, 11, 3, SUN, 0, 0, 0},
+ {2334934.5, 0, 5441, 1, 1, TUE, 0, 0, 0},
+ {2348020.5, 0, 5476, 12, 5, FRI, 0, 0, 0},
+ {2366978.5, 0, 5528, 11, 4, SUN, 0, 0, 0},
+ {2385648.5, 0, 5579, 12, 11, MON, 0, 0, 0},
+ {2392825.5, 0, 5599, 8, 12, WED, 0, 0, 0},
+ {2416223.5, 0, 5663, 8, 22, SUN, 0, 0, 0},
+ {2425848.5, 0, 5689, 12, 19, SUN, 0, 0, 0},
+ {2430266.5, 0, 5702, 1, 8, MON, 0, 0, 0},
+ {2430833.5, 0, 5703, 8, 14, MON, 0, 0, 0},
+ {2431004.5, 0, 5704, 1, 8, THU, 0, 0, 0},
+ {2448698.5, 0, 5752, 7, 12, TUE, 0, 0, 0},
+ {2450138.5, 0, 5756, 7, 5, SUN, 0, 0, 0},
+ {2465737.5, 0, 5799, 2, 12, WED, 0, 0, 0},
+ {2486076.5, 0, 5854, 12, 5, SUN, 0, 0, 0},
+
+ // Test cases taken from a table of 14 "year types" in the Help file
+ // of the application "Hebrew Calendar"
+ {2456187.5, 0, 5773, 1, 1, MON, 0, 0, 0},
+ {2459111.5, 0, 5781, 1, 1, SAT, 0, 0, 0},
+ {2453647.5, 0, 5766, 1, 1, TUE, 0, 0, 0},
+ {2462035.5, 0, 5789, 1, 1, THU, 0, 0, 0},
+ {2458756.5, 0, 5780, 1, 1, MON, 0, 0, 0},
+ {2460586.5, 0, 5785, 1, 1, THU, 0, 0, 0},
+ {2463864.5, 0, 5794, 1, 1, SAT, 0, 0, 0},
+ {2463481.5, 0, 5793, 1, 1, MON, 0, 0, 0},
+ {2470421.5, 0, 5812, 1, 1, THU, 0, 0, 0},
+ {2460203.5, 0, 5784, 1, 1, SAT, 0, 0, 0},
+ {2459464.5, 0, 5782, 1, 1, TUE, 0, 0, 0},
+ {2467142.5, 0, 5803, 1, 1, MON, 0, 0, 0},
+ {2455448.5, 0, 5771, 1, 1, THU, 0, 0, 0},
+ // Test cases for JB#2327
+ // http://www.fourmilab.com/documents/calendar/
+ // http://www.calendarhome.com/converter/
+ // 2452465.5, 2002, JULY, 10, 5762, AV, 1,
+ // 2452494.5, 2002, AUGUST, 8, 5762, AV, 30,
+ // 2452495.5, 2002, AUGUST, 9, 5762, ELUL, 1,
+ // 2452523.5, 2002, SEPTEMBER, 6, 5762, ELUL, 29,
+ // 2452524.5, 2002, SEPTEMBER, 7, 5763, TISHRI, 1,
+ // Julian Day Era Year Month Day WkDay Hour Min Sec
+ {2452465.5, 0, 5762, AV+1, 1, WED, 0, 0, 0},
+ {2452494.5, 0, 5762, AV+1, 30, THU, 0, 0, 0},
+ {2452495.5, 0, 5762, ELUL+1, 1, FRI, 0, 0, 0},
+ {2452523.5, 0, 5762, ELUL+1, 29, FRI, 0, 0, 0},
+ {2452524.5, 0, 5763, TISHRI+1, 1, SAT, 0, 0, 0},
+ { -1,-1,-1,-1,-1,-1,-1,-1,-1 }
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *c = Calendar::createInstance("he_HE@calendar=hebrew", status);
+ c->setLenient(TRUE);
+ doTestCases(tests, c);
+
+
+ // Additional test cases for bugs found during development
+ // G.YY/MM/DD Era Year Month Day WkDay Hour Min Sec
+ //{1013, 9, 8, 0, 4774, 1, 1, TUE, 0, 0, 0},
+ //{1239, 9, 1, 0, 5000, 1, 1, THU, 0, 0, 0},
+ //{1240, 9,18, 0, 5001, 1, 1, TUE, 0, 0, 0},
+
+
+ delete c;
+}
+
+void CalendarCaseTest::Indian() {
+ // Months in indian calendar are 0-based. Here taking 1-based names:
+ static const int32_t CHAITRA = IndianCalendar::CHAITRA + 1;
+ static const int32_t VAISAKHA = IndianCalendar::VAISAKHA + 1;
+ static const int32_t JYAISTHA = IndianCalendar::JYAISTHA + 1;
+ static const int32_t ASADHA = IndianCalendar::ASADHA + 1;
+ static const int32_t SRAVANA = IndianCalendar::SRAVANA + 1 ;
+ static const int32_t BHADRA = IndianCalendar::BHADRA + 1 ;
+ static const int32_t ASVINA = IndianCalendar::ASVINA + 1 ;
+ static const int32_t KARTIKA = IndianCalendar::KARTIKA + 1 ;
+ static const int32_t AGRAHAYANA = IndianCalendar::AGRAHAYANA + 1 ;
+ static const int32_t PAUSA = IndianCalendar::PAUSA + 1 ;
+ static const int32_t MAGHA = IndianCalendar::MAGHA + 1 ;
+ static const int32_t PHALGUNA = IndianCalendar::PHALGUNA + 1 ;
+
+
+ static const TestCase tests[] = {
+ // Test dates generated from:
+ // http://www.fourmilab.ch/documents/calendar/
+
+ // A huge list of test cases to make sure that computeTime and computeFields
+ // work properly for a wide range of data in the Indian civil calendar.
+ //
+ // Julian Day Era Year Month Day WkDay Hour Min Sec
+ {1770641.5, 0, 57, ASVINA, 10, SUN, 0, 0, 0},
+ {1892731.5, 0, 391, PAUSA, 18, WED, 0, 0, 0},
+ {1931579.5, 0, 498, VAISAKHA, 30, MON, 0, 0, 0},
+ {1974851.5, 0, 616, KARTIKA, 19, SAT, 0, 0, 0},
+ {2091164.5, 0, 935, VAISAKHA, 5, SUN, 0, 0, 0},
+ {2121509.5, 0, 1018, JYAISTHA, 3, SUN, 0, 0, 0},
+ {2155779.5, 0, 1112, CHAITRA, 2, FRI, 0, 0, 0},
+ {2174029.5, 0, 1161, PHALGUNA, 20, SAT, 0, 0, 0},
+ {2191584.5, 0, 1210, CHAITRA, 13, FRI, 0, 0, 0},
+ {2195261.5, 0, 1220, VAISAKHA, 7, SUN, 0, 0, 0},
+ {2229274.5, 0, 1313, JYAISTHA, 22, SUN, 0, 0, 0},
+ {2245580.5, 0, 1357, MAGHA, 14, WED, 0, 0, 0},
+ {2266100.5, 0, 1414, CHAITRA, 20, SAT, 0, 0, 0},
+ {2288542.5, 0, 1475, BHADRA, 28, SAT, 0, 0, 0},
+ {2290901.5, 0, 1481, PHALGUNA, 15, SAT, 0, 0, 0},
+ {2323140.5, 0, 1570, JYAISTHA, 20, WED, 0, 0, 0},
+ {2334551.5, 0, 1601, BHADRA, 16, THU, 0, 0, 0},
+ {2334581.5, 0, 1601, ASVINA, 15, SAT, 0, 0, 0},
+ {2334610.5, 0, 1601, KARTIKA, 14, SUN, 0, 0, 0},
+ {2334639.5, 0, 1601, AGRAHAYANA, 13, MON, 0, 0, 0},
+ {2334668.5, 0, 1601, PAUSA, 12, TUE, 0, 0, 0},
+ {2334698.5, 0, 1601, MAGHA, 12, THU, 0, 0, 0},
+ {2334728.5, 0, 1601, PHALGUNA, 12, SAT, 0, 0, 0},
+ {2334757.5, 0, 1602, CHAITRA, 11, SUN, 0, 0, 0},
+ {2334787.5, 0, 1602, VAISAKHA, 10, TUE, 0, 0, 0},
+ {2334816.5, 0, 1602, JYAISTHA, 8, WED, 0, 0, 0},
+ {2334846.5, 0, 1602, ASADHA, 7, FRI, 0, 0, 0},
+ {2334848.5, 0, 1602, ASADHA, 9, SUN, 0, 0, 0},
+ {2348020.5, 0, 1638, SRAVANA, 2, FRI, 0, 0, 0},
+ {2334934.5, 0, 1602, ASVINA, 2, TUE, 0, 0, 0},
+ {2366978.5, 0, 1690, JYAISTHA, 29, SUN, 0, 0, 0},
+ {2385648.5, 0, 1741, SRAVANA, 11, MON, 0, 0, 0},
+ {2392825.5, 0, 1761, CHAITRA, 6, WED, 0, 0, 0},
+ {2416223.5, 0, 1825, CHAITRA, 29, SUN, 0, 0, 0},
+ {2425848.5, 0, 1851, BHADRA, 3, SUN, 0, 0, 0},
+ {2430266.5, 0, 1863, ASVINA, 7, MON, 0, 0, 0},
+ {2430833.5, 0, 1865, CHAITRA, 29, MON, 0, 0, 0},
+ {2431004.5, 0, 1865, ASVINA, 15, THU, 0, 0, 0},
+ {2448698.5, 0, 1913, PHALGUNA, 27, TUE, 0, 0, 0},
+ {2450138.5, 0, 1917, PHALGUNA, 6, SUN, 0, 0, 0},
+ {2465737.5, 0, 1960, KARTIKA, 19, WED, 0, 0, 0},
+ {2486076.5, 0, 2016, ASADHA, 27, SUN, 0, 0, 0},
+ { -1,-1,-1,-1,-1,-1,-1,-1,-1 }
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *c = Calendar::createInstance("hi_IN@calendar=indian", status);
+ c->setLenient(TRUE);
+ doTestCases(tests, c);
+
+ delete c;
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/calcasts.h b/Build/source/libs/icu/icu-xetex/test/intltest/calcasts.h
new file mode 100644
index 00000000000..6085c229f70
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/calcasts.h
@@ -0,0 +1,63 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2003-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ********************************************************************
+ * Calendar Case Test is a type of CalendarTest which compares the
+ * behavior of a calendar to a certain set of 'test cases', involving
+ * conversion between julian-day to fields and vice versa.
+ ********************************************************************/
+
+#ifndef __CalendarCaseTest__
+#define __CalendarCaseTest__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/smpdtfmt.h"
+#include "caltest.h"
+
+class CalendarCaseTest: public CalendarTest {
+ public:
+ virtual void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+
+ /* Test case struct */
+ struct TestCase {
+ double julian; // Julian Date
+ int32_t era;
+ int32_t year;
+ int32_t month;
+ int32_t day;
+ int32_t dayOfWeek;
+ int32_t hour;
+ int32_t min;
+ int32_t sec;
+ };
+
+ /**
+ * @param cases array of items to test. Terminate with a "-1" for era.
+ */
+ void doTestCases(const TestCase *cases, Calendar *cal);
+
+ private:
+ /**
+ * Utility function to test out a specific field
+ * @param cal calendar
+ * @param field which field
+ * @param value expected value
+ * @param status err status
+ * @return boolean indicating success (TRUE) or failure (FALSE) of the test.
+ */
+ UBool checkField(Calendar *cal, UCalendarDateFields field, int32_t value, UErrorCode &status);
+
+ private:
+ // test cases
+ void IslamicCivil();
+ void Hebrew();
+ void Indian();
+};
+
+#endif
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/callimts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/callimts.cpp
new file mode 100644
index 00000000000..40ad122bf47
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/callimts.cpp
@@ -0,0 +1,135 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "callimts.h"
+#include "caltest.h"
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "putilimp.h"
+
+U_NAMESPACE_USE
+void CalendarLimitTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite TestCalendarLimit");
+ switch (index) {
+ // Re-enable this later
+ case 0:
+ name = "TestCalendarLimit";
+ if (exec) {
+ logln("TestCalendarLimit---"); logln("");
+ TestCalendarLimit();
+ }
+ break;
+ default: name = ""; break;
+ }
+}
+
+
+// *****************************************************************************
+// class CalendarLimitTest
+// *****************************************************************************
+
+// -------------------------------------
+void
+CalendarLimitTest::test(UDate millis, U_NAMESPACE_QUALIFIER Calendar* cal, U_NAMESPACE_QUALIFIER DateFormat* fmt)
+{
+ static const UDate kDrift = 1e-10;
+ UErrorCode exception = U_ZERO_ERROR;
+ UnicodeString theDate;
+ UErrorCode status = U_ZERO_ERROR;
+ cal->setTime(millis, exception);
+ if (U_SUCCESS(exception)) {
+ fmt->format(millis, theDate);
+ UDate dt = fmt->parse(theDate, status);
+ // allow a small amount of error (drift)
+ if(! withinErr(dt, millis, kDrift)) {
+ errln("FAIL:round trip for large milli, got: %.1lf wanted: %.1lf. (delta %.2lf greater than %.2lf)",
+ dt, millis, uprv_fabs(millis-dt), uprv_fabs(dt*kDrift));
+ logln(UnicodeString(" ") + theDate + " " + CalendarTest::calToStr(*cal));
+ } else {
+ logln(UnicodeString("OK: got ") + dt + ", wanted " + millis);
+ logln(UnicodeString(" ") + theDate);
+ }
+ }
+}
+
+// -------------------------------------
+
+// bug 986c: deprecate nextDouble/previousDouble
+//|double
+//|CalendarLimitTest::nextDouble(double a)
+//|{
+//| return uprv_nextDouble(a, TRUE);
+//|}
+//|
+//|double
+//|CalendarLimitTest::previousDouble(double a)
+//|{
+//| return uprv_nextDouble(a, FALSE);
+//|}
+
+UBool
+CalendarLimitTest::withinErr(double a, double b, double err)
+{
+ return ( uprv_fabs(a - b) < uprv_fabs(a * err) );
+}
+
+void
+CalendarLimitTest::TestCalendarLimit()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(status);
+ if (failure(status, "Calendar::createInstance")) return;
+ cal->adoptTimeZone(TimeZone::createTimeZone("GMT"));
+ DateFormat *fmt = DateFormat::createDateTimeInstance();
+ if(!fmt || !cal) {
+ dataerrln("can't open cal and/or fmt");
+ return;
+ }
+ fmt->adoptCalendar(cal);
+ ((SimpleDateFormat*) fmt)->applyPattern("HH:mm:ss.SSS zzz, EEEE, MMMM d, yyyy G");
+
+
+ // This test used to test the algorithmic limits of the dates that
+ // GregorianCalendar could handle. However, the algorithm has
+ // been rewritten completely since then and the prior limits no
+ // longer apply. Instead, we now do basic round-trip testing of
+ // some extreme (but still manageable) dates.
+ UDate m;
+ logln("checking 1e16..1e17");
+ for ( m = 1e16; m < 1e17; m *= 1.1) {
+ test(m, cal, fmt);
+ }
+ logln("checking -1e14..-1e15");
+ for ( m = -1e14; m > -1e15; m *= 1.1) {
+ test(m, cal, fmt);
+ }
+
+ // This is 2^52 - 1, the largest allowable mantissa with a 0
+ // exponent in a 64-bit double
+ UDate VERY_EARLY_MILLIS = - 4503599627370495.0;
+ UDate VERY_LATE_MILLIS = 4503599627370495.0;
+
+ // I am removing the previousDouble and nextDouble calls below for
+ // two reasons: 1. As part of jitterbug 986, I am deprecating
+ // these methods and removing calls to them. 2. This test is a
+ // non-critical boundary behavior test.
+ test(VERY_EARLY_MILLIS, cal, fmt);
+ //test(previousDouble(VERY_EARLY_MILLIS), cal, fmt);
+ test(VERY_LATE_MILLIS, cal, fmt);
+ //test(nextDouble(VERY_LATE_MILLIS), cal, fmt);
+ delete fmt;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+// eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/callimts.h b/Build/source/libs/icu/icu-xetex/test/intltest/callimts.h
new file mode 100644
index 00000000000..9ef1af36b5b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/callimts.h
@@ -0,0 +1,41 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef __CalendarLimitTest__
+#define __CalendarLimitTest__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "caltztst.h"
+
+/**
+ * This test verifies the behavior of Calendar around the very earliest limits
+ * which it can handle. It also verifies the behavior for large values of millis.
+ *
+ * Bug ID 4033662.
+ */
+class CalendarLimitTest: public CalendarTimeZoneTest {
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public: // package
+ //test routine used by TestCalendarLimit
+ virtual void test(UDate millis, Calendar *cal, DateFormat *fmt);
+
+ // bug 986c: deprecate nextDouble/previousDouble
+ //static double nextDouble(double a);
+ //static double previousDouble(double a);
+ static UBool withinErr(double a, double b, double err);
+
+public:
+ // test behaviour and error reporting at boundaries of defined range
+ virtual void TestCalendarLimit(void);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __CalendarLimitTest__
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/calregts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/calregts.cpp
new file mode 100644
index 00000000000..d5f8c670ac4
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/calregts.cpp
@@ -0,0 +1,2658 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "calregts.h"
+
+#include "unicode/gregocal.h"
+#include "unicode/simpletz.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/strenum.h"
+#include "cmemory.h"
+#include "caltest.h"
+
+#include <float.h>
+
+// *****************************************************************************
+// class CalendarRegressionTest
+// *****************************************************************************
+
+// these numbers correspond to using LONG_MIN and LONG_MAX in Java
+// this is 2^52 - 1, the largest allowable mantissa with a 0 exponent in a 64-bit double
+const UDate CalendarRegressionTest::EARLIEST_SUPPORTED_MILLIS = - 4503599627370495.0;
+const UDate CalendarRegressionTest::LATEST_SUPPORTED_MILLIS = 4503599627370495.0;
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
+
+void
+CalendarRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest");
+ switch (index) {
+ CASE(0,test4100311);
+ CASE(1,test4074758);
+ CASE(2,test4028518);
+ CASE(3,test4031502);
+ CASE(4,test4035301);
+ CASE(5,test4040996);
+ CASE(6,test4051765);
+ CASE(7,test4061476);
+ CASE(8,test4070502);
+ CASE(9,test4071197);
+ CASE(10,test4071385);
+ CASE(11,test4073929);
+ CASE(12,test4083167);
+ CASE(13,test4086724);
+ CASE(14,test4095407);
+ CASE(15,test4096231);
+ CASE(16,test4096539);
+ CASE(17,test41003112);
+ CASE(18,test4103271);
+ CASE(19,test4106136);
+ CASE(20,test4108764);
+ CASE(21,test4114578);
+ CASE(22,test4118384);
+ CASE(23,test4125881);
+ CASE(24,test4125892);
+ CASE(25,test4141665);
+ CASE(26,test4142933);
+ CASE(27,test4145158);
+ CASE(28,test4145983);
+ CASE(29,test4147269);
+
+ CASE(30,Test4149677);
+ CASE(31,Test4162587);
+ CASE(32,Test4165343);
+ CASE(33,Test4166109);
+ CASE(34,Test4167060);
+ CASE(35,Test4197699);
+ CASE(36,TestJ81);
+ CASE(37,TestJ438);
+ CASE(38,TestLeapFieldDifference);
+ CASE(39,TestMalaysianInstance);
+ CASE(40,test4059654);
+ CASE(41,test4092362);
+ CASE(42,TestWeekShift);
+ CASE(43,TestTimeZoneTransitionAdd);
+ CASE(44,TestDeprecates);
+ CASE(45,TestT5555);
+ default: name = ""; break;
+ }
+}
+
+const char* CalendarRegressionTest::FIELD_NAME [] = {
+ "ERA",
+ "YEAR",
+ "MONTH",
+ "WEEK_OF_YEAR",
+ "WEEK_OF_MONTH",
+ "DAY_OF_MONTH",
+ "DAY_OF_YEAR",
+ "DAY_OF_WEEK",
+ "DAY_OF_WEEK_IN_MONTH",
+ "AM_PM",
+ "HOUR",
+ "HOUR_OF_DAY",
+ "MINUTE",
+ "SECOND",
+ "MILLISECOND",
+ "ZONE_OFFSET",
+ "DST_OFFSET",
+ "YEAR_WOY",
+ "DOW_LOCAL"
+};
+
+UBool
+CalendarRegressionTest::failure(UErrorCode status, const char* msg)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * bug 4100311
+ */
+void
+CalendarRegressionTest::test4100311()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *cal = (GregorianCalendar*)Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ failure(status, "Calendar::createInstance(status)");
+ cal->set(UCAL_YEAR, 1997);
+ cal->set(UCAL_DAY_OF_YEAR, 1);
+ UDate d = cal->getTime(status); // Should be Jan 1
+ failure(status, "cal->getTime");
+ logln(UnicodeString("") + d);
+ delete cal;
+}
+
+
+/**
+ * @bug 4074758
+ */
+void
+CalendarRegressionTest::test4074758()
+{ //Set system time to between 12-1 (am or pm) and then run
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *cal = new GregorianCalendar(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ failure(status, "new GregorianCalendar");
+ for (int32_t h=0; h<25; ++h) {
+ cal->set(97, UCAL_JANUARY, 1, h, 34);
+ //System.out.print(d);
+ logln(UnicodeString("HOUR=") + cal->get(UCAL_HOUR, status)); //prints 0
+ failure(status, "cal->get");
+ logln(UnicodeString("HOUR_OF_DAY=") + cal->get(UCAL_HOUR_OF_DAY, status));
+ failure(status, "cal->get");
+ }
+
+ delete cal;
+}
+
+void
+CalendarRegressionTest::test4028518()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *cal1 = new GregorianCalendar(status) ;
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal1;
+ return;
+ }
+ failure(status, "new GregorianCalendar");
+ GregorianCalendar *cal2 = (GregorianCalendar*) cal1->clone() ;
+
+ printdate(cal1, "cal1: ") ;
+ printdate(cal2, "cal2 - cloned(): ") ;
+ cal1->add(UCAL_DATE, 1, status) ;
+ failure(status, "cal1->add");
+ printdate(cal1, "cal1 after adding 1 day:") ;
+ printdate(cal2, "cal2 should be unmodified:") ;
+ delete cal1;
+ delete cal2;
+}
+
+void
+CalendarRegressionTest::printdate(GregorianCalendar *cal, const char *string)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ logln(UnicodeString(string, ""));
+ log(UnicodeString("") + cal->get(UCAL_MONTH, status)) ;
+ failure(status, "cal->get");
+ int32_t date = cal->get(UCAL_DATE, status) + 1 ;
+ failure(status, "cal->get");
+ log(UnicodeString("/") + date) ;
+ logln(UnicodeString("/") + cal->get(UCAL_YEAR, status)) ;
+ failure(status, "cal->get");
+}
+
+/**
+ * @bug 4031502
+ */
+void
+CalendarRegressionTest::test4031502()
+{
+ // This bug actually occurs on Windows NT as well, and doesn't
+ // require the host zone to be set; it can be set in Java.
+ UErrorCode status = U_ZERO_ERROR;
+ StringEnumeration* ids = TimeZone::createEnumeration();
+ UBool bad = FALSE;
+ TimeZone* tz =TimeZone::createTimeZone("Asia/Riyadh87");
+ failure(status, "new TimeZone");
+ GregorianCalendar *cl = new GregorianCalendar(tz, status);
+ failure(status, "new GregorianCalendar");
+ cl->clear();
+ cl->set(1900, 15, 5, 5, 8, 13);
+ cl->get(UCAL_HOUR, status);
+ failure(status, "cl->get(UCAL_HOUR, status)");
+ status = U_ZERO_ERROR;
+ delete cl;
+ for (int32_t i=0; i<ids->count(status); ++i) {
+ TimeZone *zone = TimeZone::createTimeZone(*ids->snext(status));
+ GregorianCalendar *cal = new GregorianCalendar(zone, status);
+ failure(status, "new GregorianCalendar");
+ cal->clear();
+ cal->set(1900, 15, 5, 5, 8, 13);
+ if (cal->get(UCAL_HOUR, status) != 5 || U_FAILURE(status)) {
+ UnicodeString temp;
+ logln(zone->getID(temp) + " " +
+ //zone.useDaylightTime() + " " +
+ cal->get(UCAL_DST_OFFSET,status) / (60*60*1000) + " " +
+ zone->getRawOffset() / (60*60*1000) +
+ ": HOUR = " + cal->get(UCAL_HOUR,status));
+ bad = TRUE;
+ }
+ delete cal;
+ }
+ if (bad)
+ errln("TimeZone problems with GC");
+ // delete [] ids; // TODO: bad APIs
+ delete ids;
+}
+
+/**
+ * @bug 4035301
+ */
+void CalendarRegressionTest::test4035301()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *c = new GregorianCalendar(98, 8, 7,status);
+ GregorianCalendar *d = new GregorianCalendar(98, 8, 7,status);
+ if (c->after(*d,status) ||
+ c->after(*c,status) ||
+ c->before(*d,status) ||
+ c->before(*c,status) ||
+ *c != *c ||
+ *c != *d)
+ errln("Fail");
+ delete c;
+ delete d;
+}
+
+/**
+ * @bug 4040996
+ */
+void CalendarRegressionTest::test4040996()
+{
+ int32_t count = 0;
+ StringEnumeration* ids = TimeZone::createEnumeration(-8 * 60 * 60 * 1000);
+ UErrorCode status = U_ZERO_ERROR;
+ count = ids->count(status);
+ SimpleTimeZone *pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, *ids->snext(status));
+ pdt->setStartRule(UCAL_APRIL, 1, UCAL_SUNDAY, 2 * 60 * 60 * 1000, status);
+ pdt->setEndRule(UCAL_OCTOBER, -1, UCAL_SUNDAY, 2 * 60 * 60 * 1000, status);
+ Calendar *calendar = new GregorianCalendar(pdt, status);
+
+ calendar->set(UCAL_MONTH,3);
+ calendar->set(UCAL_DATE,18);
+ calendar->set(UCAL_SECOND, 30);
+
+ logln(UnicodeString("MONTH: ") + calendar->get(UCAL_MONTH, status));
+ logln(UnicodeString("DAY_OF_MONTH: ") +
+ calendar->get(UCAL_DATE, status));
+ logln(UnicodeString("MINUTE: ") + calendar->get(UCAL_MINUTE, status));
+ logln(UnicodeString("SECOND: ") + calendar->get(UCAL_SECOND, status));
+
+ calendar->add(UCAL_SECOND,6, status);
+ //This will print out todays date for MONTH and DAY_OF_MONTH
+ //instead of the date it was set to.
+ //This happens when adding MILLISECOND or MINUTE also
+ logln(UnicodeString("MONTH: ") + calendar->get(UCAL_MONTH, status));
+ logln(UnicodeString("DAY_OF_MONTH: ") +
+ calendar->get(UCAL_DATE, status));
+ logln(UnicodeString("MINUTE: ") + calendar->get(UCAL_MINUTE, status));
+ logln(UnicodeString("SECOND: ") + calendar->get(UCAL_SECOND, status));
+ if (calendar->get(UCAL_MONTH, status) != 3 ||
+ calendar->get(UCAL_DATE, status) != 18 ||
+ calendar->get(UCAL_SECOND, status) != 36)
+ errln(UnicodeString("Fail: Calendar::add misbehaves"));
+
+ delete calendar;
+ delete ids;
+ // delete ids; // TODO: BAD API
+}
+
+/**
+ * @bug 4051765
+ */
+void CalendarRegressionTest::test4051765()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ cal->setLenient(FALSE);
+ cal->set(UCAL_DAY_OF_WEEK, 0);
+ //try {
+ cal->getTime(status);
+ if( ! U_FAILURE(status))
+ errln("Fail: DAY_OF_WEEK 0 should be disallowed");
+ /*}
+ catch (IllegalArgumentException e) {
+ return;
+ }*/
+
+ delete cal;
+}
+
+/* User error - no bug here
+void CalendarRegressionTest::test4059524() {
+ // Create calendar for April 10, 1997
+ GregorianCalendar calendar = new GregorianCalendar(status);
+ // print out a bunch of interesting things
+ logln("ERA: " + Calendar::get(Calendar::ERA));
+ logln("YEAR: " + Calendar::get(Calendar::YEAR));
+ logln("MONTH: " + Calendar::get(Calendar::MONTH));
+ logln("WEEK_OF_YEAR: " +
+ Calendar::get(Calendar::WEEK_OF_YEAR));
+ logln("WEEK_OF_MONTH: " +
+ Calendar::get(Calendar::WEEK_OF_MONTH));
+ logln("DATE: " + Calendar::get(Calendar::DATE));
+ logln("DAY_OF_MONTH: " +
+ Calendar::get(Calendar::DAY_OF_MONTH));
+ logln("DAY_OF_YEAR: " + Calendar::get(Calendar::DAY_OF_YEAR));
+ logln("DAY_OF_WEEK: " + Calendar::get(Calendar::DAY_OF_WEEK));
+ logln("DAY_OF_WEEK_IN_MONTH: " +
+ Calendar::get(Calendar::DAY_OF_WEEK_IN_MONTH));
+ logln("AM_PM: " + Calendar::get(Calendar::AM_PM));
+ logln("HOUR: " + Calendar::get(Calendar::HOUR));
+ logln("HOUR_OF_DAY: " + Calendar::get(Calendar::HOUR_OF_DAY));
+ logln("MINUTE: " + Calendar::get(Calendar::MINUTE));
+ logln("SECOND: " + Calendar::get(Calendar::SECOND));
+ logln("MILLISECOND: " + Calendar::get(Calendar::MILLISECOND));
+ logln("ZONE_OFFSET: "
+ + (Calendar::get(Calendar::ZONE_OFFSET)/(60*60*1000)));
+ logln("DST_OFFSET: "
+ + (Calendar::get(Calendar::DST_OFFSET)/(60*60*1000)));
+ calendar = new GregorianCalendar(1997,3,10);
+ Calendar::getTime();
+ logln("April 10, 1997");
+ logln("ERA: " + Calendar::get(Calendar::ERA));
+ logln("YEAR: " + Calendar::get(Calendar::YEAR));
+ logln("MONTH: " + Calendar::get(Calendar::MONTH));
+ logln("WEEK_OF_YEAR: " +
+ Calendar::get(Calendar::WEEK_OF_YEAR));
+ logln("WEEK_OF_MONTH: " +
+ Calendar::get(Calendar::WEEK_OF_MONTH));
+ logln("DATE: " + Calendar::get(Calendar::DATE));
+ logln("DAY_OF_MONTH: " +
+ Calendar::get(Calendar::DAY_OF_MONTH));
+ logln("DAY_OF_YEAR: " + Calendar::get(Calendar::DAY_OF_YEAR));
+ logln("DAY_OF_WEEK: " + Calendar::get(Calendar::DAY_OF_WEEK));
+ logln("DAY_OF_WEEK_IN_MONTH: " + Calendar::get(Calendar::DAY_OF_WEEK_IN_MONTH));
+ logln("AM_PM: " + Calendar::get(Calendar::AM_PM));
+ logln("HOUR: " + Calendar::get(Calendar::HOUR));
+ logln("HOUR_OF_DAY: " + Calendar::get(Calendar::HOUR_OF_DAY));
+ logln("MINUTE: " + Calendar::get(Calendar::MINUTE));
+ logln("SECOND: " + Calendar::get(Calendar::SECOND));
+ logln("MILLISECOND: " + Calendar::get(Calendar::MILLISECOND));
+ logln("ZONE_OFFSET: "
+ + (Calendar::get(Calendar::ZONE_OFFSET)/(60*60*1000))); // in hours
+ logln("DST_OFFSET: "
+ + (Calendar::get(Calendar::DST_OFFSET)/(60*60*1000))); // in hours
+}
+*/
+
+/**
+ * @bug 4059654
+ */
+void CalendarRegressionTest::test4059654() {
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *gc = new GregorianCalendar(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete gc;
+ return;
+ }
+
+ gc->set(1997, 3, 1, 15, 16, 17); // April 1, 1997
+
+ gc->set(UCAL_HOUR, 0);
+ gc->set(UCAL_AM_PM, UCAL_AM);
+ gc->set(UCAL_MINUTE, 0);
+ gc->set(UCAL_SECOND, 0);
+ gc->set(UCAL_MILLISECOND, 0);
+
+ UDate cd = gc->getTime(status);
+ GregorianCalendar *exp = new GregorianCalendar(1997, 3, 1, 0, 0, 0, status);
+ if (cd != exp->getTime(status))
+ errln(UnicodeString("Fail: Calendar::set broken. Got ") + cd + " Want " + exp->getTime(status));
+
+ delete gc;
+ delete exp;
+}
+
+/**
+ * @bug 4061476
+ */
+void CalendarRegressionTest::test4061476()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("ddMMMyy"), Locale::getUK(),status);
+ Calendar *cal = Calendar::createInstance(TimeZone::createTimeZone("GMT"),
+ Locale::getUK(),status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal;
+ delete fmt;
+ return;
+ }
+ fmt->adoptCalendar(cal);
+ // try {
+ UDate date = fmt->parse("29MAY97", status);
+ failure(status, "fmt->parse");
+ cal->setTime(date, status);
+ failure(status, "cal->setTime");
+ // }
+ //catch (Exception e) {;}
+ cal->set(UCAL_HOUR_OF_DAY, 13);
+ logln(UnicodeString("Hour: ")+cal->get(UCAL_HOUR_OF_DAY, status));
+ cal->add(UCAL_HOUR_OF_DAY, 6,status);
+ logln(UnicodeString("Hour: ")+cal->get(UCAL_HOUR_OF_DAY, status));
+ if (cal->get(UCAL_HOUR_OF_DAY, status) != 19)
+ errln(UnicodeString("Fail: Want 19 Got ") + cal->get(UCAL_HOUR_OF_DAY, status));
+
+ delete fmt;
+}
+
+/**
+ * @bug 4070502
+ */
+void CalendarRegressionTest::test4070502()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = new GregorianCalendar(status);
+ if(status == U_USING_FALLBACK_WARNING) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ UDate d = getAssociatedDate(makeDate(1998,0,30), status);
+ cal->setTime(d,status);
+ if (cal->get(UCAL_DAY_OF_WEEK,status) == UCAL_SATURDAY ||
+ cal->get(UCAL_DAY_OF_WEEK,status) == UCAL_SUNDAY)
+ errln(UnicodeString("Fail: Want weekday Got ") + d);
+
+ delete cal;
+}
+
+/**
+ * Get the associated date starting from a specified date
+ * NOTE: the unnecessary "getTime()'s" below are a work-around for a
+ * bug in jdk 1.1.3 (and probably earlier versions also)
+ * <p>
+ * @param date The date to start from
+ */
+UDate
+CalendarRegressionTest::getAssociatedDate(UDate d, UErrorCode& status)
+{
+ GregorianCalendar *cal = new GregorianCalendar(status);
+ cal->setTime(d,status);
+ //cal.add(field, amount); //<-- PROBLEM SEEN WITH field = DATE,MONTH
+ // cal.getTime(); // <--- REMOVE THIS TO SEE BUG
+ for (;;) {
+ int32_t wd = cal->get(UCAL_DAY_OF_WEEK, status);
+ if (wd == UCAL_SATURDAY || wd == UCAL_SUNDAY) {
+ cal->add(UCAL_DATE, 1, status);
+ // cal.getTime();
+ }
+ else
+ break;
+ }
+
+ UDate dd = cal->getTime(status);
+ delete cal;
+ return dd;
+}
+
+/**
+ * @bug 4071197
+ */
+void CalendarRegressionTest::test4071197()
+{
+ dowTest(FALSE);
+ dowTest(TRUE);
+}
+
+void CalendarRegressionTest::dowTest(UBool lenient)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *cal = new GregorianCalendar(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ cal->set(1997, UCAL_AUGUST, 12); // Wednesday
+ // cal.getTime(); // Force update
+ cal->setLenient(lenient);
+ cal->set(1996, UCAL_DECEMBER, 1); // Set the date to be December 1, 1996
+ int32_t dow = cal->get(UCAL_DAY_OF_WEEK, status);
+ int32_t min = cal->getMinimum(UCAL_DAY_OF_WEEK);
+ int32_t max = cal->getMaximum(UCAL_DAY_OF_WEEK);
+ //logln(cal.getTime().toString());
+ if (min != UCAL_SUNDAY || max != UCAL_SATURDAY)
+ errln("FAIL: Min/max bad");
+ if (dow < min || dow > max)
+ errln("FAIL: Day of week %d out of range [%d,%d]\n", dow, min, max);
+ if (dow != UCAL_SUNDAY)
+ errln("FAIL: Day of week should be SUNDAY Got " + dow);
+
+ if(U_FAILURE(status)) {
+ errln("Error checking Calendar: %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+
+ if(cal->getActualMinimum(UCAL_DAY_OF_WEEK, status) != min) {
+ errln("FAIL: actual minimum differs from minimum");
+ }
+ if(cal->getActualMinimum(Calendar::DAY_OF_WEEK, status) != min) {
+ errln("FAIL: actual minimum (Calendar::DAY_OF_WEEK, status) differs from minimum");
+ }
+ if(cal->getActualMinimum(Calendar::DAY_OF_WEEK) != min) {
+ errln("FAIL: actual minimum (Calendar::DAY_OF_WEEK) differs from minimum");
+ }
+ if(((Calendar*)cal)->getActualMinimum(UCAL_DAY_OF_WEEK, status) != min) {
+ errln("FAIL: actual minimum (UCAL_DAY_OF_WEEK, status) differs from minimum");
+ }
+// NOTE: This function does not exist! jitterbug #3016
+// if(((Calendar*)cal)->getActualMinimum(Calendar::DAY_OF_WEEK, status) != min) {
+// errln("FAIL: actual minimum (Calendar::DAY_OF_WEEK, status) differs from minimum");
+// }
+ if(U_FAILURE(status)) {
+ errln("Error getting actual minimum: %s", u_errorName(status));
+ return;
+ }
+
+ delete cal;
+}
+
+/**
+ * @bug 4071385
+ */
+void CalendarRegressionTest::test4071385()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ cal->setTime(makeDate(1998, UCAL_JUNE, 24),status);
+ cal->set(UCAL_MONTH, UCAL_NOVEMBER); // change a field
+ //logln(cal.getTime().toString());
+ if (cal->getTime(status) != makeDate(1998, UCAL_NOVEMBER, 24))
+ errln("Fail");
+
+ delete cal;
+}
+
+/**
+ * @bug 4073929
+ */
+void CalendarRegressionTest::test4073929()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *foo1 = new GregorianCalendar(1997, 8, 27,status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete foo1;
+ return;
+ }
+ logln("foo1@%.0f - %d-%d-%d %d:%d:%d.%ds\n", foo1->getTime(status),
+ foo1->get(UCAL_YEAR, status),
+ foo1->get(UCAL_MONTH, status),
+ foo1->get(UCAL_DATE, status),
+ foo1->get(UCAL_HOUR, status),
+ foo1->get(UCAL_MINUTE, status),
+ foo1->get(UCAL_SECOND, status),
+ foo1->get(UCAL_MILLISECOND,status));
+ foo1->add(UCAL_DATE, + 1, status);
+ logln("foo1@%.0f - %d-%d-%d %d:%d:%d.%ds after +\n", foo1->getTime(status),
+ foo1->get(UCAL_YEAR, status),
+ foo1->get(UCAL_MONTH, status),
+ foo1->get(UCAL_DATE, status),
+ foo1->get(UCAL_HOUR, status),
+ foo1->get(UCAL_MINUTE, status),
+ foo1->get(UCAL_SECOND, status),
+ foo1->get(UCAL_MILLISECOND ,status));
+ foo1->add(UCAL_DATE, - 1, status);
+ logln("foo1@%.0f - %d-%d-%d %d:%d:%d.%ds after -\n", foo1->getTime(status),
+ foo1->get(UCAL_YEAR, status),
+ foo1->get(UCAL_MONTH, status),
+ foo1->get(UCAL_DATE, status),
+ foo1->get(UCAL_HOUR, status),
+ foo1->get(UCAL_MINUTE, status),
+ foo1->get(UCAL_SECOND, status),
+ foo1->get(UCAL_MILLISECOND, status));
+
+ foo1->add(UCAL_DATE, + 1, status);
+ int32_t testyear = foo1->get(UCAL_YEAR, status);
+ int32_t testmonth = foo1->get(UCAL_MONTH, status);
+ int32_t testday = foo1->get(UCAL_DATE, status);
+ if (testyear != 1997 ||
+ testmonth != 8 ||
+ testday != 28)
+ errln("Fail: Calendar not initialized");
+
+ delete foo1;
+}
+
+/**
+ * @bug 4083167
+ */
+void CalendarRegressionTest::test4083167()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ TimeZone *saveZone = TimeZone::createDefault();
+ //try {
+ TimeZone *newZone = TimeZone::createTimeZone("UTC");
+ TimeZone::setDefault(*newZone);
+ UDate firstDate = Calendar::getNow();
+ Calendar *cal = new GregorianCalendar(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ cal->setTime(firstDate,status);
+ int32_t hr = cal->get(UCAL_HOUR_OF_DAY, status);
+ int32_t min = cal->get(UCAL_MINUTE, status);
+ int32_t sec = cal->get(UCAL_SECOND, status);
+ int32_t msec = cal->get(UCAL_MILLISECOND, status);
+ double firstMillisInDay = hr * 3600000 + min * 60000 + sec * 1000 + msec;
+
+ //logln("Current time: " + firstDate.toString());
+
+ for (int32_t validity=0; validity<30; validity++) {
+ UDate lastDate = firstDate + validity*1000*24*60*60.0;
+ cal->setTime(lastDate, status);
+ hr = cal->get(UCAL_HOUR_OF_DAY, status);
+ min = cal->get(UCAL_MINUTE, status);
+ sec = cal->get(UCAL_SECOND, status);
+ msec = cal->get(UCAL_MILLISECOND, status);
+ double millisInDay = hr * 3600000.0 + min * 60000.0 + sec * 1000.0 + msec;
+ if (firstMillisInDay != millisInDay)
+ errln(UnicodeString("Day has shifted ") + lastDate);
+ }
+ //}
+ //finally {
+ TimeZone::setDefault(*saveZone);
+ //}
+
+ delete saveZone;
+ delete newZone;
+ delete cal;
+}
+
+/**
+ * @bug 4086724
+ */
+void CalendarRegressionTest::test4086724()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *date;
+ TimeZone *saveZone = TimeZone::createDefault();
+ Locale saveLocale = Locale::getDefault();
+ //try {
+ Locale::setDefault(Locale::getUK(),status);
+ TimeZone *newZone = TimeZone::createTimeZone("GMT");
+ TimeZone::setDefault(*newZone);
+ date = new SimpleDateFormat(UnicodeString("dd MMM yyy (zzzz) 'is in week' ww"),status);
+ Calendar *cal = Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating Calendar: %s", u_errorName(status));
+ delete cal;
+ delete newZone;
+ delete date;
+ return;
+ }
+ cal->set(1997,UCAL_SEPTEMBER,30);
+ UDate now = cal->getTime(status);
+ UnicodeString temp;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ logln(date->format(now, temp, pos));
+ cal->set(1997,UCAL_JANUARY,1);
+ now=cal->getTime(status);
+ logln(date->format(now,temp, pos));
+ cal->set(1997,UCAL_JANUARY,8);
+ now=cal->getTime(status);
+ logln(date->format(now,temp, pos));
+ cal->set(1996,UCAL_DECEMBER,31);
+ now=cal->getTime(status);
+ logln(date->format(now,temp, pos));
+ //}
+ //finally {
+ Locale::setDefault(saveLocale,status);
+ TimeZone::setDefault(*saveZone);
+ //}
+ logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");
+
+delete newZone;
+delete cal;
+delete date;
+delete saveZone;
+}
+
+/**
+ * @bug 4092362
+ */
+void CalendarRegressionTest::test4092362() {
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *cal1 = new GregorianCalendar(1997, 10, 11, 10, 20, 40,status);
+ /*cal1.set( Calendar::YEAR, 1997 );
+ cal1.set( Calendar::MONTH, 10 );
+ cal1.set( Calendar::DATE, 11 );
+ cal1.set( Calendar::HOUR, 10 );
+ cal1.set( Calendar::MINUTE, 20 );
+ cal1.set( Calendar::SECOND, 40 ); */
+
+ logln( UnicodeString(" Cal1 = ") + cal1->getTime(status) );
+ logln( UnicodeString(" Cal1 time in ms = ") + cal1->get(UCAL_MILLISECOND,status) );
+ for( int32_t k = 0; k < 100 ; k++ );
+
+ GregorianCalendar *cal2 = new GregorianCalendar(1997, 10, 11, 10, 20, 40,status);
+ /*cal2.set( Calendar::YEAR, 1997 );
+ cal2.set( Calendar::MONTH, 10 );
+ cal2.set( Calendar::DATE, 11 );
+ cal2.set( Calendar::HOUR, 10 );
+ cal2.set( Calendar::MINUTE, 20 );
+ cal2.set( Calendar::SECOND, 40 ); */
+
+ logln( UnicodeString(" Cal2 = ") + cal2->getTime(status) );
+ logln( UnicodeString(" Cal2 time in ms = ") + cal2->get(UCAL_MILLISECOND,status) );
+ if( *cal1 != *cal2 )
+ errln("Fail: Milliseconds randomized");
+
+ delete cal1;
+ delete cal2;
+}
+
+/**
+ * @bug 4095407
+ */
+void CalendarRegressionTest::test4095407()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *a = new GregorianCalendar(1997,UCAL_NOVEMBER, 13,status);
+ int32_t dow = a->get(UCAL_DAY_OF_WEEK, status);
+ if (dow != UCAL_THURSDAY)
+ errln("Fail: Want THURSDAY Got " + dow);
+
+ delete a;
+}
+
+/**
+ * @bug 4096231
+ */
+void CalendarRegressionTest::test4096231()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ TimeZone *GMT = TimeZone::createTimeZone("GMT");
+ TimeZone *PST = TimeZone::createTimeZone("PST");
+ int32_t sec = 0, min = 0, hr = 0, day = 1, month = 10, year = 1997;
+
+ Calendar *cal1 = new GregorianCalendar(*PST,status);
+ cal1->setTime(880698639000.0,status);
+ // Issue 1: Changing the timezone doesn't change the
+ // represented time. The old API, pre 1.2.2a requires
+ // setTime to be called in order to update the time fields after the time
+ // zone has been set.
+ int32_t h1,h2;
+ logln(UnicodeString("PST 1 is: ") + (h1=cal1->get(UCAL_HOUR_OF_DAY, status)));
+ cal1->setTimeZone(*GMT);
+ logln(UnicodeString("GMT 2 is: ") + (h2=cal1->get(UCAL_HOUR_OF_DAY, status)));
+ if ((*GMT != *PST) && (h1 == h2))
+ errln("Fail: Hour same in different zones");
+
+ Calendar *cal2 = new GregorianCalendar(*GMT,status);
+ Calendar *cal3 = new GregorianCalendar(*PST,status);
+
+ cal2->set(cal1->get(UCAL_YEAR,status),
+ cal1->get(UCAL_MONTH,status),
+ cal1->get(UCAL_DATE,status),
+ cal1->get(UCAL_HOUR_OF_DAY,status),
+ cal1->get(UCAL_MINUTE,status),
+ cal1->get(UCAL_SECOND,status));
+
+ double t1,t2,t3,t4;
+ logln(UnicodeString("RGMT 1 is: ") + (t1=cal2->getTime(status)));
+ cal3->set(year, month, day, hr, min, sec);
+ logln(UnicodeString("RPST 1 is: ") + (t2=cal3->getTime(status)));
+ cal3->setTimeZone(*GMT);
+ logln(UnicodeString("RGMT 2 is: ") + (t3=cal3->getTime(status)));
+ cal3->set(cal1->get(UCAL_YEAR,status),
+ cal1->get(UCAL_MONTH,status),
+ cal1->get(UCAL_DATE,status),
+ cal1->get(UCAL_HOUR_OF_DAY,status),
+ cal1->get(UCAL_MINUTE,status),
+ cal1->get(UCAL_SECOND,status));
+ // Issue 2: Calendar continues to use the timezone in its
+ // constructor for set() conversions, regardless
+ // of calls to setTimeZone()
+ logln(UnicodeString("RGMT 3 is: ") + (t4=cal3->getTime(status)));
+ if (t1 == t2 ||
+ t1 != t4 ||
+ t2 != t3)
+ errln("Fail: Calendar zone behavior faulty");
+
+ delete cal1;
+ delete cal2;
+ delete cal3;
+ delete GMT;
+ delete PST;
+}
+
+/**
+ * @bug 4096539
+ */
+void CalendarRegressionTest::test4096539()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t y [] = {31,28,31,30,31,30,31,31,30,31,30,31};
+
+ for (int32_t x=0;x<12;x++) {
+ GregorianCalendar *gc = new
+ GregorianCalendar(1997,x,y[x], status);
+ int32_t m1,m2;
+ log(UnicodeString("") + (m1=gc->get(UCAL_MONTH,status)+1)+UnicodeString("/")+
+ gc->get(UCAL_DATE,status)+"/"+gc->get(UCAL_YEAR,status)+
+ " + 1mo = ");
+
+ gc->add(UCAL_MONTH, 1,status);
+ logln(UnicodeString("") + (m2=gc->get(UCAL_MONTH,status)+1)+UnicodeString("/")+
+ gc->get(UCAL_DATE,status)+"/"+gc->get(UCAL_YEAR,status)
+ );
+ int32_t m = (m1 % 12) + 1;
+ if (m2 != m)
+ errln(UnicodeString("Fail: Want ") + m + " Got " + m2);
+ delete gc;
+ }
+
+}
+
+/**
+ * @bug 4100311
+ */
+void CalendarRegressionTest::test41003112()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *cal = (GregorianCalendar*)Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar: %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ cal->set(UCAL_YEAR, 1997);
+ cal->set(UCAL_DAY_OF_YEAR, 1);
+ //UDate d = cal->getTime(status); // Should be Jan 1
+ //logln(d.toString());
+ if (cal->get(UCAL_DAY_OF_YEAR, status) != 1)
+ errln("Fail: DAY_OF_YEAR not set");
+ delete cal;
+}
+
+/**
+ * @bug 4103271
+ */
+void CalendarRegressionTest::test4103271()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat sdf(status);
+ int32_t numYears=40, startYear=1997, numDays=15;
+ UnicodeString output, testDesc, str, str2;
+ GregorianCalendar *testCal = (GregorianCalendar*)Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar: %s", u_errorName(status));
+ delete testCal;
+ return;
+ }
+ testCal->clear();
+ sdf.adoptCalendar(testCal);
+ sdf.applyPattern("EEE dd MMM yyyy 'WOY'ww'-'YYYY 'DOY'DDD");
+ UBool fail = FALSE;
+ for (int32_t firstDay=1; firstDay<=2; firstDay++) {
+ for (int32_t minDays=1; minDays<=7; minDays++) {
+ testCal->setMinimalDaysInFirstWeek((uint8_t)minDays);
+ testCal->setFirstDayOfWeek((UCalendarDaysOfWeek)firstDay);
+ testDesc = (UnicodeString("Test") + firstDay + minDays);
+ logln(testDesc + " => 1st day of week=" +
+ firstDay +
+ ", minimum days in first week=" +
+ minDays);
+ for (int32_t j=startYear; j<=startYear+numYears; j++) {
+ testCal->set(j,11,25);
+ for(int32_t i=0; i<numDays; i++) {
+ testCal->add(UCAL_DATE,1,status);
+ UnicodeString calWOY;
+ int32_t actWOY = testCal->get(UCAL_WEEK_OF_YEAR,status);
+ if (actWOY < 1 || actWOY > 53) {
+ UDate d = testCal->getTime(status);
+ //calWOY = String.valueOf(actWOY);
+ UnicodeString temp;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ output = testDesc + " - " + sdf.format(d,temp,pos) + "\t";
+ output = output + "\t" + actWOY;
+ logln(output);
+ fail = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ int32_t DATA [] = {
+ 3, 52, 52, 52, 52, 52, 52, 52,
+ 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2,
+ 4, 52, 52, 52, 52, 52, 52, 52,
+ 53, 53, 53, 53, 53, 53, 53,
+ 1, 1, 1, 1, 1, 1, 1,
+ };
+ testCal->setFirstDayOfWeek(UCAL_SUNDAY);
+ for (int32_t j=0; j<44; j+=22) {
+ logln(UnicodeString("Minimal days in first week = ") + DATA[j] +
+ " Week starts on Sunday");
+ testCal->setMinimalDaysInFirstWeek((uint8_t)DATA[j]);
+ testCal->set(1997, UCAL_DECEMBER, 21);
+ for (int32_t i=0; i<21; ++i) {
+ int32_t woy = testCal->get(UCAL_WEEK_OF_YEAR,status);
+ str.remove();
+ log(UnicodeString("") + sdf.format(testCal->getTime(status), str) +
+ UnicodeString(" ") + woy);
+ if (woy != DATA[j + 1 + i]) {
+ log(" ERROR");
+ fail = TRUE;
+ }
+ logln("");
+
+ // Now compute the time from the fields, and make sure we
+ // get the same answer back. This is a round-trip test.
+ UDate save = testCal->getTime(status);
+ testCal->clear();
+ testCal->set(UCAL_YEAR_WOY, DATA[j+1+i] < 25 ? 1998 : 1997);
+ testCal->set(UCAL_WEEK_OF_YEAR, DATA[j+1+i]);
+ testCal->set(UCAL_DAY_OF_WEEK, (i%7) + UCAL_SUNDAY);
+ if (testCal->getTime(status) != save) {
+ str.remove();
+ logln(UnicodeString(" Parse failed: ") +
+ sdf.format(testCal->getTime(status), str));
+ fail= TRUE;
+ }
+
+ testCal->setTime(save,status);
+ testCal->add(UCAL_DATE, 1,status);
+ }
+ }
+ // Test field disambiguation with a few special hard-coded cases.
+ // This shouldn't fail if the above cases aren't failing.
+ int32_t DISAM_int [] = {
+ // y y_woy woy dow
+ 1997, 1998, 1, UCAL_SUNDAY,
+ (1998), (1998), (2), (UCAL_SATURDAY),
+ (1998), (1998), (53), (UCAL_THURSDAY),
+ (1999), (1998), (53), (UCAL_FRIDAY)
+ };
+
+ UDate DISAM_date [] = {
+ makeDate(1997, UCAL_DECEMBER, 28),
+ makeDate(1998, UCAL_JANUARY, 10),
+ makeDate(1998, UCAL_DECEMBER, 31),
+ makeDate(1999, UCAL_JANUARY, 1)
+ };
+
+ testCal->setMinimalDaysInFirstWeek(3);
+ testCal->setFirstDayOfWeek(UCAL_SUNDAY);
+ int32_t i = 0;
+
+ /* Enable this code to display various WOY values
+ testCal->clear();
+ for (i=25; i<38; ++i) {
+ testCal->set(1996, Calendar::DECEMBER, i);
+ UDate got = testCal->getTime(status);
+ str.remove();
+ logln(UnicodeString("") + sdf.format(got, str));
+ }
+ for (i=25; i<38; ++i) {
+ testCal->set(1997, Calendar::DECEMBER, i);
+ UDate got = testCal->getTime(status);
+ str.remove();
+ logln(UnicodeString("") + sdf.format(got, str));
+ }
+ for (i=25; i<38; ++i) {
+ testCal->set(1998, UCAL_DECEMBER, i);
+ UDate got = testCal->getTime(status);
+ str.remove();
+ logln(UnicodeString("") + sdf.format(got, str));
+ }
+ */
+
+ for (i=0; i < 16; i += 4) {
+ int32_t y = DISAM_int[i];
+ int32_t ywoy = DISAM_int[i+1];
+ int32_t woy = DISAM_int[i+2];
+ int32_t dow = DISAM_int[i+3];
+ UDate exp = DISAM_date[i/4];
+ testCal->clear();
+ testCal->set(UCAL_YEAR, y);
+ testCal->set(UCAL_WEEK_OF_YEAR, woy);
+ testCal->set(UCAL_DAY_OF_WEEK, dow);
+ UDate got = testCal->getTime(status);
+ str.remove();
+ str2.remove();
+ log(UnicodeString("Y") + y + "-W" + woy +
+ "-DOW" + dow + " expect:" + sdf.format(exp, str) +
+ " got:" + sdf.format(got, str2));
+ if (got != exp) {
+ log(" FAIL (%s:%d, i=%d)", __FILE__, __LINE__, i);
+ logln(CalendarTest::calToStr(*testCal));
+ testCal->setTime(exp, status);
+ logln(CalendarTest::calToStr(*testCal) + UnicodeString( " <<< expected "));
+ fail = TRUE;
+ }
+ logln("");
+
+ testCal->clear();
+ testCal->set(UCAL_YEAR_WOY, ywoy);
+ testCal->set(UCAL_WEEK_OF_YEAR, woy);
+ testCal->set(UCAL_DAY_OF_WEEK, dow);
+ got = testCal->getTime(status);
+ str.remove();
+ str2.remove();
+ log(UnicodeString("YWOY") + ywoy + "-W" + woy +
+ "-DOW" + dow + " expect:" + sdf.format(exp, str) +
+ " got:" + sdf.format(got, str2));
+ if (got != exp) {
+ log(" FAIL");
+ fail = TRUE;
+ }
+ logln("");
+ }
+ // Now try adding and rolling
+ UDate ADDROLL_date [] = {
+ makeDate(1998, UCAL_DECEMBER, 25), makeDate(1999, UCAL_JANUARY, 1),
+ makeDate(1997, UCAL_DECEMBER, 28), makeDate(1998, UCAL_JANUARY, 4),
+ makeDate(1998, UCAL_DECEMBER, 27), makeDate(1997, UCAL_DECEMBER, 28),
+ makeDate(1999, UCAL_JANUARY, 2), makeDate(1998, UCAL_JANUARY, 3),
+ };
+
+ int32_t ADDROLL_int []= {
+ (1),
+ (1),
+ (1),
+ (1)
+ };
+
+
+ UBool ADDROLL_bool [] = {
+ TRUE,//ADD,
+ TRUE,
+ FALSE,
+ FALSE
+ };
+
+ testCal->setMinimalDaysInFirstWeek(3);
+ testCal->setFirstDayOfWeek(UCAL_SUNDAY);
+ for (i=0; i<8; i += 2) {
+ int32_t amount = ADDROLL_int[i/2];
+ UDate before = ADDROLL_date[i];
+ UDate after = ADDROLL_date[i+1];
+
+ testCal->setTime(before,status);
+ if (ADDROLL_bool[i/2])
+ testCal->add(UCAL_WEEK_OF_YEAR, amount,status);
+ else
+ testCal->roll(UCAL_WEEK_OF_YEAR, amount,status);
+ UDate got = testCal->getTime(status);
+ str.remove();
+ str2.remove();
+ UnicodeString opTypeStr;
+ if (ADDROLL_bool[i/2]) {
+ opTypeStr = UnicodeString("add(WOY,", "");
+ } else {
+ opTypeStr = UnicodeString("roll(WOY,", "");
+ }
+ log(opTypeStr + amount + ") " + sdf.format(before, str) + " => " +
+ sdf.format(got, str2));
+ if (after != got) {
+ str.remove();
+ logln(UnicodeString(" exp:") + sdf.format(after, str) + " FAIL");
+ fail = TRUE;
+ }
+ else logln(" ok");
+
+ testCal->setTime(after,status);
+ if (ADDROLL_bool[i/2])
+ testCal->add(UCAL_WEEK_OF_YEAR, -amount,status);
+ else
+ testCal->roll(UCAL_WEEK_OF_YEAR, -amount,status);
+ got = testCal->getTime(status);
+ str.remove();
+ str2.remove();
+ log(opTypeStr + (-amount) + ") " + sdf.format(after, str) + " => " +
+ sdf.format(got, str2));
+ if (before != got) {
+ str.remove();
+ logln(UnicodeString(" exp:") + sdf.format(before, str) + " FAIL");
+ fail = TRUE;
+ }
+ else logln(" ok");
+ }
+ if (fail)
+ errln("Fail: Week of year misbehaving");
+}
+
+/**
+ * @bug 4106136
+ */
+void CalendarRegressionTest::test4106136()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Locale saveLocale = Locale::getDefault();
+ //try {
+ Locale locales [] = { Locale::getChinese(), Locale::getChina() };
+ for (int32_t i=0; i<2; ++i) {
+ Locale::setDefault(locales[i], status);
+ failure(status, "Locale::setDefault");
+ int32_t count1, count2, count3;
+ Calendar::getAvailableLocales(count1);
+ DateFormat::getAvailableLocales(count2);
+ NumberFormat::getAvailableLocales(count3);
+ int32_t n [] = {
+ count1, count2, count3
+ };
+ for (int32_t j=0; j<3; ++j) {
+ UnicodeString temp;
+ if (n[j] == 0)
+ errln(UnicodeString("Fail: No locales for ") + locales[i].getName());
+ }
+ }
+ //}
+ //finally {
+ Locale::setDefault(saveLocale,status);
+ //}
+}
+
+/**
+ * @bug 4108764
+ */
+void CalendarRegressionTest::test4108764()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ UDate d00 = makeDate(1997, UCAL_MARCH, 15, 12, 00, 00);
+ UDate d01 = makeDate(1997, UCAL_MARCH, 15, 12, 00, 56);
+ UDate d10 = makeDate(1997, UCAL_MARCH, 15, 12, 34, 00);
+ UDate d11 = makeDate(1997, UCAL_MARCH, 15, 12, 34, 56);
+ UDate epoch = makeDate(1970, UCAL_JANUARY, 1);
+
+ cal->setTime(d11,status);
+
+ cal->clear( UCAL_MINUTE );
+ logln(UnicodeString("") + cal->getTime(status));
+ if (cal->getTime(status) != d01)
+ errln("Fail: clear(MINUTE) broken");
+
+ cal->set( UCAL_SECOND, 0 );
+ logln(UnicodeString("") + cal->getTime(status));
+ if (cal->getTime(status) != d00)
+ errln("Fail: set(SECOND, 0) broken");
+
+ cal->setTime(d11,status);
+ cal->set( UCAL_SECOND, 0 );
+ logln(UnicodeString("") + cal->getTime(status));
+ if (cal->getTime(status) != d10)
+ errln("Fail: set(SECOND, 0) broken #2");
+
+ cal->clear( UCAL_MINUTE );
+ logln(UnicodeString("") + cal->getTime(status));
+ if (cal->getTime(status) != d00)
+ errln("Fail: clear(MINUTE) broken #2");
+
+ cal->clear();
+ logln(UnicodeString("") + cal->getTime(status));
+ if (cal->getTime(status) != epoch)
+ errln(UnicodeString("Fail: clear() broken Want ") + epoch);
+
+ delete cal;
+}
+
+/**
+ * @bug 4114578
+ */
+void CalendarRegressionTest::test4114578()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t ONE_HOUR = 60*60*1000;
+ Calendar *cal = Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ cal->adoptTimeZone(TimeZone::createTimeZone("PST"));
+ UDate onset = makeDate(1998, UCAL_APRIL, 5, 1, 0) + ONE_HOUR;
+ UDate cease = makeDate(1998, UCAL_OCTOBER, 25, 0, 0) + 2*ONE_HOUR;
+
+ UBool fail = FALSE;
+
+ const int32_t ADD = 1;
+ const int32_t ROLL = 2;
+
+ double DATA []= {
+ // Start Action Amt Expected_change
+ onset - ONE_HOUR, ADD, 1, ONE_HOUR,
+ onset, ADD, -1, -ONE_HOUR,
+ onset - ONE_HOUR, ROLL, 1, ONE_HOUR,
+ onset, ROLL, -1, -ONE_HOUR,
+ cease - ONE_HOUR, ADD, 1, ONE_HOUR,
+ cease, ADD, -1, -ONE_HOUR,
+ cease - ONE_HOUR, ROLL, 1, ONE_HOUR,
+ cease, ROLL, -1, -ONE_HOUR,
+ };
+
+ for (int32_t i=0; i<32; i+=4) {
+ UDate date = DATA[i];
+ int32_t amt = (int32_t) DATA[i+2];
+ double expectedChange = DATA[i+3];
+
+ log(UnicodeString("") + date);
+ cal->setTime(date,status);
+
+ switch ((int32_t) DATA[i+1]) {
+ case ADD:
+ log(UnicodeString(" add (HOUR,") + (amt<0?"":"+")+amt + ")= ");
+ cal->add(UCAL_HOUR, amt,status);
+ break;
+ case ROLL:
+ log(UnicodeString(" roll(HOUR,") + (amt<0?"":"+")+amt + ")= ");
+ cal->roll(UCAL_HOUR, amt,status);
+ break;
+ }
+
+ log(UnicodeString("") + cal->getTime(status));
+
+ double change = cal->getTime(status) - date;
+ if (change != expectedChange) {
+ fail = TRUE;
+ logln(" FAIL");
+ }
+ else logln(" OK");
+ }
+
+ if (fail) errln("Fail: roll/add misbehaves around DST onset/cease");
+
+ delete cal;
+}
+
+/**
+ * @bug 4118384
+ * Make sure maximum for HOUR field is 11, not 12.
+ */
+void CalendarRegressionTest::test4118384()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ if (cal->getMaximum(UCAL_HOUR) != 11 ||
+ cal->getLeastMaximum(UCAL_HOUR) != 11 ||
+ cal->getActualMaximum(UCAL_HOUR,status) != 11)
+ errln("Fail: maximum of HOUR field should be 11");
+
+ // test deprecated functions
+ if (cal->getLeastMaximum(Calendar::HOUR) != 11 ||
+ cal->getMaximum(Calendar::HOUR) != 11) {
+ errln("Fail: [deprecated functions] maximum of HOUR field should be 11\n");
+ }
+
+ if (cal->getGreatestMinimum(Calendar::HOUR) != 0 ||
+ cal->getMinimum(Calendar::HOUR) != 0) {
+ errln("Fail: [deprecated functions] minimum of HOUR field should be 1\n");
+ }
+
+ delete cal;
+ cal = Calendar::createInstance(Locale("th_TH@calendar=buddhist"),status);
+ // test deprecated functions
+ if (cal->getLeastMaximum(Calendar::HOUR) != 11 ||
+ cal->getMaximum(Calendar::HOUR) != 11) {
+ errln("Fail: Buddhist:[deprecated functions] maximum of HOUR field should be 11\n");
+ }
+
+ if (cal->getGreatestMinimum(Calendar::HOUR) != 0 ||
+ cal->getMinimum(Calendar::HOUR) != 0) {
+ errln("Fail: Buddhist:[deprecated functions] minimum of HOUR field should be 1\n");
+ }
+
+ delete cal;
+ // test deprecated functions
+ cal = Calendar::createInstance(Locale("ja_JP@calendar=japanese"),status);
+ if (cal->getLeastMaximum(Calendar::HOUR) != 11 ||
+ cal->getMaximum(Calendar::HOUR) != 11) {
+ errln("Fail: Japanese:[deprecated functions] maximum of HOUR field should be 11\n");
+ }
+
+ if (cal->getGreatestMinimum(Calendar::HOUR) != 0 ||
+ cal->getMinimum(Calendar::HOUR) != 0) {
+ errln("Fail: Japanese:[deprecated functions] minimum of HOUR field should be 1\n");
+ }
+
+ delete cal;
+}
+
+/**
+ * @bug 4125881
+ * Check isLeapYear for BC years.
+ */
+void CalendarRegressionTest::test4125881()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *cal = (GregorianCalendar*) Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ DateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"),status);
+ if(!assertSuccess("trying to construct", status))return;
+ cal->clear();
+ for (int32_t y=-20; y<=10; ++y) {
+ cal->set(UCAL_ERA, y < 1 ? GregorianCalendar::BC : GregorianCalendar::AD);
+ cal->set(UCAL_YEAR, y < 1 ? 1 - y : y);
+ UnicodeString temp;
+ logln(UnicodeString("") + y + UnicodeString(" = ") + fmt->format(cal->getTime(status), temp) + " " +
+ cal->isLeapYear(y));
+ if (cal->isLeapYear(y) != ((y+40)%4 == 0))
+ errln("Leap years broken");
+ }
+
+ delete cal;
+ delete fmt;
+}
+
+/**
+ * @bug 4125892
+ * Prove that GregorianCalendar is proleptic (it used to cut off
+ * at 45 BC, and not have leap years before then).
+ */
+void CalendarRegressionTest::test4125892() {
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *cal = (GregorianCalendar*) Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ DateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"),status);
+ if(!assertSuccess("trying to construct", status))return;
+ cal->clear();
+ cal->set(UCAL_ERA, GregorianCalendar::BC);
+ cal->set(UCAL_YEAR, 81); // 81 BC is a leap year (proleptically)
+ cal->set(UCAL_MONTH, UCAL_FEBRUARY);
+ cal->set(UCAL_DATE, 28);
+ cal->add(UCAL_DATE, 1,status);
+ if(U_FAILURE(status))
+ errln("add(DATE,1) failed");
+ if (cal->get(UCAL_DATE,status) != 29 ||
+ !cal->isLeapYear(-80)) // -80 == 81 BC
+ errln("Calendar not proleptic");
+
+ delete cal;
+ delete fmt;
+}
+
+/**
+ * @bug 4141665
+ * GregorianCalendar::equals() ignores cutover date
+ */
+void CalendarRegressionTest::test4141665()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *cal = new GregorianCalendar(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ GregorianCalendar *cal2 = (GregorianCalendar*)cal->clone();
+ UDate cut = cal->getGregorianChange();
+ UDate cut2 = cut + 100*24*60*60*1000.0; // 100 days later
+ if (*cal != *cal2) {
+ errln("Cloned GregorianCalendars not equal");
+ }
+ cal2->setGregorianChange(cut2,status);
+ if ( *cal == *cal2) {
+ errln("GregorianCalendar::equals() ignores cutover");
+ }
+
+ delete cal;
+ delete cal2;
+}
+
+/**
+ * @bug 4142933
+ * Bug states that ArrayIndexOutOfBoundsException is thrown by GregorianCalendar::roll()
+ * when IllegalArgumentException should be.
+ */
+void CalendarRegressionTest::test4142933()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *calendar = new GregorianCalendar(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete calendar;
+ return;
+ }
+ //try {
+ calendar->roll((UCalendarDateFields)-1, TRUE, status);
+ if(U_SUCCESS(status))
+ errln("Test failed, no exception thrown");
+ //}
+ //catch (IllegalArgumentException e) {
+ // OK: Do nothing
+ // logln("Test passed");
+ //}
+ //catch (Exception e) {
+ //errln("Test failed. Unexpected exception is thrown: " + e);
+ //e.printStackTrace();
+ //}
+
+ delete calendar;
+}
+
+/**
+ * @bug 4145158
+ * GregorianCalendar handling of Dates Long.MIN_VALUE and Long.MAX_VALUE is
+ * confusing; unless the time zone has a raw offset of zero, one or the
+ * other of these will wrap. We've modified the test given in the bug
+ * report to therefore only check the behavior of a calendar with a zero raw
+ * offset zone.
+ */
+void CalendarRegressionTest::test4145158()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *calendar = new GregorianCalendar(status);
+ if(status == U_USING_FALLBACK_WARNING || U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete calendar;
+ return;
+ }
+
+ calendar->adoptTimeZone(TimeZone::createTimeZone("GMT"));
+
+ calendar->setTime(makeDate(INT32_MIN),status);
+ int32_t year1 = calendar->get(UCAL_YEAR,status);
+ int32_t era1 = calendar->get(UCAL_ERA,status);
+
+ calendar->setTime(makeDate(INT32_MAX),status);
+ int32_t year2 = calendar->get(UCAL_YEAR,status);
+ int32_t era2 = calendar->get(UCAL_ERA,status);
+
+ if (year1 == year2 && era1 == era2) {
+ errln("Fail: Long.MIN_VALUE or Long.MAX_VALUE wrapping around");
+ }
+
+ delete calendar;
+}
+
+/**
+ * @bug 4145983
+ * Maximum value for YEAR field wrong.
+ */
+// {sfb} this is not directly applicable in C++, since all
+// possible doubles are not representable by our Calendar.
+// In Java, all longs are representable.
+// We can determine limits programmatically
+// Using DBL_MAX is a bit of a hack, since for large doubles
+// Calendar gets squirrely and doesn't behave in any sort
+// of linear fashion (ie years jump around, up/down, etc) for a
+// small change in millis.
+void CalendarRegressionTest::test4145983()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *calendar = new GregorianCalendar(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete calendar;
+ return;
+ }
+ calendar->adoptTimeZone(TimeZone::createTimeZone("GMT"));
+ UDate DATES [] = { LATEST_SUPPORTED_MILLIS, EARLIEST_SUPPORTED_MILLIS };
+ for (int32_t i=0; i<2; ++i) {
+ calendar->setTime(DATES[i], status);
+ int32_t year = calendar->get(UCAL_YEAR,status);
+ int32_t maxYear = calendar->getMaximum(UCAL_YEAR);
+ if (year > maxYear) {
+ errln(UnicodeString("Failed for ")+DATES[i]+" ms: year=" +
+ year + ", maxYear=" + maxYear);
+ }
+ }
+
+ delete calendar;
+}
+
+/**
+ * @bug 4147269
+ * This is a bug in the validation code of GregorianCalendar:: As reported,
+ * the bug seems worse than it really is, due to a bug in the way the bug
+ * report test was written. In reality the bug is restricted to the DAY_OF_YEAR
+ * field. - liu 6/29/98
+ */
+void CalendarRegressionTest::test4147269()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *calendar = new GregorianCalendar(status);
+ if(status == U_USING_FALLBACK_WARNING || U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete calendar;
+ return;
+ }
+ calendar->setLenient(FALSE);
+ UDate date = makeDate(1996, UCAL_JANUARY, 3); // Arbitrary date
+ for (int32_t field = 0; field < UCAL_FIELD_COUNT; field++) {
+ calendar->setTime(date,status);
+ // Note: In the bug report, getActualMaximum() was called instead
+ // of getMaximum() -- this was an error. The validation code doesn't
+ // use getActualMaximum(), since that's too costly.
+ int32_t max = calendar->getMaximum((UCalendarDateFields)field);
+ int32_t value = max+1;
+ calendar->set((UCalendarDateFields)field, value);
+ //try {
+ calendar->getTime(status); // Force time computation
+ // We expect an exception to be thrown. If we fall through
+ // to the next line, then we have a bug.
+ if(U_SUCCESS(status))
+ errln(UnicodeString("Test failed with field ") + FIELD_NAME[field] +
+ ", date before: " + date +
+ ", date after: " + calendar->getTime(status) +
+ ", value: " + value + " (max = " + max +")");
+ //} catch (IllegalArgumentException e) {}
+ }
+
+ delete calendar;
+}
+
+/**
+ * @bug 4149677
+ * Reported bug is that a GregorianCalendar with a cutover of Date(Long.MAX_VALUE)
+ * doesn't behave as a pure Julian calendar.
+ * CANNOT REPRODUCE THIS BUG
+ */
+void
+CalendarRegressionTest::Test4149677()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ TimeZone *zones [] = {
+ TimeZone::createTimeZone("GMT"),
+ TimeZone::createTimeZone("PST"),
+ TimeZone::createTimeZone("EAT")
+ };
+ if(U_FAILURE(status)) {
+ errln("Couldn't create zones");
+ return;
+ // could leak memory
+ }
+
+ for (int32_t i=0; i < 3; ++i) {
+ GregorianCalendar *calendar = new GregorianCalendar(zones[i], status);
+ if(U_FAILURE(status)) {
+ errln("Couldnt' create calendar.");
+ return;
+ }
+
+ // Make sure extreme values don't wrap around
+ calendar->setTime(EARLIEST_SUPPORTED_MILLIS, status);
+ if(U_FAILURE(status))
+ errln("setTime failed");
+ if (calendar->get(UCAL_ERA, status) != GregorianCalendar::BC || U_FAILURE(status)) {
+ errln("Fail: Date(EARLIEST_SUPPORTED_MILLIS) has an AD year");
+ }
+ calendar->setTime(LATEST_SUPPORTED_MILLIS, status);
+ if(U_FAILURE(status))
+ errln("setTime failed");
+ if (calendar->get(UCAL_ERA, status) != GregorianCalendar::AD || U_FAILURE(status)) {
+ errln("Fail: Date(LATEST_SUPPORTED_MILLIS) has a BC year");
+ }
+
+ calendar->setGregorianChange(LATEST_SUPPORTED_MILLIS, status);
+ if(U_FAILURE(status))
+ errln("setGregorianChange failed");
+ // to obtain a pure Julian calendar
+
+ UBool is100Leap = calendar->isLeapYear(100);
+ if (!is100Leap) {
+ UnicodeString temp;
+ errln("test failed with zone " + zones[i]->getID(temp));
+ errln(" cutover date is Date(Long.MAX_VALUE)");
+ errln(" isLeapYear(100) returns: " + is100Leap);
+ }
+ delete calendar;
+ }
+
+ // no need for cleanup- zones were adopted
+}
+
+/**
+ * @bug 4162587
+ * Calendar and Date HOUR broken. If HOUR is out-of-range, Calendar
+ * and Date classes will misbehave.
+ */
+void
+CalendarRegressionTest::Test4162587()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ TimeZone *savedef = TimeZone::createDefault();
+ TimeZone *tz = TimeZone::createTimeZone("PST");
+ //TimeZone::adoptDefault(tz);
+ TimeZone::setDefault(*tz);
+
+ GregorianCalendar *cal = new GregorianCalendar(tz, status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create calendar");
+ return;
+ }
+ UDate d0, dPlus, dMinus;
+
+ for(int32_t i=0; i<5; ++i) {
+ if (i>0) logln("---");
+
+ cal->clear();
+ cal->set(1998, UCAL_APRIL, 5, i, 0);
+ d0 = cal->getTime(status);
+ if(U_FAILURE(status))
+ errln("Coudln't get time (1)");
+ //String s0 = d.toString();
+ logln(UnicodeString("0 ") + i + ": " + d0/*s0*/);
+
+ cal->clear();
+ cal->set(1998, UCAL_APRIL, 4, i+24, 0);
+ dPlus = cal->getTime(status);
+ if(U_FAILURE(status))
+ errln("Coudln't get time (2)");
+ //String sPlus = d.toString();
+ logln(UnicodeString("+ ") + i + ": " + dPlus/*sPlus*/);
+
+ cal->clear();
+ cal->set(1998, UCAL_APRIL, 6, i-24, 0);
+ dMinus = cal->getTime(status);
+ if(U_FAILURE(status))
+ errln("Coudln't get time (3)");
+ //String sMinus = d.toString();
+ logln(UnicodeString("- ") + i + ": " + dMinus/*sMinus*/);
+
+ if (d0 != dPlus || d0 != dMinus) {
+ errln("Fail: All three lines must match");
+ }
+ }
+ TimeZone::setDefault(*savedef);
+ //delete tz;
+ delete cal;
+ delete savedef;
+}
+
+/**
+ * @bug 4165343
+ * Adding 12 months behaves differently from adding 1 year
+ */
+void
+CalendarRegressionTest::Test4165343()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *calendar = new GregorianCalendar(1996, UCAL_FEBRUARY, 29, status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create calendar");
+ return;
+ }
+ UDate start = calendar->getTime(status);
+ if(U_FAILURE(status))
+ errln("Couldn't getTime (1)");
+ logln(UnicodeString("init date: ") + start);
+ calendar->add(UCAL_MONTH, 12, status);
+ if(U_FAILURE(status))
+ errln("Couldn't add(MONTH, 12)");
+ UDate date1 = calendar->getTime(status);
+ if(U_FAILURE(status))
+ errln("Couldn't getTime (2)");
+ logln(UnicodeString("after adding 12 months: ") + date1);
+ calendar->setTime(start, status);
+ if(U_FAILURE(status))
+ errln("Couldn't setTime");
+ calendar->add(UCAL_YEAR, 1, status);
+ if(U_FAILURE(status))
+ errln("Couldn't add(YEAR, 1)");
+ UDate date2 = calendar->getTime(status);
+ if(U_FAILURE(status))
+ errln("Couldn't getTime (3)");
+ logln(UnicodeString("after adding one year : ") + date2);
+ if (date1 == date2) {
+ logln("Test passed");
+ } else {
+ errln("Test failed");
+ }
+ delete calendar;
+}
+
+/**
+ * @bug 4166109
+ * GregorianCalendar.getActualMaximum() does not account for first day of week.
+ */
+void
+CalendarRegressionTest::Test4166109()
+{
+ /* Test month:
+ *
+ * March 1998
+ * Su Mo Tu We Th Fr Sa
+ * 1 2 3 4 5 6 7
+ * 8 9 10 11 12 13 14
+ * 15 16 17 18 19 20 21
+ * 22 23 24 25 26 27 28
+ * 29 30 31
+ */
+ UBool passed = TRUE;
+ UErrorCode status = U_ZERO_ERROR;
+ UCalendarDateFields field = UCAL_WEEK_OF_MONTH;
+
+ GregorianCalendar *calendar = new GregorianCalendar(Locale::getUS(), status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create calendar");
+ return;
+ }
+ calendar->set(1998, UCAL_MARCH, 1);
+ calendar->setMinimalDaysInFirstWeek(1);
+ logln(UnicodeString("Date: ") + calendar->getTime(status)); // 888817448000
+
+ int32_t firstInMonth = calendar->get(UCAL_DATE, status);
+ if(U_FAILURE(status))
+ errln("get(D_O_M) failed");
+
+ for(int32_t firstInWeek = UCAL_SUNDAY; firstInWeek <= UCAL_SATURDAY; firstInWeek++) {
+ calendar->setFirstDayOfWeek((UCalendarDaysOfWeek)firstInWeek);
+ int32_t returned = calendar->getActualMaximum(field, status);
+ int32_t expected = (31 + ((firstInMonth - firstInWeek + 7)% 7) + 6) / 7;
+
+ logln(UnicodeString("First day of week = ") + firstInWeek +
+ " getActualMaximum(WEEK_OF_MONTH, status) = " + returned +
+ " expected = " + expected +
+ ((returned == expected) ? " ok" : " FAIL"));
+
+ if (returned != expected) {
+ passed = FALSE;
+ }
+ }
+ if (!passed) {
+ errln("Test failed");
+ }
+
+ delete calendar;
+}
+
+/**
+ * @bug 4167060
+ * Calendar.getActualMaximum(YEAR) works wrong.
+ */
+void
+CalendarRegressionTest::Test4167060()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UCalendarDateFields field = UCAL_YEAR;
+ DateFormat *format = new SimpleDateFormat(UnicodeString("EEE MMM dd HH:mm:ss zzz yyyy G"),
+ Locale::getUS(), status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat");
+ return;
+ }
+
+ GregorianCalendar *calendars [] = {
+ new GregorianCalendar(100, UCAL_NOVEMBER, 1, status),
+ new GregorianCalendar(-99 /*100BC*/, UCAL_JANUARY, 1, status),
+ new GregorianCalendar(1996, UCAL_FEBRUARY, 29, status),
+ };
+ if(U_FAILURE(status)) {
+ errln("Couldn't create GregorianCalendars");
+ return;
+ // could leak
+ }
+
+ UnicodeString id [] = { "Hybrid", "Gregorian", "Julian" };
+
+ for (int32_t k=0; k<3; ++k) {
+ logln("--- " + id[k] + " ---");
+
+ for (int32_t j=0; j < 3; ++j) {
+ GregorianCalendar *calendar = calendars[j];
+ if (k == 1) {
+ calendar->setGregorianChange(EARLIEST_SUPPORTED_MILLIS, status);
+ }
+ else if (k == 2) {
+ calendar->setGregorianChange(LATEST_SUPPORTED_MILLIS, status);
+ }
+
+ if(U_FAILURE(status))
+ errln("setGregorianChange() failed");
+ format->adoptCalendar((Calendar*)calendar->clone());
+
+ UDate dateBefore = calendar->getTime(status);
+ if(U_FAILURE(status))
+ errln("getTime() failed");
+
+ int32_t maxYear = calendar->getActualMaximum(field, status);
+ UnicodeString temp;
+ logln(UnicodeString("maxYear: ") + maxYear + " for " + format->format(calendar->getTime(status), temp));
+ temp.remove();
+ logln("date before: " + format->format(dateBefore, temp));
+
+ int32_t years[] = {2000, maxYear-1, maxYear, maxYear+1};
+
+ for (int32_t i = 0; i < 4; i++) {
+ UBool valid = years[i] <= maxYear;
+ calendar->set(field, years[i]);
+ UDate dateAfter = calendar->getTime(status);
+ if(U_FAILURE(status))
+ errln("getTime() failed");
+ int32_t newYear = calendar->get(field, status);
+ if(U_FAILURE(status))
+ errln(UnicodeString("get(") + (int32_t)field + ") failed");
+ calendar->setTime(dateBefore, status); // restore calendar for next use
+ if(U_FAILURE(status))
+ errln("setTime() failed");
+
+ temp.remove();
+ logln(UnicodeString(" Year ") + years[i] + (valid? " ok " : " bad") +
+ " => " + format->format(dateAfter, temp));
+ if (valid && newYear != years[i]) {
+ errln(UnicodeString(" FAIL: ") + newYear + " should be valid; date, month and time shouldn't change");
+ }
+ // {sfb} this next line is a hack, but it should work since if a
+ // double has an exponent, adding 1 should not yield the same double
+ else if (!valid && /*newYear == years[i]*/ dateAfter + 1.0 == dateAfter) {
+ errln(UnicodeString(" FAIL: ") + newYear + " should be invalid");
+ }
+ }
+ }
+ }
+
+ delete format;
+ delete calendars[0];
+ delete calendars[1];
+ delete calendars[2];
+}
+
+/**
+ * Week of year is wrong at the start and end of the year.
+ */
+void CalendarRegressionTest::Test4197699() {
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar cal(status);
+ cal.setFirstDayOfWeek(UCAL_MONDAY);
+ cal.setMinimalDaysInFirstWeek(4);
+ SimpleDateFormat fmt("E dd MMM yyyy 'DOY='D 'WOY='w",
+ Locale::getUS(), status);
+ fmt.setCalendar(cal);
+ if (U_FAILURE(status)) {
+ errln("Couldn't initialize test");
+ return;
+ }
+
+ int32_t DATA[] = {
+ 2000, UCAL_JANUARY, 1, 52,
+ 2001, UCAL_DECEMBER, 31, 1,
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+
+ UnicodeString str;
+ DateFormat& dfmt = *(DateFormat*)&fmt;
+ for (int32_t i=0; i<DATA_length; ) {
+ cal.clear();
+ cal.set(DATA[i], DATA[i+1], DATA[i+2]);
+ i += 3;
+ int32_t expWOY = DATA[i++];
+ int32_t actWOY = cal.get(UCAL_WEEK_OF_YEAR, status);
+ if (expWOY == actWOY) {
+ logln(UnicodeString("Ok: ") + dfmt.format(cal.getTime(status), str.remove()));
+ } else {
+ errln(UnicodeString("FAIL: ") + dfmt.format(cal.getTime(status), str.remove())
+ + ", expected WOY=" + expWOY);
+ cal.add(UCAL_DATE, -8, status);
+ for (int j=0; j<14; ++j) {
+ cal.add(UCAL_DATE, 1, status);
+ logln(dfmt.format(cal.getTime(status), str.remove()));
+ }
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: Unexpected error from Calendar");
+ return;
+ }
+ }
+}
+
+ enum Action { ADD=1, ROLL=2 };
+ enum Sign { PLUS=1, MINUS=2 };
+
+#define ONE_HOUR (60*60*1000)
+#define ONE_DAY (24*ONE_HOUR)
+
+ typedef struct {
+ UCalendarDateFields field;
+ int8_t actionMask; // ADD or ROLL or both
+ int8_t signMask; // PLUS or MINUS or both
+ int32_t amount;
+ int32_t before; // ms before cutover
+ int32_t after; // ms after cutover
+ } J81_DATA;
+
+/**
+ * Rolling and adding across the Gregorian cutover should work as expected.
+ * Jitterbug 81.
+ */
+void CalendarRegressionTest::TestJ81() {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString temp, temp2, temp3;
+ int32_t i;
+ GregorianCalendar cal(TimeZone::createTimeZone("GMT"), Locale::getUS(), status);
+ SimpleDateFormat fmt("HH:mm 'w'w 'd'D E d MMM yyyy", Locale::getUS(), status);
+ if (U_FAILURE(status)) {
+ errln("Error: Cannot create calendar or format");
+ return;
+ }
+ fmt.setCalendar(cal);
+ // Get the Gregorian cutover
+ UDate cutover = cal.getGregorianChange();
+ UDate days = ONE_DAY;
+ days = cutover/days;
+ logln(UnicodeString("Cutover: {") +
+ fmt.format(cutover, temp) + "}(epoch days-" + (int)days + ", jd" + (2440588 + days) +")");
+
+ // Check woy and doy handling. Reference data:
+ /* w40 d274 Mon 1 Oct 1582
+ w40 d275 Tue 2 Oct 1582
+ w40 d276 Wed 3 Oct 1582
+ w40 d277 Thu 4 Oct 1582
+ w40 d278 Fri 15 Oct 1582
+ w40 d279 Sat 16 Oct 1582
+ w41 d280 Sun 17 Oct 1582
+ w41 d281 Mon 18 Oct 1582
+ w41 d282 Tue 19 Oct 1582
+ w41 d283 Wed 20 Oct 1582
+ w41 d284 Thu 21 Oct 1582
+ w41 d285 Fri 22 Oct 1582
+ w41 d286 Sat 23 Oct 1582
+ w42 d287 Sun 24 Oct 1582
+ w42 d288 Mon 25 Oct 1582
+ w42 d289 Tue 26 Oct 1582
+ w42 d290 Wed 27 Oct 1582
+ w42 d291 Thu 28 Oct 1582
+ w42 d292 Fri 29 Oct 1582
+ w42 d293 Sat 30 Oct 1582
+ w43 d294 Sun 31 Oct 1582
+ w43 d295 Mon 1 Nov 1582 */
+ int32_t DOY_DATA[] = {
+ // dom, woy, doy
+ 1, 40, 274, UCAL_MONDAY,
+ 4, 40, 277, UCAL_THURSDAY,
+ 15, 40, 278, UCAL_FRIDAY,
+ 17, 41, 280, UCAL_SUNDAY,
+ 24, 42, 287, UCAL_SUNDAY,
+ 25, 42, 288, UCAL_MONDAY,
+ 26, 42, 289, UCAL_TUESDAY,
+ 27, 42, 290, UCAL_WEDNESDAY,
+ 28, 42, 291, UCAL_THURSDAY,
+ 29, 42, 292, UCAL_FRIDAY,
+ 30, 42, 293, UCAL_SATURDAY,
+ 31, 43, 294, UCAL_SUNDAY
+ };
+ int32_t DOY_DATA_length = (int32_t)(sizeof(DOY_DATA) / sizeof(DOY_DATA[0]));
+
+ for (i=0; i<DOY_DATA_length; i+=4) {
+ // Test time->fields
+ cal.set(1582, UCAL_OCTOBER, DOY_DATA[i]);
+ int32_t woy = cal.get(UCAL_WEEK_OF_YEAR, status);
+ int32_t doy = cal.get(UCAL_DAY_OF_YEAR, status);
+ int32_t dow = cal.get(UCAL_DAY_OF_WEEK, status);
+ if (U_FAILURE(status)) {
+ errln("Error: get() failed");
+ break;
+ }
+ if (woy != DOY_DATA[i+1] || doy != DOY_DATA[i+2] || dow != DOY_DATA[i+3]) {
+ errln((UnicodeString)"Fail: expect woy=" + DOY_DATA[i+1] +
+ ", doy=" + DOY_DATA[i+2] + ", dow=" + DOY_DATA[i+3] + " on " +
+ fmt.format(cal.getTime(status), temp.remove()) +
+ " set(1582,OCTOBER, " + DOY_DATA[i] + ")");
+ logln(CalendarTest::calToStr(cal));
+ status = U_ZERO_ERROR;
+ } else {
+ logln((UnicodeString)"PASS: expect woy=" + DOY_DATA[i+1] +
+ ", doy=" + DOY_DATA[i+2] + ", dow=" + DOY_DATA[i+3] + " on " +
+ fmt.format(cal.getTime(status), temp.remove()));
+ logln(CalendarTest::calToStr(cal));
+ status = U_ZERO_ERROR;
+ }
+ // Test fields->time for WOY
+ cal.clear();
+ cal.set(UCAL_YEAR, 1582);
+ cal.set(UCAL_WEEK_OF_YEAR, DOY_DATA[i+1]);
+ cal.set(UCAL_DAY_OF_WEEK, DOY_DATA[i+3]);
+ int32_t dom = cal.get(UCAL_DATE, status);
+ if (U_FAILURE(status)) {
+ errln("Error: get() failed");
+ break;
+ }
+ if (dom != DOY_DATA[i]) {
+ errln((UnicodeString)"Fail: set woy=" + DOY_DATA[i+1] +
+ " dow=" + DOY_DATA[i+3] + " => " +
+ fmt.format(cal.getTime(status), temp.remove()) +
+ ", expected 1582 Oct " + DOY_DATA[i]);
+ logln(CalendarTest::calToStr(cal));
+ status = U_ZERO_ERROR;
+ }
+
+ // Test fields->time for DOY
+ cal.clear();
+ cal.set(UCAL_YEAR, 1582);
+ cal.set(UCAL_DAY_OF_YEAR, DOY_DATA[i+2]);
+ dom = cal.get(UCAL_DATE, status);
+ if (U_FAILURE(status)) {
+ errln("Error: get() failed");
+ break;
+ }
+ if (dom != DOY_DATA[i]) {
+ errln((UnicodeString)"Fail: set doy=" + DOY_DATA[i+2] +
+ " => " +
+ fmt.format(cal.getTime(status), temp.remove()) +
+ ", expected 1582 Oct " + DOY_DATA[i]);
+ status = U_ZERO_ERROR;
+ }
+ }
+ status = U_ZERO_ERROR;
+
+#define ADD_ROLL ADD|ROLL
+#define PLUS_MINUS PLUS|MINUS
+ // Test cases
+ J81_DATA DATA[] = {
+ { UCAL_WEEK_OF_YEAR, ADD_ROLL, PLUS_MINUS, 1, -ONE_DAY, +6*ONE_DAY },
+ { UCAL_WEEK_OF_YEAR, ADD_ROLL, PLUS_MINUS, 1, -ONE_DAY, +6*ONE_DAY },
+ { UCAL_WEEK_OF_MONTH, ADD|ROLL, PLUS|MINUS, 1, -ONE_DAY, +6*ONE_DAY },
+ { UCAL_DATE, ADD|ROLL, PLUS|MINUS, 2, -ONE_DAY, +1*ONE_DAY },
+ { UCAL_DATE, ROLL, PLUS, -6, -ONE_DAY, +14*ONE_DAY },
+ { UCAL_DATE, ROLL, PLUS, -7, 0, +14*ONE_DAY },
+ { UCAL_DATE, ROLL, PLUS, -7, +ONE_DAY, +15*ONE_DAY },
+ { UCAL_DATE, ROLL, PLUS, +18, -ONE_DAY, -4*ONE_DAY },
+ { UCAL_DAY_OF_YEAR, ADD|ROLL, PLUS|MINUS, 2, -ONE_DAY, +1*ONE_DAY },
+ { UCAL_DAY_OF_WEEK, ADD|ROLL, PLUS|MINUS, 2, -ONE_DAY, +1*ONE_DAY },
+ { UCAL_DAY_OF_WEEK_IN_MONTH, ADD|ROLL, PLUS|MINUS, 1, -ONE_DAY, +6*ONE_DAY },
+ { UCAL_AM_PM, ADD, PLUS|MINUS, 4, -12*ONE_HOUR, +36*ONE_HOUR },
+ { UCAL_HOUR, ADD, PLUS|MINUS, 48, -12*ONE_HOUR, +36*ONE_HOUR },
+ { UCAL_HOUR_OF_DAY, ADD, PLUS|MINUS, 48, -12*ONE_HOUR, +36*ONE_HOUR },
+ { UCAL_MINUTE, ADD, PLUS|MINUS, 48*60, -12*ONE_HOUR, +36*ONE_HOUR },
+ { UCAL_SECOND, ADD, PLUS|MINUS, 48*60*60, -12*ONE_HOUR, +36*ONE_HOUR },
+ { UCAL_MILLISECOND, ADD, PLUS|MINUS, 48*ONE_HOUR, -12*ONE_HOUR, +36*ONE_HOUR },
+ // NOTE: These are not supported yet. See jitterbug 180.
+ // Uncomment these lines when add/roll supported on these fields.
+ // { Calendar::YEAR_WOY, ADD|ROLL, 1, -ONE_DAY, +6*ONE_DAY },
+ // { Calendar::DOW_LOCAL, ADD|ROLL, 2, -ONE_DAY, +1*ONE_DAY }
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+
+ // Now run the tests
+ for (i=0; i<DATA_length; ++i) {
+ for (Action action=ADD; action<=ROLL; action=(Action)(action+1)) {
+ if (!(DATA[i].actionMask & action)) {
+ continue;
+ }
+ for (Sign sign=PLUS; sign<=MINUS; sign=(Sign)(sign+1)) {
+ if (!(DATA[i].signMask & sign)) {
+ continue;
+ }
+ status = U_ZERO_ERROR;
+ int32_t amount = DATA[i].amount * (sign==MINUS?-1:1);
+ UDate date = cutover +
+ (sign==PLUS ? DATA[i].before : DATA[i].after);
+ UDate expected = cutover +
+ (sign==PLUS ? DATA[i].after : DATA[i].before);
+ cal.setTime(date, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: setTime returned error code " + u_errorName(status));
+ continue;
+ }
+ if (action == ADD) {
+ cal.add(DATA[i].field, amount, status);
+ } else {
+ cal.roll(DATA[i].field, amount, status);
+ }
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: " +
+ (action==ADD?"add ":"roll ") + FIELD_NAME[DATA[i].field] +
+ " returned error code " + u_errorName(status));
+ continue;
+ }
+ UDate result = cal.getTime(status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: getTime returned error code " + u_errorName(status));
+ continue;
+ }
+ if (result == expected) {
+ logln((UnicodeString)"Ok: {" +
+ fmt.format(date, temp.remove()) +
+ "}(" + date/ONE_DAY +
+ (action==ADD?") add ":") roll ") +
+ amount + " " + FIELD_NAME[DATA[i].field] + " -> {" +
+ fmt.format(result, temp2.remove()) +
+ "}(" + result/ONE_DAY + ")");
+ } else {
+ errln((UnicodeString)"FAIL: {" +
+ fmt.format(date, temp.remove()) +
+ "}(" + date/ONE_DAY +
+ (action==ADD?") add ":") roll ") +
+ amount + " " + FIELD_NAME[DATA[i].field] + " -> {" +
+ fmt.format(result, temp2.remove()) +
+ "}(" + result/ONE_DAY + "), expect {" +
+ fmt.format(expected, temp3.remove()) +
+ "}(" + expected/ONE_DAY + ")");
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Test fieldDifference().
+ */
+void CalendarRegressionTest::TestJ438(void) {
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t DATA[] = {
+ 2000, UCAL_JANUARY, 20, 2010, UCAL_JUNE, 15,
+ 2010, UCAL_JUNE, 15, 2000, UCAL_JANUARY, 20,
+ 1964, UCAL_SEPTEMBER, 7, 1999, UCAL_JUNE, 4,
+ 1999, UCAL_JUNE, 4, 1964, UCAL_SEPTEMBER, 7,
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA)/sizeof(DATA[0]));
+ Calendar* pcal = Calendar::createInstance(Locale::getUS(), ec);
+ if(U_FAILURE(ec)) {
+ errln("Error creating calendar %s", u_errorName(ec));
+ delete pcal;
+ return;
+ }
+ Calendar& cal = *pcal;
+ int32_t i;
+ SimpleDateFormat fmt(UnicodeString("MMM dd yyyy",""), ec);
+ fmt.setCalendar(cal);
+ UnicodeString s, t, u;
+ if (!failure(ec, "setup")) {
+ for (i=0; i<DATA_length; i+=6) {
+ int32_t y1 = DATA[i];
+ int32_t m1 = DATA[i+1];
+ int32_t d1 = DATA[i+2];
+ int32_t y2 = DATA[i+3];
+ int32_t m2 = DATA[i+4];
+ int32_t d2 = DATA[i+5];
+
+ cal.clear();
+ cal.set(y1, m1, d1);
+ UDate date1 = cal.getTime(ec);
+ if (failure(ec, "getTime"))
+ break;
+ cal.set(y2, m2, d2);
+ UDate date2 = cal.getTime(ec);
+ if (failure(ec, "getTime"))
+ break;
+
+ cal.setTime(date1, ec);
+ if (failure(ec, "setTime"))
+ break;
+ int32_t dy = cal.fieldDifference(date2, UCAL_YEAR, ec);
+ int32_t dm = cal.fieldDifference(date2, UCAL_MONTH, ec);
+ int32_t dd = cal.fieldDifference(date2, UCAL_DATE, ec);
+ if (failure(ec, "fieldDifference"))
+ break;
+
+ {
+ Calendar *cal2 = cal.clone();
+ UErrorCode ec2 = U_ZERO_ERROR;
+
+ cal2->setTime(date1, ec2);
+
+ int32_t dy2 = cal2->fieldDifference(date2, Calendar::YEAR, ec2);
+ int32_t dm2 = cal2->fieldDifference(date2, Calendar::MONTH, ec2);
+ int32_t dd2 = cal2->fieldDifference(date2, Calendar::DATE, ec2);
+ if (failure(ec2, "fieldDifference(date, Calendar::DATE, ec)"))
+ break;
+ if( (dd2 != dd) ||
+ (dm2 != dm) ||
+ (dy2 != dy)){
+ errln("fieldDifference(UCAL_...) and fieldDifference(Calendar::...) give different results!\n");
+ }
+ delete cal2;
+ }
+
+
+ logln(UnicodeString("") +
+ fmt.format(date2, s.remove()) + " - " +
+ fmt.format(date1, t.remove()) + " = " +
+ dy + "y " + dm + "m " + dd + "d");
+
+ cal.setTime(date1, ec);
+ if (failure(ec, "setTime"))
+ break;
+ cal.add(UCAL_YEAR, dy, ec);
+ cal.add(UCAL_MONTH, dm, ec);
+ cal.add(UCAL_DATE, dd, ec);
+ if (failure(ec, "add"))
+ break;
+ UDate date22 = cal.getTime(ec);
+ if (failure(ec, "getTime"))
+ break;
+ if (date2 != date22) {
+ errln(UnicodeString("FAIL: ") +
+ fmt.format(date1, s.remove()) + " + " +
+ dy + "y " + dm + "m " + dd + "d = " +
+ fmt.format(date22, t.remove()) + ", exp " +
+ fmt.format(date2, u.remove()));
+ } else {
+ logln(UnicodeString("Ok: ") +
+ fmt.format(date1, s.remove()) + " + " +
+ dy + "y " + dm + "m " + dd + "d = " +
+ fmt.format(date22, t.remove()));
+ }
+ }
+ }
+ delete pcal;
+}
+
+void CalendarRegressionTest::TestT5555()
+{
+ UErrorCode ec = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(ec);
+
+ if (cal == NULL || U_FAILURE(ec)) {
+ errln("FAIL: Calendar::createInstance()");
+ delete cal;
+ return;
+ }
+
+ // Set to Wednesday, February 21, 2007
+ cal->set(2007, UCAL_FEBRUARY, 21);
+
+ // Advance three years
+ cal->add(UCAL_MONTH, 36, ec);
+
+ // Set to last Wednesday of the month
+ cal->set(UCAL_DAY_OF_WEEK_IN_MONTH, -1);
+
+ cal->getTime(ec);
+
+ int32_t yy, mm, dd, ee;
+
+ yy = cal->get(UCAL_YEAR, ec);
+ mm = cal->get(UCAL_MONTH, ec);
+ dd = cal->get(UCAL_DATE, ec);
+ ee = cal->get(UCAL_DAY_OF_WEEK, ec);
+
+ // Should be set to Wednesday, February 24, 2010
+ if (U_FAILURE(ec) || yy != 2010 || mm != UCAL_FEBRUARY || dd != 24 || ee != UCAL_WEDNESDAY) {
+ errln("FAIL: got date %4d/%02d/%02d, expected 210/02/24: ", yy, mm + 1, dd);
+ }
+ delete cal;
+}
+
+/**
+ * Test behavior of fieldDifference around leap years. Also test a large
+ * field difference to check binary search.
+ */
+void CalendarRegressionTest::TestLeapFieldDifference() {
+ UErrorCode ec = U_ZERO_ERROR;
+ Calendar* cal = Calendar::createInstance(ec);
+ if (cal == NULL || U_FAILURE(ec)) {
+ errln("FAIL: Calendar::createInstance()");
+ delete cal;
+ return;
+ }
+ cal->set(2004, UCAL_FEBRUARY, 29);
+ UDate date2004 = cal->getTime(ec);
+ cal->set(2000, UCAL_FEBRUARY, 29);
+ UDate date2000 = cal->getTime(ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: getTime()");
+ delete cal;
+ return;
+ }
+ int32_t y = cal->fieldDifference(date2004, UCAL_YEAR, ec);
+ int32_t d = cal->fieldDifference(date2004, UCAL_DAY_OF_YEAR, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: fieldDifference()");
+ delete cal;
+ return;
+ }
+ if (d == 0) {
+ logln((UnicodeString)"Ok: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days");
+ } else {
+ errln((UnicodeString)"FAIL: 2004/Feb/29 - 2000/Feb/29 = " + y + " years, " + d + " days");
+ }
+ cal->setTime(date2004, ec);
+ y = cal->fieldDifference(date2000, UCAL_YEAR, ec);
+ d = cal->fieldDifference(date2000, UCAL_DAY_OF_YEAR, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: setTime() / fieldDifference()");
+ delete cal;
+ return;
+ }
+ if (d == 0) {
+ logln((UnicodeString)"Ok: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days");
+ } else {
+ errln((UnicodeString)"FAIL: 2000/Feb/29 - 2004/Feb/29 = " + y + " years, " + d + " days");
+ }
+ // Test large difference
+ cal->set(2001, UCAL_APRIL, 5); // 2452005
+ UDate ayl = cal->getTime(ec);
+ cal->set(1964, UCAL_SEPTEMBER, 7); // 2438646
+ UDate asl = cal->getTime(ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: getTime()");
+ delete cal;
+ return;
+ }
+ d = cal->fieldDifference(ayl, UCAL_DATE, ec);
+ cal->setTime(ayl, ec);
+ int32_t d2 = cal->fieldDifference(asl, UCAL_DATE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: setTime() / fieldDifference()");
+ delete cal;
+ return;
+ }
+ if (d == -d2 && d == 13359) {
+ logln((UnicodeString)"Ok: large field difference symmetrical " + d);
+ } else {
+ logln((UnicodeString)"FAIL: large field difference incorrect " + d + ", " + d2 +
+ ", expect +/- 13359");
+ }
+ delete cal;
+}
+
+/**
+ * Test ms_MY "Malay (Malaysia)" locale. Bug 1543.
+ */
+void CalendarRegressionTest::TestMalaysianInstance() {
+ Locale loc("ms", "MY"); // Malay (Malaysia)
+ UErrorCode ec = U_ZERO_ERROR;
+ Calendar* cal = Calendar::createInstance(loc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Can't construct calendar for ms_MY");
+ }
+ delete cal;
+}
+
+/**
+ * setFirstDayOfWeek and setMinimalDaysInFirstWeek may change the
+ * field <=> time mapping, since they affect the interpretation of
+ * the WEEK_OF_MONTH or WEEK_OF_YEAR fields.
+ */
+void CalendarRegressionTest::TestWeekShift() {
+ UErrorCode ec = U_ZERO_ERROR;
+ GregorianCalendar cal(TimeZone::createTimeZone("America/Los_Angeles"),
+ Locale("en", "US"), ec);
+ cal.setTime(UDate(997257600000.0), ec); // Wed Aug 08 01:00:00 PDT 2001
+ // In pass one, change the first day of week so that the weeks
+ // shift in August 2001. In pass two, change the minimal days
+ // in the first week so that the weeks shift in August 2001.
+ // August 2001
+ // Su Mo Tu We Th Fr Sa
+ // 1 2 3 4
+ // 5 6 7 8 9 10 11
+ // 12 13 14 15 16 17 18
+ // 19 20 21 22 23 24 25
+ // 26 27 28 29 30 31
+ for (int32_t pass=0; pass<2; ++pass) {
+ if (pass==0) {
+ cal.setFirstDayOfWeek(UCAL_WEDNESDAY);
+ cal.setMinimalDaysInFirstWeek(4);
+ } else {
+ cal.setFirstDayOfWeek(UCAL_SUNDAY);
+ cal.setMinimalDaysInFirstWeek(4);
+ }
+ cal.add(UCAL_DATE, 1, ec); // Force recalc
+ cal.add(UCAL_DATE, -1, ec);
+
+ UDate time1 = cal.getTime(ec); // Get time -- should not change
+
+ // Now change a week parameter and then force a recalc.
+ // The bug is that the recalc should not be necessary --
+ // calendar should do so automatically.
+ if (pass==0) {
+ cal.setFirstDayOfWeek(UCAL_THURSDAY);
+ } else {
+ cal.setMinimalDaysInFirstWeek(5);
+ }
+
+ int32_t woy1 = cal.get(UCAL_WEEK_OF_YEAR, ec);
+ int32_t wom1 = cal.get(UCAL_WEEK_OF_MONTH, ec);
+
+ cal.add(UCAL_DATE, 1, ec); // Force recalc
+ cal.add(UCAL_DATE, -1, ec);
+
+ int32_t woy2 = cal.get(UCAL_WEEK_OF_YEAR, ec);
+ int32_t wom2 = cal.get(UCAL_WEEK_OF_MONTH, ec);
+
+ UDate time2 = cal.getTime(ec);
+
+ if (U_FAILURE(ec)) {
+ errln("FAIL: internal test error");
+ return;
+ }
+
+ if (time1 != time2) {
+ errln("FAIL: shifting week should not alter time");
+ } else {
+ // logln(time1);
+ }
+ if (woy1 == woy2 && wom1 == wom2) {
+ logln((UnicodeString)"Ok: WEEK_OF_YEAR: " + woy1 +
+ ", WEEK_OF_MONTH: " + wom1);
+ } else {
+ errln((UnicodeString)"FAIL: WEEK_OF_YEAR: " + woy1 + " => " + woy2 +
+ ", WEEK_OF_MONTH: " + wom1 + " => " + wom2 +
+ " after week shift");
+ }
+ }
+}
+
+/**
+ * Make sure that when adding a day, we actually wind up in a
+ * different day. The DST adjustments we use to keep the hour
+ * constant across DST changes can backfire and change the day.
+ */
+void CalendarRegressionTest::TestTimeZoneTransitionAdd() {
+ UErrorCode ec = U_ZERO_ERROR;
+ Locale locale(Locale::getUS()); // could also be CHINA
+ SimpleDateFormat dateFormat("MM/dd/yyyy HH:mm z", locale, ec);
+
+ StringEnumeration *tz = TimeZone::createEnumeration();
+ if (tz == NULL) {
+ errln("FAIL: TimeZone::createEnumeration");
+ return;
+ }
+
+ UnicodeString buf1, buf2;
+
+ const UChar* id;
+ while ((id = tz->unext(NULL, ec)) != NULL && U_SUCCESS(ec)) {
+ if (U_FAILURE(ec)) {
+ errln("FAIL: StringEnumeration::unext");
+ break;
+ }
+
+ TimeZone *t = TimeZone::createTimeZone(id);
+ if (t == NULL) {
+ errln("FAIL: TimeZone::createTimeZone");
+ break;
+ }
+ dateFormat.setTimeZone(*t);
+
+ Calendar *cal = Calendar::createInstance(t, locale, ec);
+ if (cal == NULL || U_FAILURE(ec)) {
+ errln("FAIL: Calendar::createTimeZone");
+ delete cal;
+ break;
+ }
+
+ cal->clear();
+ // Scan the year 2003, overlapping the edges of the year
+ cal->set(UCAL_YEAR, 2002);
+ cal->set(UCAL_MONTH, UCAL_DECEMBER);
+ cal->set(UCAL_DATE, 25);
+
+ for (int32_t i=0; i<365+10 && U_SUCCESS(ec); ++i) {
+ UDate yesterday = cal->getTime(ec);
+ int32_t yesterday_day = cal->get(UCAL_DATE, ec);
+ cal->add(UCAL_DATE, 1, ec);
+ if (yesterday_day == cal->get(UCAL_DATE, ec)) {
+ errln(UnicodeString(id) + " " +
+ dateFormat.format(yesterday, buf1) + " +1d= " +
+ dateFormat.format(cal->getTime(ec), buf2));
+ buf1.truncate(0);
+ buf2.truncate(0);
+ }
+ }
+ delete cal;
+ }
+
+ if (U_FAILURE(ec)) {
+ errln("FAIL: %s", u_errorName(ec));
+ }
+
+ delete tz;
+}
+
+UDate
+CalendarRegressionTest::makeDate(int32_t y, int32_t m, int32_t d,
+ int32_t hr, int32_t min, int32_t sec)
+{
+ UDate result;
+
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(status);
+ cal->clear();
+
+ cal->set(UCAL_YEAR, y);
+
+ if(m != 0) cal->set(UCAL_MONTH, m);
+ if(d != 0) cal->set(UCAL_DATE, d);
+ if(hr != 0) cal->set(UCAL_HOUR, hr);
+ if(min != 0) cal->set(UCAL_MINUTE, min);
+ if(sec != 0) cal->set(UCAL_SECOND, sec);
+
+ result = cal->getTime(status);
+
+ delete cal;
+
+ return result;
+}
+
+void CalendarRegressionTest::TestDeprecates(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *c1 = Calendar::createInstance("ja_JP@calendar=japanese",status);
+ Calendar *c2 = Calendar::createInstance("ja_JP_TRADITIONAL",status);
+
+ if(!c1 || !c2 || U_FAILURE(status)) {
+ errln("Couldn't create calendars for roll of HOUR");
+ return;
+ }
+
+ c2->set(UCAL_HOUR,2);
+ c1->setTime(c2->getTime(status),status);
+ // *c1 = *c2;
+
+ c1->roll(Calendar::HOUR,(int32_t)3,status);
+ c2->roll(UCAL_HOUR,(int32_t)3,status);
+
+ if(U_FAILURE(status)) {
+ errln("Error code when trying to roll");
+ } else if(*c1 != *c2) {
+ errln("roll(EDateField, int32_t) had different effect than roll(UCalendarField, int32_t)");
+ }
+
+ c1->setTime(c2->getTime(status),status);
+ c1->roll(Calendar::HOUR,(UBool)FALSE,status);
+ c2->roll(UCAL_HOUR,(UBool)FALSE,status);
+
+ if(U_FAILURE(status)) {
+ errln("Error code when trying to roll(UBool)");
+ } else if(*c1 != *c2) {
+ errln("roll(EDateField, UBool) had different effect than roll(UCalendarField, UBool)");
+ }
+
+ delete c1;
+ delete c2;
+
+ status = U_ZERO_ERROR;
+
+ c1 = Calendar::createInstance("th_TH_TRADITIONAL",status);
+ c2 = Calendar::createInstance("th_TH@calendar=buddhist",status);
+
+ if(!c1 || !c2 || U_FAILURE(status)) {
+ errln("Couldn't create calendars for add of HOUR");
+ return;
+ }
+
+ c2->set(UCAL_HOUR,2);
+ c1->setTime(c2->getTime(status),status);
+ //*c1 = *c2;
+
+ c1->add(Calendar::HOUR,(int32_t)1,status);
+
+ if(U_FAILURE(status)) {
+ errln("Error code when trying to add Calendar::HOUR - %s", u_errorName(status));
+ }
+
+ c2->add(UCAL_HOUR,(int32_t)1,status);
+
+ if(U_FAILURE(status)) {
+ errln("Error code when trying to add - UCAL_HOUR %s", u_errorName(status));
+ } else if(*c1 != *c2) {
+ errln("add(EDateField) had different effect than add(UCalendarField)");
+ }
+
+ delete c1;
+ delete c2;
+
+ status = U_ZERO_ERROR;
+
+ c1 = Calendar::createInstance("es_ES",status);
+ c2 = Calendar::createInstance("es_ES",status);
+
+ if(!c1 || !c2 || U_FAILURE(status)) {
+ errln("Couldn't create calendars for add of YEAR");
+ return;
+ }
+
+ c2->set(UCAL_YEAR,1900);
+ c1->setTime(c2->getTime(status),status);
+ //*c1 = *c2;
+
+ c1->add(Calendar::YEAR,(int32_t)9,status);
+ c2->add(UCAL_YEAR,(int32_t)9,status);
+
+ if(U_FAILURE(status)) {
+ errln("Error code when trying to add YEARs");
+ } else if(*c1 != *c2) {
+ errln("add(EDateField YEAR) had different effect than add(UCalendarField YEAR)");
+ }
+
+ delete c1;
+ delete c2;
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/calregts.h b/Build/source/libs/icu/icu-xetex/test/intltest/calregts.h
new file mode 100644
index 00000000000..7133ffa3b3a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/calregts.h
@@ -0,0 +1,92 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _CALENDARREGRESSIONTEST_
+#define _CALENDARREGRESSIONTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "intltest.h"
+
+/**
+ * Performs regression test for Calendar
+ **/
+class CalendarRegressionTest: public IntlTest {
+
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+ void test4100311(void);
+ void test4074758(void);
+ void test4028518(void);
+ void test4031502(void) ;
+ void test4035301(void) ;
+ void test4040996(void) ;
+ void test4051765(void) ;
+ void test4059654(void) ;
+ void test4061476(void) ;
+ void test4070502(void) ;
+ void test4071197(void) ;
+ void test4071385(void) ;
+ void test4073929(void) ;
+ void test4083167(void) ;
+ void test4086724(void) ;
+ void test4092362(void) ;
+ void test4095407(void) ;
+ void test4096231(void) ;
+ void test4096539(void) ;
+ void test41003112(void) ;
+ void test4103271(void) ;
+ void test4106136(void) ;
+ void test4108764(void) ;
+ void test4114578(void) ;
+ void test4118384(void) ;
+ void test4125881(void) ;
+ void test4125892(void) ;
+ void test4141665(void) ;
+ void test4142933(void) ;
+ void test4145158(void) ;
+ void test4145983(void) ;
+ void test4147269(void) ;
+
+ void Test4149677(void) ;
+ void Test4162587(void) ;
+ void Test4165343(void) ;
+ void Test4166109(void) ;
+ void Test4167060(void) ;
+ void Test4197699(void);
+ void TestJ81(void);
+ void TestJ438(void);
+ void TestT5555(void);
+ void TestLeapFieldDifference(void);
+ void TestMalaysianInstance(void);
+ void TestWeekShift(void);
+ void TestTimeZoneTransitionAdd(void);
+ void TestDeprecates(void);
+
+ void printdate(GregorianCalendar *cal, const char *string);
+ void dowTest(UBool lenient) ;
+
+
+ static UDate getAssociatedDate(UDate d, UErrorCode& status);
+ static UDate makeDate(int32_t y, int32_t m = 0, int32_t d = 0, int32_t hr = 0, int32_t min = 0, int32_t sec = 0);
+
+ static const UDate EARLIEST_SUPPORTED_MILLIS;
+ static const UDate LATEST_SUPPORTED_MILLIS;
+ static const char* FIELD_NAME[];
+
+protected:
+ UBool failure(UErrorCode status, const char* msg);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _CALENDARREGRESSIONTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/caltest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/caltest.cpp
new file mode 100644
index 00000000000..070564fcd37
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/caltest.cpp
@@ -0,0 +1,1994 @@
+/************************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ************************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "caltest.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/gregocal.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/simpletz.h"
+#include "unicode/dbgutil.h"
+
+// *****************************************************************************
+// class CalendarTest
+// *****************************************************************************
+
+UnicodeString CalendarTest::calToStr(const Calendar & cal)
+{
+ UnicodeString out;
+ UErrorCode status = U_ZERO_ERROR;
+ int i;
+ UDate d;
+ for(i = 0;i<UCAL_FIELD_COUNT;i++) {
+ out += (UnicodeString("") + fieldName((UCalendarDateFields)i) + "=" + cal.get((UCalendarDateFields)i, status) + UnicodeString(" "));
+ }
+ out += "[" + UnicodeString(cal.getType()) + "]";
+
+ if(cal.inDaylightTime(status)) {
+ out += UnicodeString(" (in DST), zone=");
+ }
+ else {
+ out += UnicodeString(", zone=");
+ }
+
+ UnicodeString str2;
+ out += cal.getTimeZone().getDisplayName(str2);
+ d = cal.getTime(status);
+ out += UnicodeString(" :","") + d;
+
+ return out;
+}
+
+void CalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite TestCalendar");
+ switch (index) {
+ case 0:
+ name = "TestDOW943";
+ if (exec) {
+ logln("TestDOW943---"); logln("");
+ TestDOW943();
+ }
+ break;
+ case 1:
+ name = "TestClonesUnique908";
+ if (exec) {
+ logln("TestClonesUnique908---"); logln("");
+ TestClonesUnique908();
+ }
+ break;
+ case 2:
+ name = "TestGregorianChange768";
+ if (exec) {
+ logln("TestGregorianChange768---"); logln("");
+ TestGregorianChange768();
+ }
+ break;
+ case 3:
+ name = "TestDisambiguation765";
+ if (exec) {
+ logln("TestDisambiguation765---"); logln("");
+ TestDisambiguation765();
+ }
+ break;
+ case 4:
+ name = "TestGMTvsLocal4064654";
+ if (exec) {
+ logln("TestGMTvsLocal4064654---"); logln("");
+ TestGMTvsLocal4064654();
+ }
+ break;
+ case 5:
+ name = "TestAddSetOrder621";
+ if (exec) {
+ logln("TestAddSetOrder621---"); logln("");
+ TestAddSetOrder621();
+ }
+ break;
+ case 6:
+ name = "TestAdd520";
+ if (exec) {
+ logln("TestAdd520---"); logln("");
+ TestAdd520();
+ }
+ break;
+ case 7:
+ name = "TestFieldSet4781";
+ if (exec) {
+ logln("TestFieldSet4781---"); logln("");
+ TestFieldSet4781();
+ }
+ break;
+ case 8:
+ name = "TestSerialize337";
+ if (exec) {
+ logln("TestSerialize337---"); logln("");
+ // TestSerialize337();
+ }
+ break;
+ case 9:
+ name = "TestSecondsZero121";
+ if (exec) {
+ logln("TestSecondsZero121---"); logln("");
+ TestSecondsZero121();
+ }
+ break;
+ case 10:
+ name = "TestAddSetGet0610";
+ if (exec) {
+ logln("TestAddSetGet0610---"); logln("");
+ TestAddSetGet0610();
+ }
+ break;
+ case 11:
+ name = "TestFields060";
+ if (exec) {
+ logln("TestFields060---"); logln("");
+ TestFields060();
+ }
+ break;
+ case 12:
+ name = "TestEpochStartFields";
+ if (exec) {
+ logln("TestEpochStartFields---"); logln("");
+ TestEpochStartFields();
+ }
+ break;
+ case 13:
+ name = "TestDOWProgression";
+ if (exec) {
+ logln("TestDOWProgression---"); logln("");
+ TestDOWProgression();
+ }
+ break;
+ case 14:
+ name = "TestGenericAPI";
+ if (exec) {
+ logln("TestGenericAPI---"); logln("");
+ TestGenericAPI();
+ }
+ break;
+ case 15:
+ name = "TestAddRollExtensive";
+ if (exec) {
+ logln("TestAddRollExtensive---"); logln("");
+ TestAddRollExtensive();
+ }
+ break;
+ case 16:
+ name = "TestDOW_LOCALandYEAR_WOY";
+ if (exec) {
+ logln("TestDOW_LOCALandYEAR_WOY---"); logln("");
+ TestDOW_LOCALandYEAR_WOY();
+ }
+ break;
+ case 17:
+ name = "TestWOY";
+ if (exec) {
+ logln("TestWOY---"); logln("");
+ TestWOY();
+ }
+ break;
+ case 18:
+ name = "TestRog";
+ if (exec) {
+ logln("TestRog---"); logln("");
+ TestRog();
+ }
+ break;
+ case 19:
+ name = "TestYWOY";
+ if (exec) {
+ logln("TestYWOY---"); logln("");
+ TestYWOY();
+ }
+ break;
+ case 20:
+ name = "TestJD";
+ if(exec) {
+ logln("TestJD---"); logln("");
+ TestJD();
+ }
+ break;
+ case 21:
+ name = "TestDebug";
+ if(exec) {
+ logln("TestDebug---"); logln("");
+ TestDebug();
+ }
+ break;
+
+ default: name = ""; break;
+ }
+}
+
+// ---------------------------------------------------------------------------------
+
+UnicodeString CalendarTest::fieldName(UCalendarDateFields f) {
+ switch (f) {
+#define FIELD_NAME_STR(x) case x: return (#x+5)
+ FIELD_NAME_STR( UCAL_ERA );
+ FIELD_NAME_STR( UCAL_YEAR );
+ FIELD_NAME_STR( UCAL_MONTH );
+ FIELD_NAME_STR( UCAL_WEEK_OF_YEAR );
+ FIELD_NAME_STR( UCAL_WEEK_OF_MONTH );
+ FIELD_NAME_STR( UCAL_DATE );
+ FIELD_NAME_STR( UCAL_DAY_OF_YEAR );
+ FIELD_NAME_STR( UCAL_DAY_OF_WEEK );
+ FIELD_NAME_STR( UCAL_DAY_OF_WEEK_IN_MONTH );
+ FIELD_NAME_STR( UCAL_AM_PM );
+ FIELD_NAME_STR( UCAL_HOUR );
+ FIELD_NAME_STR( UCAL_HOUR_OF_DAY );
+ FIELD_NAME_STR( UCAL_MINUTE );
+ FIELD_NAME_STR( UCAL_SECOND );
+ FIELD_NAME_STR( UCAL_MILLISECOND );
+ FIELD_NAME_STR( UCAL_ZONE_OFFSET );
+ FIELD_NAME_STR( UCAL_DST_OFFSET );
+ FIELD_NAME_STR( UCAL_YEAR_WOY );
+ FIELD_NAME_STR( UCAL_DOW_LOCAL );
+ FIELD_NAME_STR( UCAL_EXTENDED_YEAR );
+ FIELD_NAME_STR( UCAL_JULIAN_DAY );
+ FIELD_NAME_STR( UCAL_MILLISECONDS_IN_DAY );
+#undef FIELD_NAME_STR
+ default:
+ return UnicodeString("") + ((int32_t)f);
+ }
+}
+
+/**
+ * Test various API methods for API completeness.
+ */
+void
+CalendarTest::TestGenericAPI()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UDate d;
+ UnicodeString str;
+ UBool eq = FALSE,b4 = FALSE,af = FALSE;
+
+ UDate when = date(90, UCAL_APRIL, 15);
+
+ UnicodeString tzid("TestZone");
+ int32_t tzoffset = 123400;
+
+ SimpleTimeZone *zone = new SimpleTimeZone(tzoffset, tzid);
+ Calendar *cal = Calendar::createInstance(zone->clone(), status);
+ if (failure(status, "Calendar::createInstance")) return;
+
+ if (*zone != cal->getTimeZone()) errln("FAIL: Calendar::getTimeZone failed");
+
+ Calendar *cal2 = Calendar::createInstance(cal->getTimeZone(), status);
+ if (failure(status, "Calendar::createInstance")) return;
+ cal->setTime(when, status);
+ cal2->setTime(when, status);
+ if (failure(status, "Calendar::setTime")) return;
+
+ if (!(*cal == *cal2)) errln("FAIL: Calendar::operator== failed");
+ if ((*cal != *cal2)) errln("FAIL: Calendar::operator!= failed");
+ if (!cal->equals(*cal2, status) ||
+ cal->before(*cal2, status) ||
+ cal->after(*cal2, status) ||
+ U_FAILURE(status)) errln("FAIL: equals/before/after failed");
+
+ logln(UnicodeString("cal=") +cal->getTime(status) + UnicodeString(calToStr(*cal)));
+ logln(UnicodeString("cal2=") +cal2->getTime(status) + UnicodeString(calToStr(*cal2)));
+ logln("cal2->setTime(when+1000)");
+ cal2->setTime(when + 1000, status);
+ logln(UnicodeString("cal2=") +cal2->getTime(status) + UnicodeString(calToStr(*cal2)));
+
+ if (failure(status, "Calendar::setTime")) return;
+ if (cal->equals(*cal2, status) ||
+ cal2->before(*cal, status) ||
+ cal->after(*cal2, status) ||
+ U_FAILURE(status)) errln("FAIL: equals/before/after failed after setTime(+1000)");
+
+ logln("cal1->roll(UCAL_SECOND)");
+ cal->roll(UCAL_SECOND, (UBool) TRUE, status);
+ logln(UnicodeString("cal=") +cal->getTime(status) + UnicodeString(calToStr(*cal)));
+
+ if (failure(status, "Calendar::roll")) return;
+ if (!(eq=cal->equals(*cal2, status)) ||
+ (b4=cal->before(*cal2, status)) ||
+ (af=cal->after(*cal2, status)) ||
+ U_FAILURE(status)) {
+ errln("FAIL: equals[%c]/before[%c]/after[%c] failed after roll 1 second [should be T/F/F]",
+ eq?'T':'F',
+ b4?'T':'F',
+ af?'T':'F');
+ logln(UnicodeString("cal=") +cal->getTime(status) + UnicodeString(calToStr(*cal)));
+ logln(UnicodeString("cal2=") +cal2->getTime(status) + UnicodeString(calToStr(*cal2)));
+ }
+
+ // Roll back to January
+ cal->roll(UCAL_MONTH, (int32_t)(1 + UCAL_DECEMBER - cal->get(UCAL_MONTH, status)), status);
+ if (failure(status, "Calendar::roll")) return;
+ if (cal->equals(*cal2, status) ||
+ cal2->before(*cal, status) ||
+ cal->after(*cal2, status) ||
+ U_FAILURE(status)) errln("FAIL: equals/before/after failed after rollback to January");
+
+ TimeZone *z = cal->orphanTimeZone();
+ if (z->getID(str) != tzid ||
+ z->getRawOffset() != tzoffset)
+ errln("FAIL: orphanTimeZone failed");
+
+ int32_t i;
+ for (i=0; i<2; ++i)
+ {
+ UBool lenient = ( i > 0 );
+ cal->setLenient(lenient);
+ if (lenient != cal->isLenient()) errln("FAIL: setLenient/isLenient failed");
+ // Later: Check for lenient behavior
+ }
+
+ for (i=UCAL_SUNDAY; i<=UCAL_SATURDAY; ++i)
+ {
+ cal->setFirstDayOfWeek((UCalendarDaysOfWeek)i);
+ if (cal->getFirstDayOfWeek() != i) errln("FAIL: set/getFirstDayOfWeek failed");
+ UErrorCode aStatus = U_ZERO_ERROR;
+ if (cal->getFirstDayOfWeek(aStatus) != i || U_FAILURE(aStatus)) errln("FAIL: getFirstDayOfWeek(status) failed");
+ }
+
+ for (i=1; i<=7; ++i)
+ {
+ cal->setMinimalDaysInFirstWeek((uint8_t)i);
+ if (cal->getMinimalDaysInFirstWeek() != i) errln("FAIL: set/getFirstDayOfWeek failed");
+ }
+
+ for (i=0; i<UCAL_FIELD_COUNT; ++i)
+ {
+ if (cal->getMinimum((UCalendarDateFields)i) != cal->getGreatestMinimum((UCalendarDateFields)i))
+ errln("FAIL: getMinimum doesn't match getGreatestMinimum for field " + i);
+ if (cal->getLeastMaximum((UCalendarDateFields)i) > cal->getMaximum((UCalendarDateFields)i))
+ errln("FAIL: getLeastMaximum larger than getMaximum for field " + i);
+ if (cal->getMinimum((UCalendarDateFields)i) >= cal->getMaximum((UCalendarDateFields)i))
+ errln("FAIL: getMinimum not less than getMaximum for field " + i);
+ }
+
+ cal->adoptTimeZone(TimeZone::createDefault());
+ cal->clear();
+ cal->set(1984, 5, 24);
+ if (cal->getTime(status) != date(84, 5, 24) || U_FAILURE(status))
+ errln("FAIL: Calendar::set(3 args) failed");
+
+ cal->clear();
+ cal->set(1985, 3, 2, 11, 49);
+ if (cal->getTime(status) != date(85, 3, 2, 11, 49) || U_FAILURE(status))
+ errln("FAIL: Calendar::set(5 args) failed");
+
+ cal->clear();
+ cal->set(1995, 9, 12, 1, 39, 55);
+ if (cal->getTime(status) != date(95, 9, 12, 1, 39, 55) || U_FAILURE(status))
+ errln("FAIL: Calendar::set(6 args) failed");
+
+ cal->getTime(status);
+ if (failure(status, "Calendar::getTime")) return;
+ for (i=0; i<UCAL_FIELD_COUNT; ++i)
+ {
+ switch(i) {
+ case UCAL_YEAR: case UCAL_MONTH: case UCAL_DATE:
+ case UCAL_HOUR_OF_DAY: case UCAL_MINUTE: case UCAL_SECOND:
+ case UCAL_EXTENDED_YEAR:
+ if (!cal->isSet((UCalendarDateFields)i)) errln("FAIL: Calendar::isSet F, should be T " + fieldName((UCalendarDateFields)i));
+ break;
+ default:
+ if (cal->isSet((UCalendarDateFields)i)) errln("FAIL: Calendar::isSet = T, should be F " + fieldName((UCalendarDateFields)i));
+ }
+ cal->clear((UCalendarDateFields)i);
+ if (cal->isSet((UCalendarDateFields)i)) errln("FAIL: Calendar::clear/isSet failed " + fieldName((UCalendarDateFields)i));
+ }
+
+ delete cal;
+ delete cal2;
+
+ int32_t count;
+ const Locale* loc = Calendar::getAvailableLocales(count);
+ if (count < 1 || loc == 0)
+ {
+ errln("FAIL: getAvailableLocales failed");
+ }
+ else
+ {
+ for (i=0; i<count; ++i)
+ {
+ cal = Calendar::createInstance(loc[i], status);
+ if (failure(status, "Calendar::createInstance")) return;
+ delete cal;
+ }
+ }
+
+ cal = Calendar::createInstance(TimeZone::createDefault(), Locale::getEnglish(), status);
+ if (failure(status, "Calendar::createInstance")) return;
+ delete cal;
+
+ cal = Calendar::createInstance(*zone, Locale::getEnglish(), status);
+ if (failure(status, "Calendar::createInstance")) return;
+ delete cal;
+
+ GregorianCalendar *gc = new GregorianCalendar(*zone, status);
+ if (failure(status, "new GregorianCalendar")) return;
+ delete gc;
+
+ gc = new GregorianCalendar(Locale::getEnglish(), status);
+ if (failure(status, "new GregorianCalendar")) return;
+ delete gc;
+
+ gc = new GregorianCalendar(Locale::getEnglish(), status);
+ delete gc;
+
+ gc = new GregorianCalendar(*zone, Locale::getEnglish(), status);
+ if (failure(status, "new GregorianCalendar")) return;
+ delete gc;
+
+ gc = new GregorianCalendar(zone, status);
+ if (failure(status, "new GregorianCalendar")) return;
+ delete gc;
+
+ gc = new GregorianCalendar(1998, 10, 14, 21, 43, status);
+ if (gc->getTime(status) != (d =date(98, 10, 14, 21, 43) )|| U_FAILURE(status))
+ errln("FAIL: new GregorianCalendar(ymdhm) failed with " + UnicodeString(u_errorName(status)) + ", cal=" + gc->getTime(status) + UnicodeString(calToStr(*gc)) + ", d=" + d);
+ else
+ logln(UnicodeString("GOOD: cal=") +gc->getTime(status) + UnicodeString(calToStr(*gc)) + ", d=" + d);
+ delete gc;
+
+ gc = new GregorianCalendar(1998, 10, 14, 21, 43, 55, status);
+ if (gc->getTime(status) != (d=date(98, 10, 14, 21, 43, 55)) || U_FAILURE(status))
+ errln("FAIL: new GregorianCalendar(ymdhms) failed with " + UnicodeString(u_errorName(status)));
+
+ GregorianCalendar gc2(Locale::getEnglish(), status);
+ if (failure(status, "new GregorianCalendar")) return;
+ gc2 = *gc;
+ if (gc2 != *gc || !(gc2 == *gc)) errln("FAIL: GregorianCalendar assignment/operator==/operator!= failed");
+ delete gc;
+ delete z;
+}
+
+// -------------------------------------
+
+/**
+ * This test confirms the correct behavior of add when incrementing
+ * through subsequent days.
+ */
+void
+CalendarTest::TestRog()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar* gc = new GregorianCalendar(status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ int32_t year = 1997, month = UCAL_APRIL, date = 1;
+ gc->set(year, month, date);
+ gc->set(UCAL_HOUR_OF_DAY, 23);
+ gc->set(UCAL_MINUTE, 0);
+ gc->set(UCAL_SECOND, 0);
+ gc->set(UCAL_MILLISECOND, 0);
+ for (int32_t i = 0; i < 9; i++, gc->add(UCAL_DATE, 1, status)) {
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ if (gc->get(UCAL_YEAR, status) != year ||
+ gc->get(UCAL_MONTH, status) != month ||
+ gc->get(UCAL_DATE, status) != (date + i)) errln("FAIL: Date wrong");
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ }
+ delete gc;
+}
+
+// -------------------------------------
+
+/**
+ * Test the handling of the day of the week, checking for correctness and
+ * for correct minimum and maximum values.
+ */
+void
+CalendarTest::TestDOW943()
+{
+ dowTest(FALSE);
+ dowTest(TRUE);
+}
+
+void CalendarTest::dowTest(UBool lenient)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar* cal = new GregorianCalendar(status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ logln("cal - Aug 12, 1997\n");
+ cal->set(1997, UCAL_AUGUST, 12);
+ cal->getTime(status);
+ if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
+ logln((lenient?UnicodeString("LENIENT0: "):UnicodeString("nonlenient0: ")) + UnicodeString(calToStr(*cal)));
+ cal->setLenient(lenient);
+ logln("cal - Dec 1, 1996\n");
+ cal->set(1996, UCAL_DECEMBER, 1);
+ logln((lenient?UnicodeString("LENIENT: "):UnicodeString("nonlenient: ")) + UnicodeString(calToStr(*cal)));
+ int32_t dow = cal->get(UCAL_DAY_OF_WEEK, status);
+ if (U_FAILURE(status)) { errln("Calendar::get failed [%s]", u_errorName(status)); return; }
+ int32_t min = cal->getMinimum(UCAL_DAY_OF_WEEK);
+ int32_t max = cal->getMaximum(UCAL_DAY_OF_WEEK);
+ if (dow < min ||
+ dow > max) errln(UnicodeString("FAIL: Day of week ") + (int32_t)dow + " out of range");
+ if (dow != UCAL_SUNDAY) errln("FAIL: Day of week should be SUNDAY[%d] not %d", UCAL_SUNDAY, dow);
+ if (min != UCAL_SUNDAY ||
+ max != UCAL_SATURDAY) errln("FAIL: Min/max bad");
+ delete cal;
+}
+
+// -------------------------------------
+
+/**
+ * Confirm that cloned Calendar objects do not inadvertently share substructures.
+ */
+void
+CalendarTest::TestClonesUnique908()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *c = Calendar::createInstance(status);
+ if (U_FAILURE(status)) { errln("Calendar::createInstance failed"); return; }
+ Calendar *d = (Calendar*) c->clone();
+ c->set(UCAL_MILLISECOND, 123);
+ d->set(UCAL_MILLISECOND, 456);
+ if (c->get(UCAL_MILLISECOND, status) != 123 ||
+ d->get(UCAL_MILLISECOND, status) != 456) {
+ errln("FAIL: Clones share fields");
+ }
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ delete c;
+ delete d;
+}
+
+// -------------------------------------
+
+/**
+ * Confirm that the Gregorian cutoff value works as advertised.
+ */
+void
+CalendarTest::TestGregorianChange768()
+{
+ UBool b;
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString str;
+ GregorianCalendar* c = new GregorianCalendar(status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ logln(UnicodeString("With cutoff ") + dateToString(c->getGregorianChange(), str));
+ b = c->isLeapYear(1800);
+ logln(UnicodeString(" isLeapYear(1800) = ") + (b ? "true" : "false"));
+ logln(UnicodeString(" (should be FALSE)"));
+ if (b) errln("FAIL");
+ c->setGregorianChange(date(0, 0, 1), status);
+ if (U_FAILURE(status)) { errln("GregorianCalendar::setGregorianChange failed"); return; }
+ logln(UnicodeString("With cutoff ") + dateToString(c->getGregorianChange(), str));
+ b = c->isLeapYear(1800);
+ logln(UnicodeString(" isLeapYear(1800) = ") + (b ? "true" : "false"));
+ logln(UnicodeString(" (should be TRUE)"));
+ if (!b) errln("FAIL");
+ delete c;
+}
+
+// -------------------------------------
+
+/**
+ * Confirm the functioning of the field disambiguation algorithm.
+ */
+void
+CalendarTest::TestDisambiguation765()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *c = Calendar::createInstance("en_US", status);
+ if (U_FAILURE(status)) { errln("Calendar::createInstance failed"); return; }
+ c->setLenient(FALSE);
+ c->clear();
+ c->set(UCAL_YEAR, 1997);
+ c->set(UCAL_MONTH, UCAL_JUNE);
+ c->set(UCAL_DATE, 3);
+ verify765("1997 third day of June = ", c, 1997, UCAL_JUNE, 3);
+ c->clear();
+ c->set(UCAL_YEAR, 1997);
+ c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
+ c->set(UCAL_MONTH, UCAL_JUNE);
+ c->set(UCAL_DAY_OF_WEEK_IN_MONTH, 1);
+ verify765("1997 first Tuesday in June = ", c, 1997, UCAL_JUNE, 3);
+ c->clear();
+ c->set(UCAL_YEAR, 1997);
+ c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
+ c->set(UCAL_MONTH, UCAL_JUNE);
+ c->set(UCAL_DAY_OF_WEEK_IN_MONTH, - 1);
+ verify765("1997 last Tuesday in June = ", c, 1997, UCAL_JUNE, 24);
+ // IllegalArgumentException e = null;
+ status = U_ZERO_ERROR;
+ //try {
+ c->clear();
+ c->set(UCAL_YEAR, 1997);
+ c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
+ c->set(UCAL_MONTH, UCAL_JUNE);
+ c->set(UCAL_DAY_OF_WEEK_IN_MONTH, 0);
+ c->getTime(status);
+ //}
+ //catch(IllegalArgumentException ex) {
+ // e = ex;
+ //}
+ verify765("1997 zero-th Tuesday in June = ", status);
+ c->clear();
+ c->set(UCAL_YEAR, 1997);
+ c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
+ c->set(UCAL_MONTH, UCAL_JUNE);
+ c->set(UCAL_WEEK_OF_MONTH, 1);
+ verify765("1997 Tuesday in week 1 of June = ", c, 1997, UCAL_JUNE, 3);
+ c->clear();
+ c->set(UCAL_YEAR, 1997);
+ c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
+ c->set(UCAL_MONTH, UCAL_JUNE);
+ c->set(UCAL_WEEK_OF_MONTH, 5);
+ verify765("1997 Tuesday in week 5 of June = ", c, 1997, UCAL_JULY, 1);
+ status = U_ZERO_ERROR;
+ //try {
+ c->clear();
+ c->set(UCAL_YEAR, 1997);
+ c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
+ c->set(UCAL_MONTH, UCAL_JUNE);
+ c->set(UCAL_WEEK_OF_MONTH, 0);
+ verify765("1997 Tuesday in week 0 of June = ", c, 1997, UCAL_MAY, 27);
+ //}
+ //catch(IllegalArgumentException ex) {
+ // errln("FAIL: Exception seen:");
+ // ex.printStackTrace(log);
+ //}
+ /* Note: The following test used to expect YEAR 1997, WOY 1 to
+ * resolve to a date in Dec 1996; that is, to behave as if
+ * YEAR_WOY were 1997. With the addition of a new explicit
+ * YEAR_WOY field, YEAR_WOY must itself be set if that is what is
+ * desired. Using YEAR in combination with WOY is ambiguous, and
+ * results in the first WOY/DOW day of the year satisfying the
+ * given fields (there may be up to two such days). In this case,
+ * it propertly resolves to Tue Dec 30 1997, which has a WOY value
+ * of 1 (for YEAR_WOY 1998) and a DOW of Tuesday, and falls in the
+ * _calendar_ year 1997, as specified. - aliu */
+ c->clear();
+ c->set(UCAL_YEAR_WOY, 1997); // aliu
+ c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
+ c->set(UCAL_WEEK_OF_YEAR, 1);
+ verify765("1997 Tuesday in week 1 of yearWOY = ", c, 1996, UCAL_DECEMBER, 31);
+ c->clear(); // - add test for YEAR
+ c->set(UCAL_YEAR, 1997);
+ c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
+ c->set(UCAL_WEEK_OF_YEAR, 1);
+ verify765("1997 Tuesday in week 1 of year = ", c, 1997, UCAL_DECEMBER, 30);
+ c->clear();
+ c->set(UCAL_YEAR, 1997);
+ c->set(UCAL_DAY_OF_WEEK, UCAL_TUESDAY);
+ c->set(UCAL_WEEK_OF_YEAR, 10);
+ verify765("1997 Tuesday in week 10 of year = ", c, 1997, UCAL_MARCH, 4);
+ //try {
+
+ // {sfb} week 0 is no longer a valid week of year
+ /*c->clear();
+ c->set(Calendar::YEAR, 1997);
+ c->set(Calendar::DAY_OF_WEEK, Calendar::TUESDAY);
+ //c->set(Calendar::WEEK_OF_YEAR, 0);
+ c->set(Calendar::WEEK_OF_YEAR, 1);
+ verify765("1997 Tuesday in week 0 of year = ", c, 1996, Calendar::DECEMBER, 24);*/
+
+ //}
+ //catch(IllegalArgumentException ex) {
+ // errln("FAIL: Exception seen:");
+ // ex.printStackTrace(log);
+ //}
+ delete c;
+}
+
+// -------------------------------------
+
+void
+CalendarTest::verify765(const UnicodeString& msg, Calendar* c, int32_t year, int32_t month, int32_t day)
+{
+ UnicodeString str;
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t y = c->get(UCAL_YEAR, status);
+ int32_t m = c->get(UCAL_MONTH, status);
+ int32_t d = c->get(UCAL_DATE, status);
+ if ( y == year &&
+ m == month &&
+ d == day) {
+ if (U_FAILURE(status)) { errln("FAIL: Calendar::get failed"); return; }
+ logln("PASS: " + msg + dateToString(c->getTime(status), str));
+ if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
+ }
+ else {
+ errln("FAIL: " + msg + dateToString(c->getTime(status), str) + "; expected " + (int32_t)year + "/" + (int32_t)(month + 1) + "/" + (int32_t)day +
+ "; got " + (int32_t)y + "/" + (int32_t)(m + 1) + "/" + (int32_t)d + " for Locale: " + c->getLocaleID(ULOC_ACTUAL_LOCALE,status));
+ if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
+ }
+}
+
+// -------------------------------------
+
+void
+CalendarTest::verify765(const UnicodeString& msg/*, IllegalArgumentException e*/, UErrorCode status)
+{
+ if (status != U_ILLEGAL_ARGUMENT_ERROR) errln("FAIL: No IllegalArgumentException for " + msg);
+ else logln("PASS: " + msg + "IllegalArgument as expected");
+}
+
+// -------------------------------------
+
+/**
+ * Confirm that the offset between local time and GMT behaves as expected.
+ */
+void
+CalendarTest::TestGMTvsLocal4064654()
+{
+ test4064654(1997, 1, 1, 12, 0, 0);
+ test4064654(1997, 4, 16, 18, 30, 0);
+}
+
+// -------------------------------------
+
+void
+CalendarTest::test4064654(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn, int32_t sc)
+{
+ UDate date;
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString str;
+ Calendar *gmtcal = Calendar::createInstance(status);
+ if (U_FAILURE(status)) { errln("Calendar::createInstance failed"); return; }
+ gmtcal->adoptTimeZone(TimeZone::createTimeZone("Africa/Casablanca"));
+ gmtcal->set(yr, mo - 1, dt, hr, mn, sc);
+ gmtcal->set(UCAL_MILLISECOND, 0);
+ date = gmtcal->getTime(status);
+ if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
+ logln("date = " + dateToString(date, str));
+ Calendar *cal = Calendar::createInstance(status);
+ if (U_FAILURE(status)) { errln("Calendar::createInstance failed"); return; }
+ cal->setTime(date, status);
+ if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
+ int32_t offset = cal->getTimeZone().getOffset((uint8_t)cal->get(UCAL_ERA, status),
+ cal->get(UCAL_YEAR, status),
+ cal->get(UCAL_MONTH, status),
+ cal->get(UCAL_DATE, status),
+ (uint8_t)cal->get(UCAL_DAY_OF_WEEK, status),
+ cal->get(UCAL_MILLISECOND, status), status);
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ logln("offset for " + dateToString(date, str) + "= " + (offset / 1000 / 60 / 60.0) + "hr");
+ int32_t utc = ((cal->get(UCAL_HOUR_OF_DAY, status) * 60 +
+ cal->get(UCAL_MINUTE, status)) * 60 +
+ cal->get(UCAL_SECOND, status)) * 1000 +
+ cal->get(UCAL_MILLISECOND, status) - offset;
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ int32_t expected = ((hr * 60 + mn) * 60 + sc) * 1000;
+ if (utc != expected) errln(UnicodeString("FAIL: Discrepancy of ") + (utc - expected) +
+ " millis = " + ((utc - expected) / 1000 / 60 / 60.0) + " hr");
+ delete gmtcal;
+ delete cal;
+}
+
+// -------------------------------------
+
+/**
+ * The operations of adding and setting should not exhibit pathological
+ * dependence on the order of operations. This test checks for this.
+ */
+void
+CalendarTest::TestAddSetOrder621()
+{
+ UDate d = date(97, 4, 14, 13, 23, 45);
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(status);
+ if (U_FAILURE(status)) {
+ errln("Calendar::createInstance failed");
+ delete cal;
+ return;
+ }
+ cal->setTime(d, status);
+ if (U_FAILURE(status)) {
+ errln("Calendar::setTime failed");
+ delete cal;
+ return;
+ }
+ cal->add(UCAL_DATE, - 5, status);
+ if (U_FAILURE(status)) {
+ errln("Calendar::add failed");
+ delete cal;
+ return;
+ }
+ cal->set(UCAL_HOUR_OF_DAY, 0);
+ cal->set(UCAL_MINUTE, 0);
+ cal->set(UCAL_SECOND, 0);
+ UnicodeString s;
+ dateToString(cal->getTime(status), s);
+ if (U_FAILURE(status)) {
+ errln("Calendar::getTime failed");
+ delete cal;
+ return;
+ }
+ delete cal;
+
+ cal = Calendar::createInstance(status);
+ if (U_FAILURE(status)) {
+ errln("Calendar::createInstance failed");
+ delete cal;
+ return;
+ }
+ cal->setTime(d, status);
+ if (U_FAILURE(status)) {
+ errln("Calendar::setTime failed");
+ delete cal;
+ return;
+ }
+ cal->set(UCAL_HOUR_OF_DAY, 0);
+ cal->set(UCAL_MINUTE, 0);
+ cal->set(UCAL_SECOND, 0);
+ cal->add(UCAL_DATE, - 5, status);
+ if (U_FAILURE(status)) {
+ errln("Calendar::add failed");
+ delete cal;
+ return;
+ }
+ UnicodeString s2;
+ dateToString(cal->getTime(status), s2);
+ if (U_FAILURE(status)) {
+ errln("Calendar::getTime failed");
+ delete cal;
+ return;
+ }
+ if (s == s2)
+ logln("Pass: " + s + " == " + s2);
+ else
+ errln("FAIL: " + s + " != " + s2);
+ delete cal;
+}
+
+// -------------------------------------
+
+/**
+ * Confirm that adding to various fields works.
+ */
+void
+CalendarTest::TestAdd520()
+{
+ int32_t y = 1997, m = UCAL_FEBRUARY, d = 1;
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *temp = new GregorianCalendar(y, m, d, status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ check520(temp, y, m, d);
+ temp->add(UCAL_YEAR, 1, status);
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ y++;
+ check520(temp, y, m, d);
+ temp->add(UCAL_MONTH, 1, status);
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ m++;
+ check520(temp, y, m, d);
+ temp->add(UCAL_DATE, 1, status);
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ d++;
+ check520(temp, y, m, d);
+ temp->add(UCAL_DATE, 2, status);
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ d += 2;
+ check520(temp, y, m, d);
+ temp->add(UCAL_DATE, 28, status);
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ d = 1;++m;
+ check520(temp, y, m, d);
+ delete temp;
+}
+
+// -------------------------------------
+
+/**
+ * Execute adding and rolling in GregorianCalendar extensively,
+ */
+void
+CalendarTest::TestAddRollExtensive()
+{
+ int32_t maxlimit = 40;
+ int32_t y = 1997, m = UCAL_FEBRUARY, d = 1, hr = 1, min = 1, sec = 0, ms = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *temp = new GregorianCalendar(y, m, d, status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+
+ temp->set(UCAL_HOUR, hr);
+ temp->set(UCAL_MINUTE, min);
+ temp->set(UCAL_SECOND, sec);
+ temp->set(UCAL_MILLISECOND, ms);
+
+ UCalendarDateFields e;
+
+ logln("Testing GregorianCalendar add...");
+ e = UCAL_YEAR;
+ while (e < UCAL_FIELD_COUNT) {
+ int32_t i;
+ int32_t limit = maxlimit;
+ status = U_ZERO_ERROR;
+ for (i = 0; i < limit; i++) {
+ temp->add(e, 1, status);
+ if (U_FAILURE(status)) { limit = i; status = U_ZERO_ERROR; }
+ }
+ for (i = 0; i < limit; i++) {
+ temp->add(e, -1, status);
+ if (U_FAILURE(status)) { errln("GregorianCalendar::add -1 failed"); return; }
+ }
+ check520(temp, y, m, d, hr, min, sec, ms, e);
+
+ e = (UCalendarDateFields) ((int32_t) e + 1);
+ }
+
+ logln("Testing GregorianCalendar roll...");
+ e = UCAL_YEAR;
+ while (e < UCAL_FIELD_COUNT) {
+ int32_t i;
+ int32_t limit = maxlimit;
+ status = U_ZERO_ERROR;
+ for (i = 0; i < limit; i++) {
+ logln(calToStr(*temp) + UnicodeString(" " ) + fieldName(e) + UnicodeString("++") );
+ temp->roll(e, 1, status);
+ if (U_FAILURE(status)) {
+ logln("caltest.cpp:%d e=%d, i=%d - roll(+) err %s\n", __LINE__, (int) e, (int) i, u_errorName(status));
+ logln(calToStr(*temp));
+ limit = i; status = U_ZERO_ERROR;
+ }
+ }
+ for (i = 0; i < limit; i++) {
+ logln("caltest.cpp:%d e=%d, i=%d\n", __LINE__, (int) e, (int) i);
+ logln(calToStr(*temp) + UnicodeString(" " ) + fieldName(e) + UnicodeString("--") );
+ temp->roll(e, -1, status);
+ if (U_FAILURE(status)) { errln(UnicodeString("GregorianCalendar::roll ") + CalendarTest::fieldName(e) + " count=" + UnicodeString('@'+i) + " by -1 failed with " + u_errorName(status) ); return; }
+ }
+ check520(temp, y, m, d, hr, min, sec, ms, e);
+
+ e = (UCalendarDateFields) ((int32_t) e + 1);
+ }
+
+ delete temp;
+}
+
+// -------------------------------------
+void
+CalendarTest::check520(Calendar* c,
+ int32_t y, int32_t m, int32_t d,
+ int32_t hr, int32_t min, int32_t sec,
+ int32_t ms, UCalendarDateFields field)
+
+{
+ UErrorCode status = U_ZERO_ERROR;
+ if (c->get(UCAL_YEAR, status) != y ||
+ c->get(UCAL_MONTH, status) != m ||
+ c->get(UCAL_DATE, status) != d ||
+ c->get(UCAL_HOUR, status) != hr ||
+ c->get(UCAL_MINUTE, status) != min ||
+ c->get(UCAL_SECOND, status) != sec ||
+ c->get(UCAL_MILLISECOND, status) != ms) {
+ errln(UnicodeString("U_FAILURE for field ") + (int32_t)field +
+ ": Expected y/m/d h:m:s:ms of " +
+ y + "/" + (m + 1) + "/" + d + " " +
+ hr + ":" + min + ":" + sec + ":" + ms +
+ "; got " + c->get(UCAL_YEAR, status) +
+ "/" + (c->get(UCAL_MONTH, status) + 1) +
+ "/" + c->get(UCAL_DATE, status) +
+ " " + c->get(UCAL_HOUR, status) + ":" +
+ c->get(UCAL_MINUTE, status) + ":" +
+ c->get(UCAL_SECOND, status) + ":" +
+ c->get(UCAL_MILLISECOND, status)
+ );
+
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ }
+ else
+ logln(UnicodeString("Confirmed: ") + y + "/" +
+ (m + 1) + "/" + d + " " +
+ hr + ":" + min + ":" + sec + ":" + ms);
+}
+
+// -------------------------------------
+void
+CalendarTest::check520(Calendar* c,
+ int32_t y, int32_t m, int32_t d)
+
+{
+ UErrorCode status = U_ZERO_ERROR;
+ if (c->get(UCAL_YEAR, status) != y ||
+ c->get(UCAL_MONTH, status) != m ||
+ c->get(UCAL_DATE, status) != d) {
+ errln(UnicodeString("FAILURE: Expected y/m/d of ") +
+ y + "/" + (m + 1) + "/" + d + " " +
+ "; got " + c->get(UCAL_YEAR, status) +
+ "/" + (c->get(UCAL_MONTH, status) + 1) +
+ "/" + c->get(UCAL_DATE, status)
+ );
+
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ }
+ else
+ logln(UnicodeString("Confirmed: ") + y + "/" +
+ (m + 1) + "/" + d);
+}
+
+// -------------------------------------
+
+/**
+ * Test that setting of fields works. In particular, make sure that all instances
+ * of GregorianCalendar don't share a static instance of the fields array.
+ */
+void
+CalendarTest::TestFieldSet4781()
+{
+ // try {
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *g = new GregorianCalendar(status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ GregorianCalendar *g2 = new GregorianCalendar(status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ g2->set(UCAL_HOUR, 12, status);
+ g2->set(UCAL_MINUTE, 0, status);
+ g2->set(UCAL_SECOND, 0, status);
+ if (U_FAILURE(status)) { errln("Calendar::set failed"); return; }
+ if (*g == *g2) logln("Same");
+ else logln("Different");
+ //}
+ //catch(IllegalArgumentException e) {
+ //errln("Unexpected exception seen: " + e);
+ //}
+ delete g;
+ delete g2;
+}
+
+// -------------------------------------
+
+/* We don't support serialization on C++
+void
+CalendarTest::TestSerialize337()
+{
+ Calendar cal = Calendar::getInstance();
+ UBool ok = FALSE;
+ try {
+ FileOutputStream f = new FileOutputStream(FILENAME);
+ ObjectOutput s = new ObjectOutputStream(f);
+ s.writeObject(PREFIX);
+ s.writeObject(cal);
+ s.writeObject(POSTFIX);
+ f.close();
+ FileInputStream in = new FileInputStream(FILENAME);
+ ObjectInputStream t = new ObjectInputStream(in);
+ UnicodeString& pre = (UnicodeString&) t.readObject();
+ Calendar c = (Calendar) t.readObject();
+ UnicodeString& post = (UnicodeString&) t.readObject();
+ in.close();
+ ok = pre.equals(PREFIX) &&
+ post.equals(POSTFIX) &&
+ cal->equals(c);
+ File fl = new File(FILENAME);
+ fl.delete();
+ }
+ catch(IOException e) {
+ errln("FAIL: Exception received:");
+ e.printStackTrace(log);
+ }
+ catch(ClassNotFoundException e) {
+ errln("FAIL: Exception received:");
+ e.printStackTrace(log);
+ }
+ if (!ok) errln("Serialization of Calendar object failed.");
+}
+
+UnicodeString& CalendarTest::PREFIX = "abc";
+
+UnicodeString& CalendarTest::POSTFIX = "def";
+
+UnicodeString& CalendarTest::FILENAME = "tmp337.bin";
+ */
+
+// -------------------------------------
+
+/**
+ * Verify that the seconds of a Calendar can be zeroed out through the
+ * expected sequence of operations.
+ */
+void
+CalendarTest::TestSecondsZero121()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = new GregorianCalendar(status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ cal->setTime(Calendar::getNow(), status);
+ if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
+ cal->set(UCAL_SECOND, 0);
+ if (U_FAILURE(status)) { errln("Calendar::set failed"); return; }
+ UDate d = cal->getTime(status);
+ if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
+ UnicodeString s;
+ dateToString(d, s);
+ if (s.indexOf(":00 ") < 0) errln("Expected to see :00 in " + s);
+ delete cal;
+}
+
+// -------------------------------------
+
+/**
+ * Verify that a specific sequence of adding and setting works as expected;
+ * it should not vary depending on when and whether the get method is
+ * called.
+ */
+void
+CalendarTest::TestAddSetGet0610()
+{
+ UnicodeString EXPECTED_0610("1993/0/5", "");
+ UErrorCode status = U_ZERO_ERROR;
+ {
+ Calendar *calendar = new GregorianCalendar(status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ calendar->set(1993, UCAL_JANUARY, 4);
+ logln("1A) " + value(calendar));
+ calendar->add(UCAL_DATE, 1, status);
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ UnicodeString v = value(calendar);
+ logln("1B) " + v);
+ logln("--) 1993/0/5");
+ if (!(v == EXPECTED_0610)) errln("Expected " + EXPECTED_0610 + "; saw " + v);
+ delete calendar;
+ }
+ {
+ Calendar *calendar = new GregorianCalendar(1993, UCAL_JANUARY, 4, status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ logln("2A) " + value(calendar));
+ calendar->add(UCAL_DATE, 1, status);
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ UnicodeString v = value(calendar);
+ logln("2B) " + v);
+ logln("--) 1993/0/5");
+ if (!(v == EXPECTED_0610)) errln("Expected " + EXPECTED_0610 + "; saw " + v);
+ delete calendar;
+ }
+ {
+ Calendar *calendar = new GregorianCalendar(1993, UCAL_JANUARY, 4, status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ logln("3A) " + value(calendar));
+ calendar->getTime(status);
+ if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
+ calendar->add(UCAL_DATE, 1, status);
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ UnicodeString v = value(calendar);
+ logln("3B) " + v);
+ logln("--) 1993/0/5");
+ if (!(v == EXPECTED_0610)) errln("Expected " + EXPECTED_0610 + "; saw " + v);
+ delete calendar;
+ }
+}
+
+// -------------------------------------
+
+UnicodeString
+CalendarTest::value(Calendar* calendar)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ return UnicodeString("") + (int32_t)calendar->get(UCAL_YEAR, status) +
+ "/" + (int32_t)calendar->get(UCAL_MONTH, status) +
+ "/" + (int32_t)calendar->get(UCAL_DATE, status) +
+ (U_FAILURE(status) ? " FAIL: Calendar::get failed" : "");
+}
+
+
+// -------------------------------------
+
+/**
+ * Verify that various fields on a known date are set correctly.
+ */
+void
+CalendarTest::TestFields060()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t year = 1997;
+ int32_t month = UCAL_OCTOBER;
+ int32_t dDate = 22;
+ GregorianCalendar *calendar = 0;
+ calendar = new GregorianCalendar(year, month, dDate, status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ for (int32_t i = 0; i < EXPECTED_FIELDS_length;) {
+ UCalendarDateFields field = (UCalendarDateFields)EXPECTED_FIELDS[i++];
+ int32_t expected = EXPECTED_FIELDS[i++];
+ if (calendar->get(field, status) != expected) {
+ errln(UnicodeString("Expected field ") + (int32_t)field + " to have value " + (int32_t)expected +
+ "; received " + (int32_t)calendar->get(field, status) + " instead");
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ }
+ }
+ delete calendar;
+}
+
+int32_t CalendarTest::EXPECTED_FIELDS[] = {
+ UCAL_YEAR, 1997,
+ UCAL_MONTH, UCAL_OCTOBER,
+ UCAL_DATE, 22,
+ UCAL_DAY_OF_WEEK, UCAL_WEDNESDAY,
+ UCAL_DAY_OF_WEEK_IN_MONTH, 4,
+ UCAL_DAY_OF_YEAR, 295
+};
+
+const int32_t CalendarTest::EXPECTED_FIELDS_length = (int32_t)(sizeof(CalendarTest::EXPECTED_FIELDS) /
+ sizeof(CalendarTest::EXPECTED_FIELDS[0]));
+
+// -------------------------------------
+
+/**
+ * Verify that various fields on a known date are set correctly. In this
+ * case, the start of the epoch (January 1 1970).
+ */
+void
+CalendarTest::TestEpochStartFields()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ TimeZone *z = TimeZone::createDefault();
+ Calendar *c = Calendar::createInstance(status);
+ if (U_FAILURE(status)) { errln("Calendar::createInstance failed"); return; }
+ UDate d = - z->getRawOffset();
+ GregorianCalendar *gc = new GregorianCalendar(status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ gc->setTimeZone(*z);
+ gc->setTime(d, status);
+ if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
+ UBool idt = gc->inDaylightTime(status);
+ if (U_FAILURE(status)) { errln("GregorianCalendar::inDaylightTime failed"); return; }
+ if (idt) {
+ UnicodeString str;
+ logln("Warning: Skipping test because " + dateToString(d, str) + " is in DST.");
+ }
+ else {
+ c->setTime(d, status);
+ if (U_FAILURE(status)) { errln("Calendar::setTime failed"); return; }
+ for (int32_t i = 0; i < UCAL_ZONE_OFFSET;++i) {
+ if (c->get((UCalendarDateFields)i, status) != EPOCH_FIELDS[i])
+ errln(UnicodeString("Expected field ") + i + " to have value " + EPOCH_FIELDS[i] +
+ "; saw " + c->get((UCalendarDateFields)i, status) + " instead");
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ }
+ if (c->get(UCAL_ZONE_OFFSET, status) != z->getRawOffset())
+ {
+ errln(UnicodeString("Expected field ZONE_OFFSET to have value ") + z->getRawOffset() +
+ "; saw " + c->get(UCAL_ZONE_OFFSET, status) + " instead");
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ }
+ if (c->get(UCAL_DST_OFFSET, status) != 0)
+ {
+ errln(UnicodeString("Expected field DST_OFFSET to have value 0") +
+ "; saw " + c->get(UCAL_DST_OFFSET, status) + " instead");
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ }
+ }
+ delete c;
+ delete z;
+ delete gc;
+}
+
+int32_t CalendarTest::EPOCH_FIELDS[] = {
+ 1, 1970, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, - 28800000, 0
+};
+
+// -------------------------------------
+
+/**
+ * Test that the days of the week progress properly when add is called repeatedly
+ * for increments of 24 days.
+ */
+void
+CalendarTest::TestDOWProgression()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = new GregorianCalendar(1972, UCAL_OCTOBER, 26, status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ marchByDelta(cal, 24);
+ delete cal;
+}
+
+// -------------------------------------
+
+void
+CalendarTest::TestDOW_LOCALandYEAR_WOY()
+{
+ /* Note: I've commented out the loop_addroll tests for YEAR and
+ * YEAR_WOY below because these two fields should NOT behave
+ * identically when adding. YEAR should keep the month/dom
+ * invariant. YEAR_WOY should keep the woy/dow invariant. I've
+ * added a new test that checks for this in place of the old call
+ * to loop_addroll. - aliu */
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t times = 20;
+ Calendar *cal=Calendar::createInstance(Locale::getGermany(), status);
+ if (U_FAILURE(status)) { errln("Couldn't create GregorianCalendar"); return; }
+ SimpleDateFormat *sdf=new SimpleDateFormat(UnicodeString("YYYY'-W'ww-ee"), Locale::getGermany(), status);
+ if (U_FAILURE(status)) { errln("Couldn't create SimpleDateFormat"); return; }
+
+ // ICU no longer use localized date-time pattern characters by default.
+ // So we set pattern chars using 'J' instead of 'Y'.
+ DateFormatSymbols *dfs = new DateFormatSymbols(Locale::getGermany(), status);
+ dfs->setLocalPatternChars(UnicodeString("GyMdkHmsSEDFwWahKzJeugAZvcLQq"));
+ sdf->adoptDateFormatSymbols(dfs);
+ sdf->applyLocalizedPattern(UnicodeString("JJJJ'-W'ww-ee"), status);
+ if (U_FAILURE(status)) { errln("Couldn't apply localized pattern"); return; }
+
+ cal->clear();
+ cal->set(1997, UCAL_DECEMBER, 25);
+ doYEAR_WOYLoop(cal, sdf, times, status);
+ //loop_addroll(cal, /*sdf,*/ times, UCAL_YEAR_WOY, UCAL_YEAR, status);
+ yearAddTest(*cal, status); // aliu
+ loop_addroll(cal, /*sdf,*/ times, UCAL_DOW_LOCAL, UCAL_DAY_OF_WEEK, status);
+ if (U_FAILURE(status)) { errln("Error in parse/calculate test for 1997"); return; }
+
+ cal->clear();
+ cal->set(1998, UCAL_DECEMBER, 25);
+ doYEAR_WOYLoop(cal, sdf, times, status);
+ //loop_addroll(cal, /*sdf,*/ times, UCAL_YEAR_WOY, UCAL_YEAR, status);
+ yearAddTest(*cal, status); // aliu
+ loop_addroll(cal, /*sdf,*/ times, UCAL_DOW_LOCAL, UCAL_DAY_OF_WEEK, status);
+ if (U_FAILURE(status)) { errln("Error in parse/calculate test for 1998"); return; }
+
+ cal->clear();
+ cal->set(1582, UCAL_OCTOBER, 1);
+ doYEAR_WOYLoop(cal, sdf, times, status);
+ //loop_addroll(cal, /*sdf,*/ times, Calendar::YEAR_WOY, Calendar::YEAR, status);
+ yearAddTest(*cal, status); // aliu
+ loop_addroll(cal, /*sdf,*/ times, UCAL_DOW_LOCAL, UCAL_DAY_OF_WEEK, status);
+ if (U_FAILURE(status)) { errln("Error in parse/calculate test for 1582"); return; }
+ delete sdf;
+ delete cal;
+
+ return;
+}
+
+/**
+ * Confirm that adding a YEAR and adding a YEAR_WOY work properly for
+ * the given Calendar at its current setting.
+ */
+void CalendarTest::yearAddTest(Calendar& cal, UErrorCode& status) {
+ /**
+ * When adding the YEAR, the month and day should remain constant.
+ * When adding the YEAR_WOY, the WOY and DOW should remain constant. - aliu
+ * Examples:
+ * Wed Jan 14 1998 / 1998-W03-03 Add(YEAR_WOY, 1) -> Wed Jan 20 1999 / 1999-W03-03
+ * Add(YEAR, 1) -> Thu Jan 14 1999 / 1999-W02-04
+ * Thu Jan 14 1999 / 1999-W02-04 Add(YEAR_WOY, 1) -> Thu Jan 13 2000 / 2000-W02-04
+ * Add(YEAR, 1) -> Fri Jan 14 2000 / 2000-W02-05
+ * Sun Oct 31 1582 / 1582-W42-07 Add(YEAR_WOY, 1) -> Sun Oct 23 1583 / 1583-W42-07
+ * Add(YEAR, 1) -> Mon Oct 31 1583 / 1583-W44-01
+ */
+ int32_t y = cal.get(UCAL_YEAR, status);
+ int32_t mon = cal.get(UCAL_MONTH, status);
+ int32_t day = cal.get(UCAL_DATE, status);
+ int32_t ywy = cal.get(UCAL_YEAR_WOY, status);
+ int32_t woy = cal.get(UCAL_WEEK_OF_YEAR, status);
+ int32_t dow = cal.get(UCAL_DOW_LOCAL, status);
+ UDate t = cal.getTime(status);
+
+ if(U_FAILURE(status)){
+ errln(UnicodeString("Failed to create Calendar for locale. Error: ") + UnicodeString(u_errorName(status)));
+ return;
+ }
+ UnicodeString str, str2;
+ SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"), status);
+ fmt.setCalendar(cal);
+
+ fmt.format(t, str.remove());
+ str += ".add(YEAR, 1) =>";
+ cal.add(UCAL_YEAR, 1, status);
+ int32_t y2 = cal.get(UCAL_YEAR, status);
+ int32_t mon2 = cal.get(UCAL_MONTH, status);
+ int32_t day2 = cal.get(UCAL_DATE, status);
+ fmt.format(cal.getTime(status), str);
+ if (y2 != (y+1) || mon2 != mon || day2 != day) {
+ str += (UnicodeString)", expected year " +
+ (y+1) + ", month " + (mon+1) + ", day " + day;
+ errln((UnicodeString)"FAIL: " + str);
+ logln( UnicodeString(" -> ") + CalendarTest::calToStr(cal) );
+ } else {
+ logln(str);
+ }
+
+ fmt.format(t, str.remove());
+ str += ".add(YEAR_WOY, 1)=>";
+ cal.setTime(t, status);
+ logln( UnicodeString(" <- ") + CalendarTest::calToStr(cal) );
+ cal.add(UCAL_YEAR_WOY, 1, status);
+ int32_t ywy2 = cal.get(UCAL_YEAR_WOY, status);
+ int32_t woy2 = cal.get(UCAL_WEEK_OF_YEAR, status);
+ int32_t dow2 = cal.get(UCAL_DOW_LOCAL, status);
+ fmt.format(cal.getTime(status), str);
+ if (ywy2 != (ywy+1) || woy2 != woy || dow2 != dow) {
+ str += (UnicodeString)", expected yearWOY " +
+ (ywy+1) + ", woy " + woy + ", dowLocal " + dow;
+ errln((UnicodeString)"FAIL: " + str);
+ logln( UnicodeString(" -> ") + CalendarTest::calToStr(cal) );
+ } else {
+ logln(str);
+ }
+}
+
+// -------------------------------------
+
+void CalendarTest::loop_addroll(Calendar *cal, /*SimpleDateFormat *sdf,*/ int times, UCalendarDateFields field, UCalendarDateFields field2, UErrorCode& errorCode) {
+ Calendar *calclone;
+ SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"), errorCode);
+ fmt.setCalendar(*cal);
+ int i;
+
+ for(i = 0; i<times; i++) {
+ calclone = cal->clone();
+ UDate start = cal->getTime(errorCode);
+ cal->add(field,1,errorCode);
+ if (U_FAILURE(errorCode)) { errln("Error in add"); delete calclone; return; }
+ calclone->add(field2,1,errorCode);
+ if (U_FAILURE(errorCode)) { errln("Error in add"); delete calclone; return; }
+ if(cal->getTime(errorCode) != calclone->getTime(errorCode)) {
+ UnicodeString str("FAIL: Results of add differ. "), str2;
+ str += fmt.format(start, str2) + " ";
+ str += UnicodeString("Add(") + fieldName(field) + ", 1) -> " +
+ fmt.format(cal->getTime(errorCode), str2.remove()) + "; ";
+ str += UnicodeString("Add(") + fieldName(field2) + ", 1) -> " +
+ fmt.format(calclone->getTime(errorCode), str2.remove());
+ errln(str);
+ delete calclone;
+ return;
+ }
+ delete calclone;
+ }
+
+ for(i = 0; i<times; i++) {
+ calclone = cal->clone();
+ cal->roll(field,(int32_t)1,errorCode);
+ if (U_FAILURE(errorCode)) { errln("Error in roll"); delete calclone; return; }
+ calclone->roll(field2,(int32_t)1,errorCode);
+ if (U_FAILURE(errorCode)) { errln("Error in roll"); delete calclone; return; }
+ if(cal->getTime(errorCode) != calclone->getTime(errorCode)) {
+ delete calclone;
+ errln("Results of roll differ!");
+ return;
+ }
+ delete calclone;
+ }
+}
+
+// -------------------------------------
+
+void
+CalendarTest::doYEAR_WOYLoop(Calendar *cal, SimpleDateFormat *sdf,
+ int32_t times, UErrorCode& errorCode) {
+
+ UnicodeString us;
+ UDate tst, original;
+ Calendar *tstres = new GregorianCalendar(Locale::getGermany(), errorCode);
+ for(int i=0; i<times; ++i) {
+ sdf->format(Formattable(cal->getTime(errorCode),Formattable::kIsDate), us, errorCode);
+ //logln("expected: "+us);
+ if (U_FAILURE(errorCode)) { errln("Format error"); return; }
+ tst=sdf->parse(us,errorCode);
+ if (U_FAILURE(errorCode)) { errln("Parse error"); return; }
+ tstres->clear();
+ tstres->setTime(tst, errorCode);
+ //logln((UnicodeString)"Parsed week of year is "+tstres->get(UCAL_WEEK_OF_YEAR, errorCode));
+ if (U_FAILURE(errorCode)) { errln("Set time error"); return; }
+ original = cal->getTime(errorCode);
+ us.remove();
+ sdf->format(Formattable(tst,Formattable::kIsDate), us, errorCode);
+ //logln("got: "+us);
+ if (U_FAILURE(errorCode)) { errln("Get time error"); return; }
+ if(original!=tst) {
+ us.remove();
+ sdf->format(Formattable(original, Formattable::kIsDate), us, errorCode);
+ errln("FAIL: Parsed time doesn't match with regular");
+ logln("expected "+us + " " + calToStr(*cal));
+ us.remove();
+ sdf->format(Formattable(tst, Formattable::kIsDate), us, errorCode);
+ logln("got "+us + " " + calToStr(*tstres));
+ }
+ tstres->clear();
+ tstres->set(UCAL_YEAR_WOY, cal->get(UCAL_YEAR_WOY, errorCode));
+ tstres->set(UCAL_WEEK_OF_YEAR, cal->get(UCAL_WEEK_OF_YEAR, errorCode));
+ tstres->set(UCAL_DOW_LOCAL, cal->get(UCAL_DOW_LOCAL, errorCode));
+ if(cal->get(UCAL_YEAR, errorCode) != tstres->get(UCAL_YEAR, errorCode)) {
+ errln("FAIL: Different Year!");
+ logln((UnicodeString)"Expected "+cal->get(UCAL_YEAR, errorCode));
+ logln((UnicodeString)"Got "+tstres->get(UCAL_YEAR, errorCode));
+ return;
+ }
+ if(cal->get(UCAL_DAY_OF_YEAR, errorCode) != tstres->get(UCAL_DAY_OF_YEAR, errorCode)) {
+ errln("FAIL: Different Day Of Year!");
+ logln((UnicodeString)"Expected "+cal->get(UCAL_DAY_OF_YEAR, errorCode));
+ logln((UnicodeString)"Got "+tstres->get(UCAL_DAY_OF_YEAR, errorCode));
+ return;
+ }
+ //logln(calToStr(*cal));
+ cal->add(UCAL_DATE, 1, errorCode);
+ if (U_FAILURE(errorCode)) { errln("Add error"); return; }
+ us.remove();
+ }
+ delete (tstres);
+}
+// -------------------------------------
+
+void
+CalendarTest::marchByDelta(Calendar* cal, int32_t delta)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cur = (Calendar*) cal->clone();
+ int32_t initialDOW = cur->get(UCAL_DAY_OF_WEEK, status);
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ int32_t DOW, newDOW = initialDOW;
+ do {
+ UnicodeString str;
+ DOW = newDOW;
+ logln(UnicodeString("DOW = ") + DOW + " " + dateToString(cur->getTime(status), str));
+ if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
+ cur->add(UCAL_DAY_OF_WEEK, delta, status);
+ if (U_FAILURE(status)) { errln("Calendar::add failed"); return; }
+ newDOW = cur->get(UCAL_DAY_OF_WEEK, status);
+ if (U_FAILURE(status)) { errln("Calendar::get failed"); return; }
+ int32_t expectedDOW = 1 + (DOW + delta - 1) % 7;
+ if (newDOW != expectedDOW) {
+ errln(UnicodeString("Day of week should be ") + expectedDOW + " instead of " + newDOW +
+ " on " + dateToString(cur->getTime(status), str));
+ if (U_FAILURE(status)) { errln("Calendar::getTime failed"); return; }
+ return;
+ }
+ }
+ while (newDOW != initialDOW);
+ delete cur;
+}
+
+#define CHECK(status, msg) \
+ if (U_FAILURE(status)) { \
+ errln(msg); \
+ return; \
+ }
+
+void CalendarTest::TestWOY(void) {
+ /*
+ FDW = Mon, MDFW = 4:
+ Sun Dec 26 1999, WOY 51
+ Mon Dec 27 1999, WOY 52
+ Tue Dec 28 1999, WOY 52
+ Wed Dec 29 1999, WOY 52
+ Thu Dec 30 1999, WOY 52
+ Fri Dec 31 1999, WOY 52
+ Sat Jan 01 2000, WOY 52 ***
+ Sun Jan 02 2000, WOY 52 ***
+ Mon Jan 03 2000, WOY 1
+ Tue Jan 04 2000, WOY 1
+ Wed Jan 05 2000, WOY 1
+ Thu Jan 06 2000, WOY 1
+ Fri Jan 07 2000, WOY 1
+ Sat Jan 08 2000, WOY 1
+ Sun Jan 09 2000, WOY 1
+ Mon Jan 10 2000, WOY 2
+
+ FDW = Mon, MDFW = 2:
+ Sun Dec 26 1999, WOY 52
+ Mon Dec 27 1999, WOY 1 ***
+ Tue Dec 28 1999, WOY 1 ***
+ Wed Dec 29 1999, WOY 1 ***
+ Thu Dec 30 1999, WOY 1 ***
+ Fri Dec 31 1999, WOY 1 ***
+ Sat Jan 01 2000, WOY 1
+ Sun Jan 02 2000, WOY 1
+ Mon Jan 03 2000, WOY 2
+ Tue Jan 04 2000, WOY 2
+ Wed Jan 05 2000, WOY 2
+ Thu Jan 06 2000, WOY 2
+ Fri Jan 07 2000, WOY 2
+ Sat Jan 08 2000, WOY 2
+ Sun Jan 09 2000, WOY 2
+ Mon Jan 10 2000, WOY 3
+ */
+
+ UnicodeString str;
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t i;
+
+ GregorianCalendar cal(status);
+ SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy', WOY' w"), status);
+ CHECK(status, "Fail: Cannot construct calendar/format");
+
+ UCalendarDaysOfWeek fdw = (UCalendarDaysOfWeek) 0;
+
+ //for (int8_t pass=2; pass<=2; ++pass) {
+ for (int8_t pass=1; pass<=2; ++pass) {
+ switch (pass) {
+ case 1:
+ fdw = UCAL_MONDAY;
+ cal.setFirstDayOfWeek(fdw);
+ cal.setMinimalDaysInFirstWeek(4);
+ fmt.adoptCalendar(cal.clone());
+ break;
+ case 2:
+ fdw = UCAL_MONDAY;
+ cal.setFirstDayOfWeek(fdw);
+ cal.setMinimalDaysInFirstWeek(2);
+ fmt.adoptCalendar(cal.clone());
+ break;
+ }
+
+ //for (i=2; i<=6; ++i) {
+ for (i=0; i<16; ++i) {
+ UDate t, t2;
+ int32_t t_y, t_woy, t_dow;
+ cal.clear();
+ cal.set(1999, UCAL_DECEMBER, 26 + i);
+ fmt.format(t = cal.getTime(status), str.remove());
+ CHECK(status, "Fail: getTime failed");
+ logln(UnicodeString("* ") + str);
+ int32_t dow = cal.get(UCAL_DAY_OF_WEEK, status);
+ int32_t woy = cal.get(UCAL_WEEK_OF_YEAR, status);
+ int32_t year = cal.get(UCAL_YEAR, status);
+ int32_t mon = cal.get(UCAL_MONTH, status);
+ logln(calToStr(cal));
+ CHECK(status, "Fail: get failed");
+ int32_t dowLocal = dow - fdw;
+ if (dowLocal < 0) dowLocal += 7;
+ dowLocal++;
+ int32_t yearWoy = year;
+ if (mon == UCAL_JANUARY) {
+ if (woy >= 52) --yearWoy;
+ } else {
+ if (woy == 1) ++yearWoy;
+ }
+
+ // Basic fields->time check y/woy/dow
+ // Since Y/WOY is ambiguous, we do a check of the fields,
+ // not of the specific time.
+ cal.clear();
+ cal.set(UCAL_YEAR, year);
+ cal.set(UCAL_WEEK_OF_YEAR, woy);
+ cal.set(UCAL_DAY_OF_WEEK, dow);
+ t_y = cal.get(UCAL_YEAR, status);
+ t_woy = cal.get(UCAL_WEEK_OF_YEAR, status);
+ t_dow = cal.get(UCAL_DAY_OF_WEEK, status);
+ CHECK(status, "Fail: get failed");
+ if (t_y != year || t_woy != woy || t_dow != dow) {
+ str = "Fail: y/woy/dow fields->time => ";
+ fmt.format(cal.getTime(status), str);
+ errln(str);
+ logln(calToStr(cal));
+ logln("[get!=set] Y%d!=%d || woy%d!=%d || dow%d!=%d\n",
+ t_y, year, t_woy, woy, t_dow, dow);
+ } else {
+ logln("y/woy/dow fields->time OK");
+ }
+
+ // Basic fields->time check y/woy/dow_local
+ // Since Y/WOY is ambiguous, we do a check of the fields,
+ // not of the specific time.
+ cal.clear();
+ cal.set(UCAL_YEAR, year);
+ cal.set(UCAL_WEEK_OF_YEAR, woy);
+ cal.set(UCAL_DOW_LOCAL, dowLocal);
+ t_y = cal.get(UCAL_YEAR, status);
+ t_woy = cal.get(UCAL_WEEK_OF_YEAR, status);
+ t_dow = cal.get(UCAL_DOW_LOCAL, status);
+ CHECK(status, "Fail: get failed");
+ if (t_y != year || t_woy != woy || t_dow != dowLocal) {
+ str = "Fail: y/woy/dow_local fields->time => ";
+ fmt.format(cal.getTime(status), str);
+ errln(str);
+ }
+
+ // Basic fields->time check y_woy/woy/dow
+ cal.clear();
+ cal.set(UCAL_YEAR_WOY, yearWoy);
+ cal.set(UCAL_WEEK_OF_YEAR, woy);
+ cal.set(UCAL_DAY_OF_WEEK, dow);
+ t2 = cal.getTime(status);
+ CHECK(status, "Fail: getTime failed");
+ if (t != t2) {
+ str = "Fail: y_woy/woy/dow fields->time => ";
+ fmt.format(t2, str);
+ errln(str);
+ logln(calToStr(cal));
+ logln("%.f != %.f\n", t, t2);
+ } else {
+ logln("y_woy/woy/dow OK");
+ }
+
+ // Basic fields->time check y_woy/woy/dow_local
+ cal.clear();
+ cal.set(UCAL_YEAR_WOY, yearWoy);
+ cal.set(UCAL_WEEK_OF_YEAR, woy);
+ cal.set(UCAL_DOW_LOCAL, dowLocal);
+ t2 = cal.getTime(status);
+ CHECK(status, "Fail: getTime failed");
+ if (t != t2) {
+ str = "Fail: y_woy/woy/dow_local fields->time => ";
+ fmt.format(t2, str);
+ errln(str);
+ }
+
+ logln("Testing DOW_LOCAL.. dow%d\n", dow);
+ // Make sure DOW_LOCAL disambiguates over DOW
+ int32_t wrongDow = dow - 3;
+ if (wrongDow < 1) wrongDow += 7;
+ cal.setTime(t, status);
+ cal.set(UCAL_DAY_OF_WEEK, wrongDow);
+ cal.set(UCAL_DOW_LOCAL, dowLocal);
+ t2 = cal.getTime(status);
+ CHECK(status, "Fail: set/getTime failed");
+ if (t != t2) {
+ str = "Fail: DOW_LOCAL fields->time => ";
+ fmt.format(t2, str);
+ errln(str);
+ logln(calToStr(cal));
+ logln("%.f : DOW%d, DOW_LOCAL%d -> %.f\n",
+ t, wrongDow, dowLocal, t2);
+ }
+
+ // Make sure DOW disambiguates over DOW_LOCAL
+ int32_t wrongDowLocal = dowLocal - 3;
+ if (wrongDowLocal < 1) wrongDowLocal += 7;
+ cal.setTime(t, status);
+ cal.set(UCAL_DOW_LOCAL, wrongDowLocal);
+ cal.set(UCAL_DAY_OF_WEEK, dow);
+ t2 = cal.getTime(status);
+ CHECK(status, "Fail: set/getTime failed");
+ if (t != t2) {
+ str = "Fail: DOW fields->time => ";
+ fmt.format(t2, str);
+ errln(str);
+ }
+
+ // Make sure YEAR_WOY disambiguates over YEAR
+ cal.setTime(t, status);
+ cal.set(UCAL_YEAR, year - 2);
+ cal.set(UCAL_YEAR_WOY, yearWoy);
+ t2 = cal.getTime(status);
+ CHECK(status, "Fail: set/getTime failed");
+ if (t != t2) {
+ str = "Fail: YEAR_WOY fields->time => ";
+ fmt.format(t2, str);
+ errln(str);
+ }
+
+ // Make sure YEAR disambiguates over YEAR_WOY
+ cal.setTime(t, status);
+ cal.set(UCAL_YEAR_WOY, yearWoy - 2);
+ cal.set(UCAL_YEAR, year);
+ t2 = cal.getTime(status);
+ CHECK(status, "Fail: set/getTime failed");
+ if (t != t2) {
+ str = "Fail: YEAR fields->time => ";
+ fmt.format(t2, str);
+ errln(str);
+ }
+ }
+ }
+
+ /*
+ FDW = Mon, MDFW = 4:
+ Sun Dec 26 1999, WOY 51
+ Mon Dec 27 1999, WOY 52
+ Tue Dec 28 1999, WOY 52
+ Wed Dec 29 1999, WOY 52
+ Thu Dec 30 1999, WOY 52
+ Fri Dec 31 1999, WOY 52
+ Sat Jan 01 2000, WOY 52
+ Sun Jan 02 2000, WOY 52
+ */
+
+ // Roll the DOW_LOCAL within week 52
+ for (i=27; i<=33; ++i) {
+ int32_t amount;
+ for (amount=-7; amount<=7; ++amount) {
+ str = "roll(";
+ cal.set(1999, UCAL_DECEMBER, i);
+ UDate t, t2;
+ fmt.format(cal.getTime(status), str);
+ CHECK(status, "Fail: getTime failed");
+ str += UnicodeString(", ") + amount + ") = ";
+
+ cal.roll(UCAL_DOW_LOCAL, amount, status);
+ CHECK(status, "Fail: roll failed");
+
+ t = cal.getTime(status);
+ int32_t newDom = i + amount;
+ while (newDom < 27) newDom += 7;
+ while (newDom > 33) newDom -= 7;
+ cal.set(1999, UCAL_DECEMBER, newDom);
+ t2 = cal.getTime(status);
+ CHECK(status, "Fail: getTime failed");
+ fmt.format(t, str);
+
+ if (t != t2) {
+ str.append(", exp ");
+ fmt.format(t2, str);
+ errln(str);
+ } else {
+ logln(str);
+ }
+ }
+ }
+}
+
+void CalendarTest::TestYWOY()
+{
+ UnicodeString str;
+ UErrorCode status = U_ZERO_ERROR;
+
+ GregorianCalendar cal(status);
+ CHECK(status, "Fail: Cannot construct calendar/format");
+
+ cal.setFirstDayOfWeek(UCAL_SUNDAY);
+ cal.setMinimalDaysInFirstWeek(1);
+
+ logln("Setting: ywoy=2004, woy=1, dow=MONDAY");
+ cal.clear();
+ cal.set(UCAL_YEAR_WOY,2004);
+ cal.set(UCAL_WEEK_OF_YEAR,1);
+ cal.set(UCAL_DAY_OF_WEEK, UCAL_MONDAY);
+
+ logln(calToStr(cal));
+ if(cal.get(UCAL_YEAR, status) != 2003) {
+ errln("year not 2003");
+ }
+
+ logln("+ setting DOW to THURSDAY");
+ cal.clear();
+ cal.set(UCAL_YEAR_WOY,2004);
+ cal.set(UCAL_WEEK_OF_YEAR,1);
+ cal.set(UCAL_DAY_OF_WEEK, UCAL_THURSDAY);
+
+ logln(calToStr(cal));
+ if(cal.get(UCAL_YEAR, status) != 2004) {
+ errln("year not 2004");
+ }
+
+ logln("+ setting DOW_LOCAL to 1");
+ cal.clear();
+ cal.set(UCAL_YEAR_WOY,2004);
+ cal.set(UCAL_WEEK_OF_YEAR,1);
+ cal.set(UCAL_DAY_OF_WEEK, UCAL_THURSDAY);
+ cal.set(UCAL_DOW_LOCAL, 1);
+
+ logln(calToStr(cal));
+ if(cal.get(UCAL_YEAR, status) != 2003) {
+ errln("year not 2003");
+ }
+
+ cal.setFirstDayOfWeek(UCAL_MONDAY);
+ cal.setMinimalDaysInFirstWeek(4);
+ UDate t = 946713600000.;
+ cal.setTime(t, status);
+ cal.set(UCAL_DAY_OF_WEEK, 4);
+ cal.set(UCAL_DOW_LOCAL, 6);
+ if(cal.getTime(status) != t) {
+ logln(calToStr(cal));
+ errln("FAIL: DOW_LOCAL did not take precedence");
+ }
+
+}
+
+void CalendarTest::TestJD()
+{
+ int32_t jd;
+ static const int32_t kEpochStartAsJulianDay = 2440588;
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar cal(status);
+ cal.setTimeZone(*TimeZone::getGMT());
+ cal.clear();
+ jd = cal.get(UCAL_JULIAN_DAY, status);
+ if(jd != kEpochStartAsJulianDay) {
+ errln("Wanted JD of %d at time=0, [epoch 1970] but got %d\n", kEpochStartAsJulianDay, jd);
+ } else {
+ logln("Wanted JD of %d at time=0, [epoch 1970], got %d\n", kEpochStartAsJulianDay, jd);
+ }
+
+ cal.setTime(Calendar::getNow(), status);
+ cal.clear();
+ cal.set(UCAL_JULIAN_DAY, kEpochStartAsJulianDay);
+ UDate epochTime = cal.getTime(status);
+ if(epochTime != 0) {
+ errln("Wanted time of 0 at jd=%d, got %.1lf\n", kEpochStartAsJulianDay, epochTime);
+ } else {
+ logln("Wanted time of 0 at jd=%d, got %.1lf\n", kEpochStartAsJulianDay, epochTime);
+ }
+
+}
+
+// make sure the ctestfw utilities are in sync with the Calendar
+void CalendarTest::TestDebug()
+{
+ for(int32_t t=0;t<=UDBG_ENUM_COUNT;t++) {
+ int32_t count = udbg_enumCount((UDebugEnumType)t);
+ if(count == -1) {
+ logln("enumCount(%d) returned -1", count);
+ continue;
+ }
+ for(int32_t i=0;i<=count;i++) {
+ if(i<count) {
+ if( i!=udbg_enumArrayValue((UDebugEnumType)t, i)) {
+ errln("FAIL: udbg_enumArrayValue(%d,%d) returned %d, expected %d", t, i, udbg_enumArrayValue((UDebugEnumType)t,i), i);
+ }
+ } else {
+ logln("Testing count+1:");
+ }
+ const char *name = udbg_enumName((UDebugEnumType)t,i);
+ if(name==NULL) {
+ if(i==count) {
+ logln(" null name - expected.\n");
+ } else {
+ errln("FAIL: udbg_enumName(%d,%d) returned NULL", t, i);
+ }
+ name = "(null)";
+ }
+ logln("udbg_enumArrayValue(%d,%d) = %s, returned %d", t, i,
+ name, udbg_enumArrayValue((UDebugEnumType)t,i));
+ logln("udbg_enumString = " + udbg_enumString((UDebugEnumType)t,i));
+ }
+ if(udbg_enumExpectedCount((UDebugEnumType)t) != count) {
+ errln("FAIL: udbg_enumExpectedCount(%d): %d, != UCAL_FIELD_COUNT=%d ", t, udbg_enumExpectedCount((UDebugEnumType)t), count);
+ } else {
+ logln("udbg_ucal_fieldCount: %d, UCAL_FIELD_COUNT=udbg_enumCount %d ", udbg_enumExpectedCount((UDebugEnumType)t), count);
+ }
+ }
+}
+
+
+#undef CHECK
+
+// List of interesting locales
+const char *CalendarTest::testLocaleID(int32_t i)
+{
+ switch(i) {
+ case 0: return "he_IL@calendar=hebrew";
+ case 1: return "en_US@calendar=hebrew";
+ case 2: return "fr_FR@calendar=hebrew";
+ case 3: return "fi_FI@calendar=hebrew";
+ case 4: return "nl_NL@calendar=hebrew";
+ case 5: return "hu_HU@calendar=hebrew";
+ case 6: return "nl_BE@currency=MTL;calendar=islamic";
+ case 7: return "th_TH_TRADITIONAL@calendar=gregorian";
+ case 8: return "ar_JO@calendar=islamic-civil";
+ case 9: return "fi_FI@calendar=islamic";
+ case 10: return "fr_CH@calendar=islamic-civil";
+ case 11: return "he_IL@calendar=islamic-civil";
+ case 12: return "hu_HU@calendar=buddhist";
+ case 13: return "hu_HU@calendar=islamic";
+ case 14: return "en_US@calendar=japanese";
+ default: return NULL;
+ }
+}
+
+int32_t CalendarTest::testLocaleCount()
+{
+ static int32_t gLocaleCount = -1;
+ if(gLocaleCount < 0) {
+ int32_t i;
+ for(i=0;testLocaleID(i) != NULL;i++) {
+ ;
+ }
+ gLocaleCount = i;
+ }
+ return gLocaleCount;
+}
+
+static UDate doMinDateOfCalendar(Calendar* adopt, UBool &isGregorian, UErrorCode& status) {
+ if(U_FAILURE(status)) return 0.0;
+
+ adopt->clear();
+ adopt->set(UCAL_EXTENDED_YEAR, adopt->getActualMinimum(UCAL_EXTENDED_YEAR, status));
+ UDate ret = adopt->getTime(status);
+ isGregorian = (adopt->getDynamicClassID() == GregorianCalendar::getStaticClassID());
+ delete adopt;
+ return ret;
+}
+
+UDate CalendarTest::minDateOfCalendar(const Locale& locale, UBool &isGregorian, UErrorCode& status) {
+ if(U_FAILURE(status)) return 0.0;
+ return doMinDateOfCalendar(Calendar::createInstance(locale, status), isGregorian, status);
+}
+
+UDate CalendarTest::minDateOfCalendar(const Calendar& cal, UBool &isGregorian, UErrorCode& status) {
+ if(U_FAILURE(status)) return 0.0;
+ return doMinDateOfCalendar(cal.clone(), isGregorian, status);
+}
+
+
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/caltest.h b/Build/source/libs/icu/icu-xetex/test/intltest/caltest.h
new file mode 100644
index 00000000000..94ec73185d4
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/caltest.h
@@ -0,0 +1,224 @@
+/***********************************************************************
+ * Copyright (c) 1997-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#ifndef __CalendarTest__
+#define __CalendarTest__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/smpdtfmt.h"
+#include "caltztst.h"
+
+class CalendarTest: public CalendarTimeZoneTest {
+public:
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+ /**
+ * This test confirms the correct behavior of add when incrementing
+ * through subsequent days.
+ */
+ virtual void TestRog(void);
+ /**
+ * Test the handling of the day of the week, checking for correctness and
+ * for correct minimum and maximum values.
+ */
+ virtual void TestDOW943(void);
+ /**
+ * test subroutine use by TestDOW943
+ */
+ void dowTest(UBool lenient);
+ /**
+ * Confirm that cloned Calendar objects do not inadvertently share substructures.
+ */
+ virtual void TestClonesUnique908(void);
+ /**
+ * Confirm that the Gregorian cutoff value works as advertised.
+ */
+ virtual void TestGregorianChange768(void);
+ /**
+ * Confirm the functioning of the field disambiguation algorithm.
+ */
+ virtual void TestDisambiguation765(void);
+ /**
+ * Test various API methods for API completeness.
+ */
+ virtual void TestGenericAPI(void); // New to C++ -- needs to be back ported to Java
+
+ virtual void TestWOY(void);
+
+ virtual void TestDebug(void);
+
+public: // package
+ /**
+ * test subroutine used by TestDisambiguation765
+ */
+ virtual void verify765(const UnicodeString& msg, Calendar* c, int32_t year, int32_t month, int32_t day);
+ /**
+ * test subroutine used by TestDisambiguation765
+ */
+ virtual void verify765(const UnicodeString& msg/*, IllegalArgumentException e*/, UErrorCode status);
+
+public:
+ /**
+ * Confirm that the offset between local time and GMT behaves as expected.
+ */
+ virtual void TestGMTvsLocal4064654(void);
+
+public: // package
+ /**
+ * test subroutine used by TestGMTvsLocal4064654
+ */
+ virtual void test4064654(int32_t yr, int32_t mo, int32_t dt, int32_t hr, int32_t mn, int32_t sc);
+
+public:
+ /**
+ * The operations of adding and setting should not exhibit pathological
+ * dependence on the order of operations. This test checks for this.
+ */
+ virtual void TestAddSetOrder621(void);
+ /**
+ * Confirm that adding to various fields works.
+ */
+ virtual void TestAdd520(void);
+ /**
+ * Execute and test adding and rolling in GregorianCalendar extensively.
+ */
+ virtual void TestAddRollExtensive(void);
+
+public: // package
+ // internal utility routine for checking date
+ virtual void check520(Calendar* c,
+ int32_t y, int32_t m, int32_t d,
+ int32_t hr, int32_t min, int32_t sec,
+ int32_t ms, UCalendarDateFields field);
+
+ virtual void check520(Calendar* c,
+ int32_t y, int32_t m, int32_t d);
+
+public:
+ /**
+ * Test that setting of fields works. In particular, make sure that all instances
+ * of GregorianCalendar don't share a static instance of the fields array.
+ */
+ virtual void TestFieldSet4781(void);
+/* virtual void TestSerialize337();
+
+public: // package
+ static UnicodeString& PREFIX;
+ static UnicodeString& POSTFIX;
+ static UnicodeString& FILENAME;
+*/
+public:
+ /**
+ * Verify that the seconds of a Calendar can be zeroed out through the
+ * expected sequence of operations.
+ */
+ virtual void TestSecondsZero121(void);
+ /**
+ * Verify that a specific sequence of adding and setting works as expected;
+ * it should not vary depending on when and whether the get method is
+ * called.
+ */
+ virtual void TestAddSetGet0610(void);
+
+public: // package
+ // internal routine for checking date
+ static UnicodeString value(Calendar* calendar);
+
+public:
+ /**
+ * Verify that various fields on a known date are set correctly.
+ */
+ virtual void TestFields060(void);
+
+public: // package
+ static int32_t EXPECTED_FIELDS[];
+ static const int32_t EXPECTED_FIELDS_length;
+
+public:
+ /**
+ * Verify that various fields on a known date are set correctly. In this
+ * case, the start of the epoch (January 1 1970).
+ */
+ virtual void TestEpochStartFields(void);
+
+public: // package
+ static int32_t EPOCH_FIELDS[];
+
+public:
+ /**
+ * Test that the days of the week progress properly when add is called repeatedly
+ * for increments of 24 days.
+ */
+ virtual void TestDOWProgression(void);
+ /**
+ * Test newly added fields - DOW_LOCAL and YEAR_WOY
+ */
+ virtual void TestDOW_LOCALandYEAR_WOY(void);
+ // test subroutine used by TestDOW_LOCALandYEAR_WOY
+ virtual void doYEAR_WOYLoop(Calendar *cal,
+ SimpleDateFormat *sdf, int32_t times, UErrorCode& status);
+ // test subroutine used by TestDOW_LOCALandYEAR_WOY
+ virtual void loop_addroll(Calendar *cal, /*SimpleDateFormat *sdf, */
+ int times, UCalendarDateFields field, UCalendarDateFields field2,
+ UErrorCode& errorCode);
+
+ void TestYWOY(void);
+ void TestJD(void);
+
+ void yearAddTest(Calendar& cal, UErrorCode& status);
+
+public: // package
+ // test subroutine use by TestDOWProgression
+ virtual void marchByDelta(Calendar* cal, int32_t delta);
+
+ public:
+ // for other tests' use
+ static UnicodeString fieldName(UCalendarDateFields f);
+ static UnicodeString calToStr(const Calendar & cal);
+
+ // List of non-installed locales with interesting calendars
+
+ /**
+ * @return the count of 'other' locales to test
+ */
+ static int32_t testLocaleCount();
+
+ /**
+ * @param i index of 'other' locale to return
+ * @return locale ID
+ */
+ static const char* testLocaleID(int32_t i);
+
+ /**
+ * Clone the specified calendar, and determine its earliest supported date
+ * by setting the extended year to the minimum value.
+ * @param cal Calendar (will be cloned)
+ * @param isGregorian output: returns 'TRUE' if the calendar's class is GregorianCalendar
+ * @param status error code
+ */
+ static UDate minDateOfCalendar(const Calendar& cal, UBool &isGregorian, UErrorCode& status);
+
+ /**
+ * Construct a calendar of the specified locale, and determine its earliest supported date
+ * by setting the extended year to the minimum value.
+ * @param locale locale of calendar to check
+ * @param isGregorian output: returns 'TRUE' if the calendar's class is GregorianCalendar
+ * @param status error code
+ */
+ static UDate minDateOfCalendar(const Locale& locale, UBool &isGregorian, UErrorCode& status);
+
+ // internal - for other test use
+ public:
+
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __CalendarTest__
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/caltztst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/caltztst.cpp
new file mode 100644
index 00000000000..3d50ce954c2
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/caltztst.cpp
@@ -0,0 +1,240 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/*
+* File CALTZTST.H
+*
+* Modification History:
+*
+* Date Name Description
+* 08/06/97 aliu Creation.
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "caltztst.h"
+#include "unicode/smpdtfmt.h"
+#include "mutex.h"
+
+DateFormat* CalendarTimeZoneTest::fgDateFormat = 0;
+Calendar* CalendarTimeZoneTest::fgCalendar = 0;
+
+UBool CalendarTimeZoneTest::failure(UErrorCode status, const char* msg)
+{
+ if (U_FAILURE(status))
+ {
+ errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+DateFormat* CalendarTimeZoneTest::getDateFormat()
+{
+ DateFormat *theFormat = 0;
+
+ if (fgDateFormat != 0) // if there's something in the cache
+ {
+ Mutex lock;
+
+ if (fgDateFormat != 0) // Someone might have grabbed it.
+ {
+ theFormat = fgDateFormat;
+ fgDateFormat = 0; // We have exclusive right to this formatter.
+ }
+ }
+
+ if(theFormat == 0) // If we weren't able to pull it out of the cache, then we have to create it.
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ theFormat = new SimpleDateFormat(UnicodeString("EEE MMM dd HH:mm:ss zzz yyyy"), status);
+ if (U_FAILURE(status))
+ {
+ delete theFormat;
+ theFormat = 0;
+ errln("FAIL: Could not create SimpleDateFormat");
+ }
+ }
+
+ return theFormat;
+}
+
+void CalendarTimeZoneTest::releaseDateFormat(DateFormat *adopt)
+{
+ if(fgDateFormat == 0) // If the cache is empty we must add it back.
+ {
+ Mutex lock;
+
+ if(fgDateFormat == 0)
+ {
+ fgDateFormat = adopt;
+ adopt = 0;
+ }
+ }
+ else {
+ delete adopt;
+ }
+}
+
+Calendar* CalendarTimeZoneTest::getCalendar()
+{
+ Calendar *theCalendar = 0;
+
+ if (fgCalendar != 0) // if there's something in the cache
+ {
+ Mutex lock;
+
+ if (fgCalendar != 0) // Someone might have grabbed it.
+ {
+ theCalendar = fgCalendar;
+ fgCalendar = 0; // We have exclusive right to this calendar.
+ }
+ }
+
+ if(theCalendar == 0) // If we weren't able to pull it out of the cache, then we have to create it.
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ theCalendar = Calendar::createInstance(status);
+ if (U_FAILURE(status))
+ {
+ delete theCalendar;
+ theCalendar = 0;
+ errln("FAIL: Calendar::createInstance failed");
+ }
+ }
+ return theCalendar;
+}
+
+void CalendarTimeZoneTest::releaseCalendar(Calendar* adopt)
+{
+ if(fgCalendar == 0) // If the cache is empty we must add it back.
+ {
+ Mutex lock;
+
+ if(fgCalendar == 0)
+ {
+ fgCalendar = adopt;
+ adopt = 0;
+ }
+ }
+ else
+ {
+ delete adopt;
+ }
+}
+
+// Utility method for formatting dates for printing; useful for Java->C++ conversion.
+// Tries to mimic the Java Date.toString() format.
+UnicodeString
+CalendarTimeZoneTest::dateToString(UDate d)
+{
+ UnicodeString str;
+ return dateToString(d, str);
+}
+
+UnicodeString&
+CalendarTimeZoneTest::dateToString(UDate d, UnicodeString& str)
+{
+ str.remove();
+ DateFormat* format = getDateFormat();
+ if (format == 0)
+ {
+ str += "DATE_FORMAT_FAILURE";
+ return str;
+ }
+ format->format(d, str);
+ releaseDateFormat(format);
+ return str;
+}
+
+UnicodeString&
+CalendarTimeZoneTest::dateToString(UDate d, UnicodeString& str,
+ const TimeZone& tz)
+{
+ str.remove();
+ DateFormat* format = getDateFormat();
+ if (format == 0)
+ {
+ str += "DATE_FORMAT_FAILURE";
+ return str;
+ }
+ TimeZone* save = format->getTimeZone().clone();
+ format->setTimeZone(tz);
+ format->format(d, str);
+ format->adoptTimeZone(save);
+ releaseDateFormat(format);
+ return str;
+}
+
+// Utility methods to create a date. This is useful for converting Java constructs
+// which create a Date object.
+UDate
+CalendarTimeZoneTest::date(int32_t y, int32_t m, int32_t d, int32_t hr, int32_t min, int32_t sec)
+{
+ Calendar* cal = getCalendar();
+ if (cal == 0) return 0.0;
+ cal->clear();
+ cal->set(1900 + y, m, d, hr, min, sec); // Add 1900 to follow java.util.Date protocol
+ UErrorCode status = U_ZERO_ERROR;
+ UDate dt = cal->getTime(status);
+ releaseCalendar(cal);
+ if (U_FAILURE(status))
+ {
+ errln("FAIL: Calendar::getTime failed");
+ return 0.0;
+ }
+ return dt;
+}
+
+// Utility methods to create a date. The returned Date is UTC rather than local.
+/*Date
+CalendarTimeZoneTest::utcDate(int32_t y, int32_t m, int32_t d, int32_t hr, int32_t min, int32_t sec)
+{
+ Calendar* cal = getCalendar();
+ if (cal == 0) return 0.0;
+ UErrorCode status = U_ZERO_ERROR;
+ Date dt = date(y, m, d, hr, min, sec) +
+ cal->get(Calendar::ZONE_OFFSET, status) -
+ cal->get(Calendar::DST_OFFSET, status);
+ releaseCalendar(cal);
+ if (U_FAILURE(status))
+ {
+ errln("FAIL: Calendar::get failed");
+ return 0.0;
+ }
+ return dt;
+}*/
+
+// Mimics Date.getYear() etc.
+void
+CalendarTimeZoneTest::dateToFields(UDate date, int32_t& y, int32_t& m, int32_t& d, int32_t& hr, int32_t& min, int32_t& sec)
+{
+ Calendar* cal = getCalendar();
+ if (cal == 0) return;
+ UErrorCode status = U_ZERO_ERROR;
+ cal->setTime(date, status);
+ y = cal->get(UCAL_YEAR, status) - 1900;
+ m = cal->get(UCAL_MONTH, status);
+ d = cal->get(UCAL_DATE, status);
+ hr = cal->get(UCAL_HOUR_OF_DAY, status);
+ min = cal->get(UCAL_MINUTE, status);
+ sec = cal->get(UCAL_SECOND, status);
+ releaseCalendar(cal);
+}
+
+void CalendarTimeZoneTest::cleanup()
+{
+ delete fgDateFormat;
+ fgDateFormat = 0;
+ delete fgCalendar;
+ fgCalendar = 0;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/caltztst.h b/Build/source/libs/icu/icu-xetex/test/intltest/caltztst.h
new file mode 100644
index 00000000000..60e8447d184
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/caltztst.h
@@ -0,0 +1,65 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#ifndef _CALTZTST
+#define _CALTZTST
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/calendar.h"
+#include "unicode/datefmt.h"
+#include "intltest.h"
+
+/**
+ * This class doesn't perform any tests, but provides utility methods to its subclasses.
+ **/
+class CalendarTimeZoneTest : public IntlTest
+{
+public:
+ static void cleanup();
+protected:
+ // Return true if the given status indicates failure. Also has the side effect
+ // of calling errln(). Msg should be of the form "Class::Method" in general.
+ UBool failure(UErrorCode status, const char* msg);
+
+ // Utility method for formatting dates for printing; useful for Java->C++ conversion.
+ // Tries to mimic the Java Date.toString() format.
+ UnicodeString dateToString(UDate d);
+ UnicodeString& dateToString(UDate d, UnicodeString& str);
+ UnicodeString& dateToString(UDate d, UnicodeString& str, const TimeZone& z);
+
+ // Utility methods to create a date. This is useful for converting Java constructs
+ // which create a Date object. Returns a Date in the current local time.
+ UDate date(int32_t y, int32_t m, int32_t d, int32_t hr=0, int32_t min=0, int32_t sec=0);
+
+ // Utility methods to create a date. Returns a Date in UTC. This will differ
+ // from local dates returned by date() by the current default zone offset.
+// Date utcDate(int y, int m, int d, int hr=0, int min=0, int sec=0);
+
+ // Utility method to get the fields of a date; similar to Date.getYear() etc.
+ void dateToFields(UDate date, int32_t& y, int32_t& m, int32_t& d, int32_t& hr, int32_t& min, int32_t& sec);
+
+protected:
+ static DateFormat* fgDateFormat;
+ static Calendar* fgCalendar;
+
+ // the 'get()' functions are not static because they can call errln().
+ // they are effectively static otherwise.
+ DateFormat* getDateFormat(void);
+ static void releaseDateFormat(DateFormat *f);
+
+ Calendar* getCalendar(void);
+ static void releaseCalendar(Calendar *c);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif //_CALTZTST
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/canittst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/canittst.cpp
new file mode 100644
index 00000000000..ed04269b6d6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/canittst.cpp
@@ -0,0 +1,330 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************
+ *
+ * @author Mark E. Davis
+ * @author Vladimir Weinstein
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "intltest.h"
+#include "cstring.h"
+#include "canittst.h"
+#include "unicode/caniter.h"
+#include "unicode/normlzr.h"
+#include "unicode/uchar.h"
+#include "hash.h"
+
+#define ARRAY_LENGTH(array) ((int32_t)(sizeof (array) / sizeof (*array)))
+
+#define CASE(id,test) case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ test(); \
+ } \
+ break
+
+void CanonicalIteratorTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ CASE(0, TestBasic);
+ CASE(1, TestExhaustive);
+ CASE(2, TestAPI);
+ default: name = ""; break;
+ }
+}
+
+/**
+ * Convert Java-style strings with \u Unicode escapes into UnicodeString objects
+static UnicodeString str(const char *input)
+{
+ UnicodeString str(input, ""); // Invariant conversion
+ return str.unescape();
+}
+ */
+
+
+CanonicalIteratorTest::CanonicalIteratorTest() :
+nameTrans(NULL), hexTrans(NULL)
+{
+}
+
+CanonicalIteratorTest::~CanonicalIteratorTest()
+{
+#if !UCONFIG_NO_TRANSLITERATION
+ if(nameTrans != NULL) {
+ delete(nameTrans);
+ }
+ if(hexTrans != NULL) {
+ delete(hexTrans);
+ }
+#endif
+}
+
+void CanonicalIteratorTest::TestExhaustive() {
+ UErrorCode status = U_ZERO_ERROR;
+ CanonicalIterator it("", status);
+ UChar32 i = 0;
+ UnicodeString s;
+ // Test static and dynamic class IDs
+ if(it.getDynamicClassID() != CanonicalIterator::getStaticClassID()){
+ errln("CanonicalIterator::getStaticClassId ! = CanonicalIterator.getDynamicClassID");
+ }
+ for (i = 0; i < 0x10FFFF; quick?i+=0x10:++i) {
+ //for (i = 0xae00; i < 0xaf00; ++i) {
+
+ if ((i % 0x100) == 0) {
+ logln("Testing U+%06X", i);
+ }
+
+ // skip characters we know don't have decomps
+ int8_t type = u_charType(i);
+ if (type == U_UNASSIGNED || type == U_PRIVATE_USE_CHAR
+ || type == U_SURROGATE) continue;
+
+ s = i;
+ characterTest(s, i, it);
+
+ s += (UChar32)0x0345; //"\\u0345";
+ characterTest(s, i, it);
+ }
+}
+
+void CanonicalIteratorTest::TestBasic() {
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ static const char * const testArray[][2] = {
+ {"\\u00C5d\\u0307\\u0327", "A\\u030Ad\\u0307\\u0327, A\\u030Ad\\u0327\\u0307, A\\u030A\\u1E0B\\u0327, "
+ "A\\u030A\\u1E11\\u0307, \\u00C5d\\u0307\\u0327, \\u00C5d\\u0327\\u0307, "
+ "\\u00C5\\u1E0B\\u0327, \\u00C5\\u1E11\\u0307, \\u212Bd\\u0307\\u0327, "
+ "\\u212Bd\\u0327\\u0307, \\u212B\\u1E0B\\u0327, \\u212B\\u1E11\\u0307"},
+ {"\\u010d\\u017E", "c\\u030Cz\\u030C, c\\u030C\\u017E, \\u010Dz\\u030C, \\u010D\\u017E"},
+ {"x\\u0307\\u0327", "x\\u0307\\u0327, x\\u0327\\u0307, \\u1E8B\\u0327"},
+ };
+
+#if 0
+ // This is not interesting for C/C++ as the data is already built beforehand
+ // check build
+ UnicodeSet ss = CanonicalIterator.getSafeStart();
+ logln("Safe Start: " + ss.toPattern(true));
+ ss = CanonicalIterator.getStarts('a');
+ expectEqual("Characters with 'a' at the start of their decomposition: ", "", CanonicalIterator.getStarts('a'),
+ new UnicodeSet("[\u00E0-\u00E5\u0101\u0103\u0105\u01CE\u01DF\u01E1\u01FB"
+ + "\u0201\u0203\u0227\u1E01\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7]")
+ );
+#endif
+
+ // check permute
+ // NOTE: we use a TreeSet below to sort the output, which is not guaranteed to be sorted!
+
+ Hashtable *permutations = new Hashtable(FALSE, status);
+ permutations->setValueDeleter(uhash_deleteUnicodeString);
+ UnicodeString toPermute("ABC");
+
+ CanonicalIterator::permute(toPermute, FALSE, permutations, status);
+
+ logln("testing permutation");
+
+ expectEqual("Simple permutation ", "", collectionToString(permutations), "ABC, ACB, BAC, BCA, CAB, CBA");
+
+ delete permutations;
+
+ // try samples
+ logln("testing samples");
+ Hashtable *set = new Hashtable(FALSE, status);
+ set->setValueDeleter(uhash_deleteUnicodeString);
+ int32_t i = 0;
+ CanonicalIterator it("", status);
+ if(U_SUCCESS(status)) {
+ for (i = 0; i < ARRAY_LENGTH(testArray); ++i) {
+ //logln("Results for: " + name.transliterate(testArray[i]));
+ UnicodeString testStr = CharsToUnicodeString(testArray[i][0]);
+ it.setSource(testStr, status);
+ set->removeAll();
+ for (;;) {
+ //UnicodeString *result = new UnicodeString(it.next());
+ UnicodeString result(it.next());
+ if (result.isBogus()) {
+ break;
+ }
+ set->put(result, new UnicodeString(result), status); // Add result to the table
+ //logln(++counter + ": " + hex.transliterate(result));
+ //logln(" = " + name.transliterate(result));
+ }
+ expectEqual(i + ": ", testStr, collectionToString(set), CharsToUnicodeString(testArray[i][1]));
+
+ }
+ } else {
+ errln("Couldn't instantiate canonical iterator. Error: %s", u_errorName(status));
+ }
+ delete set;
+}
+
+void CanonicalIteratorTest::characterTest(UnicodeString &s, UChar32 ch, CanonicalIterator &it)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString decomp, comp;
+ UBool gotDecomp = FALSE;
+ UBool gotComp = FALSE;
+ UBool gotSource = FALSE;
+
+ Normalizer::decompose(s, FALSE, 0, decomp, status);
+ Normalizer::compose(s, FALSE, 0, comp, status);
+
+ // skip characters that don't have either decomp.
+ // need quick test for this!
+ if (s == decomp && s == comp) {
+ return;
+ }
+
+ it.setSource(s, status);
+
+ for (;;) {
+ UnicodeString item = it.next();
+ if (item.isBogus()) break;
+ if (item == s) gotSource = TRUE;
+ if (item == decomp) gotDecomp = TRUE;
+ if (item == comp) gotComp = TRUE;
+ }
+
+ if (!gotSource || !gotDecomp || !gotComp) {
+ errln("FAIL CanonicalIterator: " + s + (int)ch);
+ }
+}
+
+void CanonicalIteratorTest::expectEqual(const UnicodeString &message, const UnicodeString &item, const UnicodeString &a, const UnicodeString &b) {
+ if (!(a==b)) {
+ errln("FAIL: " + message + getReadable(item));
+ errln("\t" + getReadable(a));
+ errln("\t" + getReadable(b));
+ } else {
+ logln("Checked: " + message + getReadable(item));
+ logln("\t" + getReadable(a));
+ logln("\t" + getReadable(b));
+ }
+}
+
+UnicodeString CanonicalIteratorTest::getReadable(const UnicodeString &s) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString result = "[";
+ if (s.length() == 0) return "";
+ // set up for readable display
+#if !UCONFIG_NO_TRANSLITERATION
+ if(verbose) {
+ if (nameTrans == NULL)
+ nameTrans = Transliterator::createInstance("[^\\ -\\u007F] name", UTRANS_FORWARD, status);
+ UnicodeString sName = s;
+ nameTrans->transliterate(sName);
+ result += sName;
+ result += ";";
+ }
+ if (hexTrans == NULL)
+ hexTrans = Transliterator::createInstance("[^\\ -\\u007F] hex", UTRANS_FORWARD, status);
+#endif
+ UnicodeString sHex = s;
+#if !UCONFIG_NO_TRANSLITERATION
+ if(hexTrans) { // maybe there is no data and transliterator cannot be instantiated
+ hexTrans->transliterate(sHex);
+ }
+#endif
+ result += sHex;
+ result += "]";
+ return result;
+ //return "[" + (verbose ? name->transliterate(s) + "; " : "") + hex->transliterate(s) + "]";
+}
+
+U_CFUNC int U_CALLCONV
+compareUnicodeStrings(const void *s1, const void *s2) {
+ UnicodeString **st1 = (UnicodeString **)s1;
+ UnicodeString **st2 = (UnicodeString **)s2;
+
+ return (*st1)->compare(**st2);
+}
+
+
+UnicodeString CanonicalIteratorTest::collectionToString(Hashtable *col) {
+ UnicodeString result;
+
+ // Iterate over the Hashtable, then qsort.
+
+ UnicodeString **resArray = new UnicodeString*[col->count()];
+ int32_t i = 0;
+
+ const UHashElement *ne = NULL;
+ int32_t el = -1;
+ //Iterator it = basic.iterator();
+ ne = col->nextElement(el);
+ //while (it.hasNext())
+ while (ne != NULL) {
+ //String item = (String) it.next();
+ UnicodeString *item = (UnicodeString *)(ne->value.pointer);
+ resArray[i++] = item;
+ ne = col->nextElement(el);
+ }
+
+ for(i = 0; i<col->count(); ++i) {
+ logln(*resArray[i]);
+ }
+
+ qsort(resArray, col->count(), sizeof(UnicodeString *), compareUnicodeStrings);
+
+ result = *resArray[0];
+
+ for(i = 1; i<col->count(); ++i) {
+ result += ", ";
+ result += *resArray[i];
+ }
+
+/*
+ Iterator it = col.iterator();
+ while (it.hasNext()) {
+ if (result.length() != 0) result.append(", ");
+ result.append(it.next().toString());
+ }
+*/
+
+ delete [] resArray;
+
+ return result;
+}
+
+void CanonicalIteratorTest::TestAPI() {
+ UErrorCode status = U_ZERO_ERROR;
+ // Test reset and getSource
+ UnicodeString start("ljubav");
+ logln("Testing CanonicalIterator::getSource");
+ logln("Instantiating canonical iterator with string "+start);
+ CanonicalIterator can(start, status);
+ UnicodeString source = can.getSource();
+ logln("CanonicalIterator::getSource returned "+source);
+ if(start != source) {
+ errln("CanonicalIterator.getSource() didn't return the starting string. Expected "+start+", got "+source);
+ }
+ logln("Testing CanonicalIterator::reset");
+ UnicodeString next = can.next();
+ logln("CanonicalIterator::next returned "+next);
+
+ can.reset();
+
+ UnicodeString afterReset = can.next();
+ logln("After reset, CanonicalIterator::next returned "+afterReset);
+
+ if(next != afterReset) {
+ errln("Next after instantiation ("+next+") is different from next after reset ("+afterReset+").");
+ }
+
+ logln("Testing getStaticClassID and getDynamicClassID");
+ if(can.getDynamicClassID() != CanonicalIterator::getStaticClassID()){
+ errln("RTTI failed for CanonicalIterator getDynamicClassID != getStaticClassID");
+ }
+}
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/canittst.h b/Build/source/libs/icu/icu-xetex/test/intltest/canittst.h
new file mode 100644
index 00000000000..650cc089db0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/canittst.h
@@ -0,0 +1,59 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************
+ *
+ * @author Mark E. Davis
+ * @author Vladimir Weinstein
+ */
+
+/**
+ * Test Canonical Iterator
+ */
+
+#ifndef _CANITTST
+#define _CANITTST
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+
+U_NAMESPACE_BEGIN
+
+class Transliterator;
+
+U_NAMESPACE_END
+
+#include "unicode/translit.h"
+#include "unicode/caniter.h"
+#include "intltest.h"
+#include "hash.h"
+
+class CanonicalIteratorTest : public IntlTest {
+public:
+ CanonicalIteratorTest();
+ virtual ~CanonicalIteratorTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ void TestCanonicalIterator(void);
+ void TestExhaustive(void);
+ void TestBasic();
+ void TestAPI();
+ UnicodeString collectionToString(Hashtable *col);
+ //static UnicodeString collectionToString(Collection col);
+private:
+ void expectEqual(const UnicodeString &message, const UnicodeString &item, const UnicodeString &a, const UnicodeString &b);
+ void characterTest(UnicodeString &s, UChar32 ch, CanonicalIterator &it);
+
+ Transliterator *nameTrans;
+ Transliterator *hexTrans;
+
+ UnicodeString getReadable(const UnicodeString &obj);
+};
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
+
+#endif // _CANITTST
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/citrtest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/citrtest.cpp
new file mode 100644
index 00000000000..75bd1e583f7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/citrtest.cpp
@@ -0,0 +1,1185 @@
+/****************************************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ * Modification History:
+ *
+ * Date Name Description
+ * 05/22/2000 Madhu Added tests for testing new API for utf16 support and more
+ ****************************************************************************************/
+
+#include <string.h>
+#include "unicode/chariter.h"
+#include "unicode/ustring.h"
+#include "unicode/unistr.h"
+#include "unicode/schriter.h"
+#include "unicode/uchriter.h"
+#include "unicode/uiter.h"
+#include "unicode/putil.h"
+#include "citrtest.h"
+
+
+class SCharacterIterator : public CharacterIterator {
+public:
+ SCharacterIterator(const UnicodeString& textStr){
+ text = textStr;
+ pos=0;
+ textLength = textStr.length();
+ begin = 0;
+ end=textLength;
+
+ }
+
+ virtual ~SCharacterIterator(){};
+
+
+ void setText(const UnicodeString& newText){
+ text = newText;
+ }
+
+ virtual void getText(UnicodeString& result) {
+ text.extract(0,text.length(),result);
+ }
+ static UClassID getStaticClassID(void){
+ return (UClassID)(&fgClassID);
+ }
+ virtual UClassID getDynamicClassID(void) const{
+ return getStaticClassID();
+ }
+
+ virtual UBool operator==(const ForwardCharacterIterator& /*that*/) const{
+ return TRUE;
+ }
+
+ virtual CharacterIterator* clone(void) const {
+ return NULL;
+ }
+ virtual int32_t hashCode(void) const{
+ return DONE;
+ }
+ virtual UChar nextPostInc(void){ return text.charAt(pos++);}
+ virtual UChar32 next32PostInc(void){return text.char32At(pos++);}
+ virtual UBool hasNext() { return TRUE;};
+ virtual UChar first(){return DONE;};
+ virtual UChar32 first32(){return DONE;};
+ virtual UChar last(){return DONE;};
+ virtual UChar32 last32(){return DONE;};
+ virtual UChar setIndex(int32_t /*pos*/){return DONE;};
+ virtual UChar32 setIndex32(int32_t /*pos*/){return DONE;};
+ virtual UChar current() const{return DONE;};
+ virtual UChar32 current32() const{return DONE;};
+ virtual UChar next(){return DONE;};
+ virtual UChar32 next32(){return DONE;};
+ virtual UChar previous(){return DONE;};
+ virtual UChar32 previous32(){return DONE;};
+ virtual int32_t move(int32_t delta,CharacterIterator::EOrigin origin){
+ switch(origin) {
+ case kStart:
+ pos = begin + delta;
+ break;
+ case kCurrent:
+ pos += delta;
+ break;
+ case kEnd:
+ pos = end + delta;
+ break;
+ default:
+ break;
+ }
+
+ if(pos < begin) {
+ pos = begin;
+ } else if(pos > end) {
+ pos = end;
+ }
+
+ return pos;
+ };
+ virtual int32_t move32(int32_t delta, CharacterIterator::EOrigin origin){
+ switch(origin) {
+ case kStart:
+ pos = begin;
+ if(delta > 0) {
+ UTF_FWD_N(text, pos, end, delta);
+ }
+ break;
+ case kCurrent:
+ if(delta > 0) {
+ UTF_FWD_N(text, pos, end, delta);
+ } else {
+ UTF_BACK_N(text, begin, pos, -delta);
+ }
+ break;
+ case kEnd:
+ pos = end;
+ if(delta < 0) {
+ UTF_BACK_N(text, begin, pos, -delta);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return pos;
+ };
+ virtual UBool hasPrevious() {return TRUE;};
+
+ SCharacterIterator& operator=(const SCharacterIterator& that){
+ text = that.text;
+ return *this;
+ }
+
+
+private:
+ UnicodeString text;
+ static const char fgClassID;
+};
+const char SCharacterIterator::fgClassID=0;
+
+#define LENGTHOF(array) ((int32_t)(sizeof(array)/sizeof((array)[0])))
+
+CharIterTest::CharIterTest()
+{
+}
+void CharIterTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CharIterTest: ");
+ switch (index) {
+ case 0: name = "TestConstructionAndEquality"; if (exec) TestConstructionAndEquality(); break;
+ case 1: name = "TestConstructionAndEqualityUChariter"; if (exec) TestConstructionAndEqualityUChariter(); break;
+ case 2: name = "TestIteration"; if (exec) TestIteration(); break;
+ case 3: name = "TestIterationUChar32"; if (exec) TestIterationUChar32(); break;
+ case 4: name = "TestUCharIterator"; if (exec) TestUCharIterator(); break;
+ case 5: name = "TestCoverage"; if(exec) TestCoverage(); break;
+ case 6: name = "TestCharIteratorSubClasses"; if (exec) TestCharIteratorSubClasses(); break;
+ default: name = ""; break; //needed to end loop
+ }
+}
+
+void CharIterTest::TestCoverage(){
+ UnicodeString testText("Now is the time for all good men to come to the aid of their country.");
+ UnicodeString testText2("\\ud800\\udc01deadbeef");
+ testText2 = testText2.unescape();
+ SCharacterIterator* test = new SCharacterIterator(testText);
+ if(test->firstPostInc()!= 0x004E){
+ errln("Failed: firstPostInc() failed");
+ }
+ if(test->getIndex()!=1){
+ errln("Failed: getIndex().");
+ }
+ if(test->getLength()!=testText.length()){
+ errln("Failed: getLength()");
+ }
+ test->setToStart();
+ if(test->getIndex()!=0){
+ errln("Failed: setToStart().");
+ }
+ test->setToEnd();
+ if(test->getIndex()!=testText.length()){
+ errln("Failed: setToEnd().");
+ }
+ if(test->startIndex() != 0){
+ errln("Failed: startIndex()");
+ }
+ test->setText(testText2);
+ if(test->first32PostInc()!= testText2.char32At(0)){
+ errln("Failed: first32PostInc() failed");
+ }
+
+ delete test;
+
+}
+void CharIterTest::TestConstructionAndEquality() {
+ UnicodeString testText("Now is the time for all good men to come to the aid of their country.");
+ UnicodeString testText2("Don't bother using this string.");
+ UnicodeString result1, result2, result3;
+
+ CharacterIterator* test1 = new StringCharacterIterator(testText);
+ CharacterIterator* test1b= new StringCharacterIterator(testText, -1);
+ CharacterIterator* test1c= new StringCharacterIterator(testText, 100);
+ CharacterIterator* test1d= new StringCharacterIterator(testText, -2, 100, 5);
+ CharacterIterator* test1e= new StringCharacterIterator(testText, 100, 20, 5);
+ CharacterIterator* test2 = new StringCharacterIterator(testText, 5);
+ CharacterIterator* test3 = new StringCharacterIterator(testText, 2, 20, 5);
+ CharacterIterator* test4 = new StringCharacterIterator(testText2);
+ CharacterIterator* test5 = test1->clone();
+
+ if (test1d->startIndex() < 0)
+ errln("Construction failed: startIndex is negative");
+ if (test1d->endIndex() > testText.length())
+ errln("Construction failed: endIndex is greater than the text length");
+ if (test1d->getIndex() < test1d->startIndex() || test1d->endIndex() < test1d->getIndex())
+ errln("Construction failed: index is invalid");
+
+ if (*test1 == *test2 || *test1 == *test3 || *test1 == *test4)
+ errln("Construction or operator== failed: Unequal objects compared equal");
+ if (*test1 != *test5)
+ errln("clone() or equals() failed: Two clones tested unequal");
+
+ if (test1->hashCode() == test2->hashCode() || test1->hashCode() == test3->hashCode()
+ || test1->hashCode() == test4->hashCode())
+ errln("hashCode() failed: different objects have same hash code");
+
+ if (test1->hashCode() != test5->hashCode())
+ errln("hashCode() failed: identical objects have different hash codes");
+
+ if(test1->getLength() != testText.length()){
+ errln("getLength of CharacterIterator failed");
+ }
+ test1->getText(result1);
+ test1b->getText(result2);
+ test1c->getText(result3);
+ if(result1 != result2 || result1 != result3)
+ errln("construction failed or getText() failed");
+
+
+ test1->setIndex(5);
+ if (*test1 != *test2 || *test1 == *test5)
+ errln("setIndex() failed");
+
+ *((StringCharacterIterator*)test1) = *((StringCharacterIterator*)test3);
+ if (*test1 != *test3 || *test1 == *test5)
+ errln("operator= failed");
+
+ delete test2;
+ delete test3;
+ delete test4;
+ delete test5;
+ delete test1b;
+ delete test1c;
+ delete test1d;
+ delete test1e;
+
+
+ StringCharacterIterator* testChar1=new StringCharacterIterator(testText);
+ StringCharacterIterator* testChar2=new StringCharacterIterator(testText2);
+ StringCharacterIterator* testChar3=(StringCharacterIterator*)test1->clone();
+
+ testChar1->getText(result1);
+ testChar2->getText(result2);
+ testChar3->getText(result3);
+ if(result1 != result3 || result1 == result2)
+ errln("getText() failed");
+ testChar3->setText(testText2);
+ testChar3->getText(result3);
+ if(result1 == result3 || result2 != result3)
+ errln("setText() or getText() failed");
+ testChar3->setText(testText);
+ testChar3->getText(result3);
+ if(result1 != result3 || result1 == result2)
+ errln("setText() or getText() round-trip failed");
+
+ delete testChar1;
+ delete testChar2;
+ delete testChar3;
+ delete test1;
+
+}
+void CharIterTest::TestConstructionAndEqualityUChariter() {
+ U_STRING_DECL(testText, "Now is the time for all good men to come to the aid of their country.", 69);
+ U_STRING_DECL(testText2, "Don't bother using this string.", 31);
+
+ U_STRING_INIT(testText, "Now is the time for all good men to come to the aid of their country.", 69);
+ U_STRING_INIT(testText2, "Don't bother using this string.", 31);
+
+ UnicodeString result, result4, result5;
+
+ UCharCharacterIterator* test1 = new UCharCharacterIterator(testText, u_strlen(testText));
+ UCharCharacterIterator* test2 = new UCharCharacterIterator(testText, u_strlen(testText), 5);
+ UCharCharacterIterator* test3 = new UCharCharacterIterator(testText, u_strlen(testText), 2, 20, 5);
+ UCharCharacterIterator* test4 = new UCharCharacterIterator(testText2, u_strlen(testText2));
+ UCharCharacterIterator* test5 = (UCharCharacterIterator*)test1->clone();
+ UCharCharacterIterator* test6 = new UCharCharacterIterator(*test1);
+
+ // j785: length=-1 will use u_strlen()
+ UCharCharacterIterator* test7a = new UCharCharacterIterator(testText, -1);
+ UCharCharacterIterator* test7b = new UCharCharacterIterator(testText, -1);
+ UCharCharacterIterator* test7c = new UCharCharacterIterator(testText, -1, 2, 20, 5);
+
+ // Bad parameters.
+ UCharCharacterIterator* test8a = new UCharCharacterIterator(testText, -1, -1, 20, 5);
+ UCharCharacterIterator* test8b = new UCharCharacterIterator(testText, -1, 2, 100, 5);
+ UCharCharacterIterator* test8c = new UCharCharacterIterator(testText, -1, 2, 20, 100);
+
+ if (test8a->startIndex() < 0)
+ errln("Construction failed: startIndex is negative");
+ if (test8b->endIndex() != u_strlen(testText))
+ errln("Construction failed: endIndex is different from the text length");
+ if (test8c->getIndex() < test8c->startIndex() || test8c->endIndex() < test8c->getIndex())
+ errln("Construction failed: index is invalid");
+
+ if (*test1 == *test2 || *test1 == *test3 || *test1 == *test4 )
+ errln("Construction or operator== failed: Unequal objects compared equal");
+ if (*test1 != *test5 )
+ errln("clone() or equals() failed: Two clones tested unequal");
+
+ if (*test6 != *test1 )
+ errln("copy construction or equals() failed: Two copies tested unequal");
+
+ if (test1->hashCode() == test2->hashCode() || test1->hashCode() == test3->hashCode()
+ || test1->hashCode() == test4->hashCode())
+ errln("hashCode() failed: different objects have same hash code");
+
+ if (test1->hashCode() != test5->hashCode())
+ errln("hashCode() failed: identical objects have different hash codes");
+
+ test7a->getText(result);
+ test7b->getText(result4);
+ test7c->getText(result5);
+
+ if(result != UnicodeString(testText) || result4 != result || result5 != result)
+ errln("error in construction");
+
+ test1->getText(result);
+ test4->getText(result4);
+ test5->getText(result5);
+ if(result != result5 || result == result4)
+ errln("getText() failed");
+ test5->setText(testText2, u_strlen(testText2));
+ test5->getText(result5);
+ if(result == result5 || result4 != result5)
+ errln("setText() or getText() failed");
+ test5->setText(testText, u_strlen(testText));
+ test5->getText(result5);
+ if(result != result5 || result == result4)
+ errln("setText() or getText() round-trip failed");
+
+
+ test1->setIndex(5);
+ if (*test1 != *test2 || *test1 == *test5)
+ errln("setIndex() failed");
+ test8b->setIndex32(5);
+ if (test8b->getIndex()!=5)
+ errln("setIndex32() failed");
+
+ *test1 = *test3;
+ if (*test1 != *test3 || *test1 == *test5)
+ errln("operator= failed");
+
+ delete test1;
+ delete test2;
+ delete test3;
+ delete test4;
+ delete test5;
+ delete test6;
+ delete test7a;
+ delete test7b;
+ delete test7c;
+ delete test8a;
+ delete test8b;
+ delete test8c;
+}
+
+
+void CharIterTest::TestIteration() {
+ UnicodeString text("Now is the time for all good men to come to the aid of their country.");
+
+ UChar c;
+ int32_t i;
+ {
+ StringCharacterIterator iter(text, 5);
+
+ UnicodeString iterText;
+ iter.getText(iterText);
+ if (iterText != text)
+ errln("iter.getText() failed");
+
+ if (iter.current() != text[(int32_t)5])
+ errln("Iterator didn't start out in the right place.");
+
+ c = iter.first();
+ i = 0;
+
+ if (iter.startIndex() != 0 || iter.endIndex() != text.length())
+ errln("startIndex() or endIndex() failed");
+
+ logln("Testing forward iteration...");
+ do {
+ if (c == CharacterIterator::DONE && i != text.length())
+ errln("Iterator reached end prematurely");
+ else if (c != text[i])
+ errln((UnicodeString)"Character mismatch at position " + i +
+ ", iterator has " + UCharToUnicodeString(c) +
+ ", string has " + UCharToUnicodeString(text[i]));
+
+ if (iter.current() != c)
+ errln("current() isn't working right");
+ if (iter.getIndex() != i)
+ errln("getIndex() isn't working right");
+
+ if (c != CharacterIterator::DONE) {
+ c = iter.next();
+ i++;
+ }
+ } while (c != CharacterIterator::DONE);
+ c=iter.next();
+ if(c!= CharacterIterator::DONE)
+ errln("next() didn't return DONE at the end");
+ c=iter.setIndex(text.length()+1);
+ if(c!= CharacterIterator::DONE)
+ errln("setIndex(len+1) didn't return DONE");
+
+ c = iter.last();
+ i = text.length() - 1;
+
+ logln("Testing backward iteration...");
+ do {
+ if (c == CharacterIterator::DONE && i >= 0)
+ errln("Iterator reached end prematurely");
+ else if (c != text[i])
+ errln((UnicodeString)"Character mismatch at position " + i +
+ ", iterator has " + UCharToUnicodeString(c) +
+ ", string has " + UCharToUnicodeString(text[i]));
+
+ if (iter.current() != c)
+ errln("current() isn't working right");
+ if (iter.getIndex() != i)
+ errln("getIndex() isn't working right");
+ if(iter.setIndex(i) != c)
+ errln("setIndex() isn't working right");
+
+ if (c != CharacterIterator::DONE) {
+ c = iter.previous();
+ i--;
+ }
+ } while (c != CharacterIterator::DONE);
+
+ c=iter.previous();
+ if(c!= CharacterIterator::DONE)
+ errln("previous didn't return DONE at the beginning");
+
+
+ //testing firstPostInc, nextPostInc, setTostart
+ i = 0;
+ c=iter.firstPostInc();
+ if(c != text[i])
+ errln((UnicodeString)"firstPostInc failed. Expected->" +
+ UCharToUnicodeString(text[i]) + " Got->" + UCharToUnicodeString(c));
+ if(iter.getIndex() != i+1)
+ errln((UnicodeString)"getIndex() after firstPostInc() failed");
+
+ iter.setToStart();
+ i=0;
+ if (iter.startIndex() != 0)
+ errln("setToStart failed");
+
+ logln("Testing forward iteration...");
+ do {
+ if (c != CharacterIterator::DONE)
+ c = iter.nextPostInc();
+
+ if(c != text[i])
+ errln((UnicodeString)"Character mismatch at position " + i +
+ (UnicodeString)", iterator has " + UCharToUnicodeString(c) +
+ (UnicodeString)", string has " + UCharToUnicodeString(text[i]));
+
+ i++;
+ if(iter.getIndex() != i)
+ errln("getIndex() aftr nextPostInc() isn't working right");
+ if(iter.current() != text[i])
+ errln("current() after nextPostInc() isn't working right");
+ } while (iter.hasNext());
+ c=iter.nextPostInc();
+ if(c!= CharacterIterator::DONE)
+ errln("nextPostInc() didn't return DONE at the beginning");
+ }
+
+ {
+ StringCharacterIterator iter(text, 5, 15, 10);
+ if (iter.startIndex() != 5 || iter.endIndex() != 15)
+ errln("creation of a restricted-range iterator failed");
+
+ if (iter.getIndex() != 10 || iter.current() != text[(int32_t)10])
+ errln("starting the iterator in the middle didn't work");
+
+ c = iter.first();
+ i = 5;
+
+ logln("Testing forward iteration over a range...");
+ do {
+ if (c == CharacterIterator::DONE && i != 15)
+ errln("Iterator reached end prematurely");
+ else if (c != text[i])
+ errln((UnicodeString)"Character mismatch at position " + i +
+ ", iterator has " + UCharToUnicodeString(c) +
+ ", string has " + UCharToUnicodeString(text[i]));
+
+ if (iter.current() != c)
+ errln("current() isn't working right");
+ if (iter.getIndex() != i)
+ errln("getIndex() isn't working right");
+ if(iter.setIndex(i) != c)
+ errln("setIndex() isn't working right");
+
+ if (c != CharacterIterator::DONE) {
+ c = iter.next();
+ i++;
+ }
+ } while (c != CharacterIterator::DONE);
+
+ c = iter.last();
+ i = 14;
+
+ logln("Testing backward iteration over a range...");
+ do {
+ if (c == CharacterIterator::DONE && i >= 5)
+ errln("Iterator reached end prematurely");
+ else if (c != text[i])
+ errln((UnicodeString)"Character mismatch at position " + i +
+ ", iterator has " + UCharToUnicodeString(c) +
+ ", string has " + UCharToUnicodeString(text[i]));
+
+ if (iter.current() != c)
+ errln("current() isn't working right");
+ if (iter.getIndex() != i)
+ errln("getIndex() isn't working right");
+
+ if (c != CharacterIterator::DONE) {
+ c = iter.previous();
+ i--;
+ }
+ } while (c != CharacterIterator::DONE);
+
+
+ }
+}
+
+//Tests for new API for utf-16 support
+void CharIterTest::TestIterationUChar32() {
+ UChar textChars[]={ 0x0061, 0x0062, 0xd841, 0xdc02, 0x20ac, 0xd7ff, 0xd842, 0xdc06, 0xd801, 0xdc00, 0x0061, 0x0000};
+ UnicodeString text(textChars);
+ UChar32 c;
+ int32_t i;
+ {
+ StringCharacterIterator iter(text, 1);
+
+ UnicodeString iterText;
+ iter.getText(iterText);
+ if (iterText != text)
+ errln("iter.getText() failed");
+
+ if (iter.current32() != text[(int32_t)1])
+ errln("Iterator didn't start out in the right place.");
+
+ c=iter.setToStart();
+ i=0;
+ i=iter.move32(1, CharacterIterator::kStart);
+ c=iter.current32();
+ if(c != text.char32At(1) || i!=1)
+ errln("move32(1, kStart) didn't work correctly expected %X got %X", c, text.char32At(1) );
+
+ i=iter.move32(2, CharacterIterator::kCurrent);
+ c=iter.current32();
+ if(c != text.char32At(4) || i!=4)
+ errln("move32(2, kCurrent) didn't work correctly expected %X got %X i=%ld", c, text.char32At(4), i);
+
+ i=iter.move32(-2, CharacterIterator::kCurrent);
+ c=iter.current32();
+ if(c != text.char32At(1) || i!=1)
+ errln("move32(-2, kCurrent) didn't work correctly expected %X got %X i=%d", c, text.char32At(1), i);
+
+
+ i=iter.move32(-2, CharacterIterator::kEnd);
+ c=iter.current32();
+ if(c != text.char32At((text.length()-3)) || i!=(text.length()-3))
+ errln("move32(-2, kEnd) didn't work correctly expected %X got %X i=%d", c, text.char32At((text.length()-3)), i);
+
+
+ c = iter.first32();
+ i = 0;
+
+ if (iter.startIndex() != 0 || iter.endIndex() != text.length())
+ errln("startIndex() or endIndex() failed");
+
+ logln("Testing forward iteration...");
+ do {
+ /* logln("c=%d i=%d char32At=%d", c, i, text.char32At(i)); */
+ if (c == CharacterIterator::DONE && i != text.length())
+ errln("Iterator reached end prematurely");
+ else if(iter.hasNext() == FALSE && i != text.length())
+ errln("Iterator reached end prematurely. Failed at hasNext");
+ else if (c != text.char32At(i))
+ errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
+
+ if (iter.current32() != c)
+ errln("current32() isn't working right");
+ if(iter.setIndex32(i) != c)
+ errln("setIndex32() isn't working right");
+ if (c != CharacterIterator::DONE) {
+ c = iter.next32();
+ i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i+2 : i+1;
+ }
+ } while (c != CharacterIterator::DONE);
+ if(iter.hasNext() == TRUE)
+ errln("hasNext() returned true at the end of the string");
+
+
+
+ c=iter.setToEnd();
+ if(iter.getIndex() != text.length() || iter.hasNext() != FALSE)
+ errln("setToEnd failed");
+
+ c=iter.next32();
+ if(c!= CharacterIterator::DONE)
+ errln("next32 didn't return DONE at the end");
+ c=iter.setIndex32(text.length()+1);
+ if(c!= CharacterIterator::DONE)
+ errln("setIndex32(len+1) didn't return DONE");
+
+
+ c = iter.last32();
+ i = text.length()-1;
+ logln("Testing backward iteration...");
+ do {
+ if (c == CharacterIterator::DONE && i >= 0)
+ errln((UnicodeString)"Iterator reached start prematurely for i=" + i);
+ else if(iter.hasPrevious() == FALSE && i>0)
+ errln((UnicodeString)"Iterator reached start prematurely for i=" + i);
+ else if (c != text.char32At(i))
+ errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
+
+ if (iter.current32() != c)
+ errln("current32() isn't working right");
+ if(iter.setIndex32(i) != c)
+ errln("setIndex32() isn't working right");
+ if (iter.getIndex() != i)
+ errln("getIndex() isn't working right");
+ if (c != CharacterIterator::DONE) {
+ c = iter.previous32();
+ i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i-2 : i-1;
+ }
+ } while (c != CharacterIterator::DONE);
+ if(iter.hasPrevious() == TRUE)
+ errln("hasPrevious returned true after reaching the start");
+
+ c=iter.previous32();
+ if(c!= CharacterIterator::DONE)
+ errln("previous32 didn't return DONE at the beginning");
+
+
+
+
+ //testing first32PostInc, next32PostInc, setTostart
+ i = 0;
+ c=iter.first32PostInc();
+ if(c != text.char32At(i))
+ errln("first32PostInc failed. Expected->%X Got->%X", text.char32At(i), c);
+ if(iter.getIndex() != UTF16_CHAR_LENGTH(c) + i)
+ errln((UnicodeString)"getIndex() after first32PostInc() failed");
+
+ iter.setToStart();
+ i=0;
+ if (iter.startIndex() != 0)
+ errln("setToStart failed");
+
+ logln("Testing forward iteration...");
+ do {
+ if (c != CharacterIterator::DONE)
+ c = iter.next32PostInc();
+
+ if(c != text.char32At(i))
+ errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
+
+ i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i+2 : i+1;
+ if(iter.getIndex() != i)
+ errln("getIndex() aftr next32PostInc() isn't working right");
+ if(iter.current32() != text.char32At(i))
+ errln("current() after next32PostInc() isn't working right");
+ } while (iter.hasNext());
+ c=iter.next32PostInc();
+ if(c!= CharacterIterator::DONE)
+ errln("next32PostInc() didn't return DONE at the beginning");
+
+
+ }
+
+ {
+ StringCharacterIterator iter(text, 1, 11, 10);
+ if (iter.startIndex() != 1 || iter.endIndex() != 11)
+ errln("creation of a restricted-range iterator failed");
+
+ if (iter.getIndex() != 10 || iter.current32() != text.char32At(10))
+ errln("starting the iterator in the middle didn't work");
+
+ c = iter.first32();
+
+ i = 1;
+
+ logln("Testing forward iteration over a range...");
+ do {
+ if (c == CharacterIterator::DONE && i != 11)
+ errln("Iterator reached end prematurely");
+ else if(iter.hasNext() == FALSE)
+ errln("Iterator reached end prematurely");
+ else if (c != text.char32At(i))
+ errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
+
+ if (iter.current32() != c)
+ errln("current32() isn't working right");
+ if(iter.setIndex32(i) != c)
+ errln("setIndex32() isn't working right");
+
+ if (c != CharacterIterator::DONE) {
+ c = iter.next32();
+ i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i+2 : i+1;
+ }
+ } while (c != CharacterIterator::DONE);
+ c=iter.next32();
+ if(c != CharacterIterator::DONE)
+ errln("error in next32()");
+
+
+
+ c=iter.last32();
+ i = 10;
+ logln("Testing backward iteration over a range...");
+ do {
+ if (c == CharacterIterator::DONE && i >= 5)
+ errln("Iterator reached start prematurely");
+ else if(iter.hasPrevious() == FALSE && i > 5)
+ errln("Iterator reached start prematurely");
+ else if (c != text.char32At(i))
+ errln("Character mismatch at position %d, iterator has %X, string has %X", i, c, text.char32At(i));
+ if (iter.current32() != c)
+ errln("current32() isn't working right");
+ if (iter.getIndex() != i)
+ errln("getIndex() isn't working right");
+ if(iter.setIndex32(i) != c)
+ errln("setIndex32() isn't working right");
+
+ if (c != CharacterIterator::DONE) {
+ c = iter.previous32();
+ i=UTF16_NEED_MULTIPLE_UCHAR(c) ? i-2 : i-1;
+ }
+
+ } while (c != CharacterIterator::DONE);
+ c=iter.previous32();
+ if(c!= CharacterIterator::DONE)
+ errln("error on previous32");
+
+
+ }
+}
+
+void CharIterTest::TestUCharIterator(UCharIterator *iter, CharacterIterator &ci,
+ const char *moves, const char *which) {
+ int32_t m;
+ UChar32 c, c2;
+ UBool h, h2;
+
+ for(m=0;; ++m) {
+ // move both iter and s[index]
+ switch(moves[m]) {
+ case '0':
+ h=iter->hasNext(iter);
+ h2=ci.hasNext();
+ c=iter->current(iter);
+ c2=ci.current();
+ break;
+ case '|':
+ h=iter->hasNext(iter);
+ h2=ci.hasNext();
+ c=uiter_current32(iter);
+ c2=ci.current32();
+ break;
+
+ case '+':
+ h=iter->hasNext(iter);
+ h2=ci.hasNext();
+ c=iter->next(iter);
+ c2=ci.nextPostInc();
+ break;
+ case '>':
+ h=iter->hasNext(iter);
+ h2=ci.hasNext();
+ c=uiter_next32(iter);
+ c2=ci.next32PostInc();
+ break;
+
+ case '-':
+ h=iter->hasPrevious(iter);
+ h2=ci.hasPrevious();
+ c=iter->previous(iter);
+ c2=ci.previous();
+ break;
+ case '<':
+ h=iter->hasPrevious(iter);
+ h2=ci.hasPrevious();
+ c=uiter_previous32(iter);
+ c2=ci.previous32();
+ break;
+
+ case '2':
+ h=h2=FALSE;
+ c=(UChar32)iter->move(iter, 2, UITER_CURRENT);
+ c2=(UChar32)ci.move(2, CharacterIterator::kCurrent);
+ break;
+
+ case '8':
+ h=h2=FALSE;
+ c=(UChar32)iter->move(iter, -2, UITER_CURRENT);
+ c2=(UChar32)ci.move(-2, CharacterIterator::kCurrent);
+ break;
+
+ case 0:
+ return;
+ default:
+ errln("error: unexpected move character '%c' in \"%s\"", moves[m], moves);
+ return;
+ }
+
+ // compare results
+ if(c2==0xffff) {
+ c2=(UChar32)-1;
+ }
+ if(c!=c2 || h!=h2 || ci.getIndex()!=iter->getIndex(iter, UITER_CURRENT)) {
+ errln("error: UCharIterator(%s) misbehaving at \"%s\"[%d]='%c'", which, moves, m, moves[m]);
+ }
+ }
+}
+
+void CharIterTest::TestUCharIterator() {
+ // test string of length 8
+ UnicodeString s=UnicodeString("a \\U00010001b\\U0010fffdz", "").unescape();
+ const char *const moves=
+ "0+++++++++" // 10 moves per line
+ "----0-----"
+ ">>|>>>>>>>"
+ "<<|<<<<<<<"
+ "22+>8>-8+2";
+
+ StringCharacterIterator sci(s), compareCI(s);
+
+ UCharIterator sIter, cIter, rIter;
+
+ uiter_setString(&sIter, s.getBuffer(), s.length());
+ uiter_setCharacterIterator(&cIter, &sci);
+ uiter_setReplaceable(&rIter, &s);
+
+ TestUCharIterator(&sIter, compareCI, moves, "uiter_setString");
+ compareCI.setIndex(0);
+ TestUCharIterator(&cIter, compareCI, moves, "uiter_setCharacterIterator");
+ compareCI.setIndex(0);
+ TestUCharIterator(&rIter, compareCI, moves, "uiter_setReplaceable");
+
+ // test move & getIndex some more
+ sIter.start=2;
+ sIter.index=3;
+ sIter.limit=5;
+ if( sIter.getIndex(&sIter, UITER_ZERO)!=0 ||
+ sIter.getIndex(&sIter, UITER_START)!=2 ||
+ sIter.getIndex(&sIter, UITER_CURRENT)!=3 ||
+ sIter.getIndex(&sIter, UITER_LIMIT)!=5 ||
+ sIter.getIndex(&sIter, UITER_LENGTH)!=s.length()
+ ) {
+ errln("error: UCharIterator(string).getIndex returns wrong index");
+ }
+
+ if( sIter.move(&sIter, 4, UITER_ZERO)!=4 ||
+ sIter.move(&sIter, 1, UITER_START)!=3 ||
+ sIter.move(&sIter, 3, UITER_CURRENT)!=5 ||
+ sIter.move(&sIter, -1, UITER_LIMIT)!=4 ||
+ sIter.move(&sIter, -5, UITER_LENGTH)!=3 ||
+ sIter.move(&sIter, 0, UITER_CURRENT)!=sIter.getIndex(&sIter, UITER_CURRENT) ||
+ sIter.getIndex(&sIter, UITER_CURRENT)!=3
+ ) {
+ errln("error: UCharIterator(string).move sets/returns wrong index");
+ }
+
+ sci=StringCharacterIterator(s, 2, 5, 3);
+ uiter_setCharacterIterator(&cIter, &sci);
+ if( cIter.getIndex(&cIter, UITER_ZERO)!=0 ||
+ cIter.getIndex(&cIter, UITER_START)!=2 ||
+ cIter.getIndex(&cIter, UITER_CURRENT)!=3 ||
+ cIter.getIndex(&cIter, UITER_LIMIT)!=5 ||
+ cIter.getIndex(&cIter, UITER_LENGTH)!=s.length()
+ ) {
+ errln("error: UCharIterator(character iterator).getIndex returns wrong index");
+ }
+
+ if( cIter.move(&cIter, 4, UITER_ZERO)!=4 ||
+ cIter.move(&cIter, 1, UITER_START)!=3 ||
+ cIter.move(&cIter, 3, UITER_CURRENT)!=5 ||
+ cIter.move(&cIter, -1, UITER_LIMIT)!=4 ||
+ cIter.move(&cIter, -5, UITER_LENGTH)!=3 ||
+ cIter.move(&cIter, 0, UITER_CURRENT)!=cIter.getIndex(&cIter, UITER_CURRENT) ||
+ cIter.getIndex(&cIter, UITER_CURRENT)!=3
+ ) {
+ errln("error: UCharIterator(character iterator).move sets/returns wrong index");
+ }
+
+
+ if(cIter.getIndex(&cIter, (enum UCharIteratorOrigin)-1) != -1)
+ {
+ errln("error: UCharIterator(char iter).getIndex did not return error value");
+ }
+
+ if(cIter.move(&cIter, 0, (enum UCharIteratorOrigin)-1) != -1)
+ {
+ errln("error: UCharIterator(char iter).move did not return error value");
+ }
+
+
+ if(rIter.getIndex(&rIter, (enum UCharIteratorOrigin)-1) != -1)
+ {
+ errln("error: UCharIterator(repl iter).getIndex did not return error value");
+ }
+
+ if(rIter.move(&rIter, 0, (enum UCharIteratorOrigin)-1) != -1)
+ {
+ errln("error: UCharIterator(repl iter).move did not return error value");
+ }
+
+
+ if(sIter.getIndex(&sIter, (enum UCharIteratorOrigin)-1) != -1)
+ {
+ errln("error: UCharIterator(string iter).getIndex did not return error value");
+ }
+
+ if(sIter.move(&sIter, 0, (enum UCharIteratorOrigin)-1) != -1)
+ {
+ errln("error: UCharIterator(string iter).move did not return error value");
+ }
+
+ /* Testing function coverage on bad input */
+ UErrorCode status = U_ZERO_ERROR;
+ uiter_setString(&sIter, NULL, 1);
+ uiter_setState(&sIter, 1, &status);
+ if (status != U_UNSUPPORTED_ERROR) {
+ errln("error: uiter_setState returned %s instead of U_UNSUPPORTED_ERROR", u_errorName(status));
+ }
+ status = U_ZERO_ERROR;
+ uiter_setState(NULL, 1, &status);
+ if (status != U_ILLEGAL_ARGUMENT_ERROR) {
+ errln("error: uiter_setState returned %s instead of U_ILLEGAL_ARGUMENT_ERROR", u_errorName(status));
+ }
+ if (uiter_getState(&sIter) != UITER_NO_STATE) {
+ errln("error: uiter_getState did not return UITER_NO_STATE on bad input");
+ }
+}
+
+// subclass test, and completing API coverage -------------------------------
+
+class SubCharIter : public CharacterIterator {
+public:
+ // public default constructor, to get coverage of CharacterIterator()
+ SubCharIter() : CharacterIterator() {
+ textLength=end=LENGTHOF(s);
+ s[0]=0x61; // 'a'
+ s[1]=0xd900; // U+50400
+ s[2]=0xdd00;
+ s[3]=0x2029; // PS
+ }
+
+ // useful stuff, mostly dummy but testing coverage and subclassability
+ virtual UChar nextPostInc() {
+ if(pos<LENGTHOF(s)) {
+ return s[pos++];
+ } else {
+ return DONE;
+ }
+ }
+
+ virtual UChar32 next32PostInc() {
+ if(pos<LENGTHOF(s)) {
+ UChar32 c;
+ U16_NEXT(s, pos, LENGTHOF(s), c);
+ return c;
+ } else {
+ return DONE;
+ }
+ }
+
+ virtual UBool hasNext() {
+ return pos<LENGTHOF(s);
+ }
+
+ virtual UChar first() {
+ pos=0;
+ return s[0];
+ }
+
+ virtual UChar32 first32() {
+ UChar32 c;
+ pos=0;
+ U16_NEXT(s, pos, LENGTHOF(s), c);
+ pos=0;
+ return c;
+ }
+
+ virtual UChar setIndex(int32_t position) {
+ if(0<=position && position<=LENGTHOF(s)) {
+ pos=position;
+ if(pos<LENGTHOF(s)) {
+ return s[pos];
+ }
+ }
+ return DONE;
+ }
+
+ virtual UChar32 setIndex32(int32_t position) {
+ if(0<=position && position<=LENGTHOF(s)) {
+ pos=position;
+ if(pos<LENGTHOF(s)) {
+ UChar32 c;
+ U16_GET(s, 0, pos, LENGTHOF(s), c);
+ return c;
+ }
+ }
+ return DONE;
+ }
+
+ virtual UChar current() const {
+ if(pos<LENGTHOF(s)) {
+ return s[pos];
+ } else {
+ return DONE;
+ }
+ }
+
+ virtual UChar32 current32() const {
+ if(pos<LENGTHOF(s)) {
+ UChar32 c;
+ U16_GET(s, 0, pos, LENGTHOF(s), c);
+ return c;
+ } else {
+ return DONE;
+ }
+ }
+
+ virtual UChar next() {
+ if(pos<LENGTHOF(s) && ++pos<LENGTHOF(s)) {
+ return s[pos];
+ } else {
+ return DONE;
+ }
+ }
+
+ virtual UChar32 next32() {
+ if(pos<LENGTHOF(s)) {
+ U16_FWD_1(s, pos, LENGTHOF(s));
+ }
+ if(pos<LENGTHOF(s)) {
+ UChar32 c;
+ int32_t i=pos;
+ U16_NEXT(s, i, LENGTHOF(s), c);
+ return c;
+ } else {
+ return DONE;
+ }
+ }
+
+ virtual UBool hasPrevious() {
+ return pos>0;
+ }
+
+ virtual void getText(UnicodeString &result) {
+ result.setTo(s, LENGTHOF(s));
+ }
+
+ // dummy implementations of other pure virtual base class functions
+ virtual UBool operator==(const ForwardCharacterIterator &that) const {
+ return
+ this==&that ||
+ getDynamicClassID()==that.getDynamicClassID() && pos==((SubCharIter &)that).pos;
+ }
+
+ virtual int32_t hashCode() const {
+ return 2;
+ }
+
+ virtual CharacterIterator *clone() const {
+ return NULL;
+ }
+
+ virtual UChar last() {
+ return 0;
+ }
+
+ virtual UChar32 last32() {
+ return 0;
+ }
+
+ virtual UChar previous() {
+ return 0;
+ }
+
+ virtual UChar32 previous32() {
+ return 0;
+ }
+
+ virtual int32_t move(int32_t /*delta*/, EOrigin /*origin*/) {
+ return 0;
+ }
+
+ virtual int32_t move32(int32_t /*delta*/, EOrigin /*origin*/) {
+ return 0;
+ }
+
+ // RTTI
+ static UClassID getStaticClassID() {
+ return (UClassID)(&fgClassID);
+ }
+
+ virtual UClassID getDynamicClassID() const {
+ return getStaticClassID();
+ }
+
+private:
+ // dummy string data
+ UChar s[4];
+
+ static const char fgClassID;
+};
+
+const char SubCharIter::fgClassID = 0;
+
+class SubStringCharIter : public StringCharacterIterator {
+public:
+ SubStringCharIter() {
+ setText(UNICODE_STRING("abc", 3));
+ }
+};
+
+class SubUCharCharIter : public UCharCharacterIterator {
+public:
+ SubUCharCharIter() {
+ setText(u, 3);
+ }
+
+private:
+ static const UChar u[3];
+};
+
+const UChar SubUCharCharIter::u[3]={ 0x61, 0x62, 0x63 };
+
+void CharIterTest::TestCharIteratorSubClasses() {
+ SubCharIter *p;
+
+ // coverage - call functions that are not otherwise tested
+ // first[32]PostInc() are default implementations that are overridden
+ // in ICU's own CharacterIterator subclasses
+ p=new SubCharIter;
+ if(p->firstPostInc()!=0x61) {
+ errln("SubCharIter.firstPosInc() failed\n");
+ }
+ delete p;
+
+ p=new SubCharIter[2];
+ if(p[1].first32PostInc()!=0x61) {
+ errln("SubCharIter.first32PosInc() failed\n");
+ }
+ delete [] p;
+
+ // coverage: StringCharacterIterator default constructor
+ SubStringCharIter sci;
+ if(sci.firstPostInc()!=0x61) {
+ errln("SubStringCharIter.firstPostInc() failed\n");
+ }
+
+ // coverage: UCharCharacterIterator default constructor
+ SubUCharCharIter uci;
+ if(uci.firstPostInc()!=0x61) {
+ errln("SubUCharCharIter.firstPostInc() failed\n");
+ }
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/citrtest.h b/Build/source/libs/icu/icu-xetex/test/intltest/citrtest.h
new file mode 100644
index 00000000000..09521c76605
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/citrtest.h
@@ -0,0 +1,46 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2002, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef CHARITERTEST_H
+#define CHARITERTEST_H
+
+#include "intltest.h"
+#include "unicode/uiter.h"
+
+/**
+ * Some tests for CharacterIterator and StringCharacterIterator
+ **/
+class CharIterTest: public IntlTest {
+public:
+ CharIterTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ /**
+ * Test Constructors and operators ==, != and a few other methods
+ **/
+ void TestConstructionAndEquality(void);
+ /**
+ * Test Constructors and operators ==, != and a few other methods for UChariter
+ **/
+ void TestConstructionAndEqualityUChariter(void);
+ /**
+ * test the iteration functionality in different ways
+ **/
+ void TestIteration(void);
+ /**
+ * test the iteration functionality in different ways with unicodestring of UChar32's
+ **/
+ void TestIterationUChar32(void);
+
+ void TestUCharIterator();
+ void TestUCharIterator(UCharIterator *iter, CharacterIterator &ci, const char *moves, const char *which);
+ void TestCoverage();
+ void TestCharIteratorSubClasses();
+};
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/cntabcol.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/cntabcol.cpp
new file mode 100644
index 00000000000..28f38cb6f79
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/cntabcol.cpp
@@ -0,0 +1,249 @@
+/********************************************************************
+* COPYRIGHT:
+* Copyright (c) 1997-2006, International Business Machines Corporation and
+* others. All Rights Reserved.
+********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "cntabcol.h"
+
+U_NAMESPACE_USE
+
+ContractionTableTest::ContractionTableTest() {
+ testMapping = utrie_open(NULL, NULL, 0, 0, 0, TRUE);
+}
+
+ContractionTableTest::~ContractionTableTest() {
+ utrie_close(testMapping);
+}
+
+void ContractionTableTest::TestGrowTable(/* char* par */) {
+ UErrorCode status = U_ZERO_ERROR;
+ uint32_t i = 0, res = 0;
+ testTable = uprv_cnttab_open(testMapping, &status);
+
+ // fill up one contraction so that it has to expand
+ for(i = 0; i<65536; i++) {
+ uprv_cnttab_addContraction(testTable, 0, (UChar)i, i, &status);
+ if(U_FAILURE(status)) {
+ errln("Error occurred at position %i, error = %i (%s)\n", i, status, u_errorName(status));
+ break;
+ }
+ }
+ // test whether the filled up contraction really contains the data we input
+ if(U_SUCCESS(status)) {
+ for(i = 0; i<65536; i++) {
+ res = uprv_cnttab_getCE(testTable, 0, i, &status);
+ if(U_FAILURE(status)) {
+ errln("Error occurred at position %i, error = %i (%s)\n", i, status, u_errorName(status));
+ break;
+ }
+ if(res != i) {
+ errln("Error: expected %i, got %i\n", i, res);
+ break;
+ }
+ }
+ }
+ uprv_cnttab_close(testTable);
+}
+
+void ContractionTableTest::TestSetContraction(){
+ UErrorCode status = U_ZERO_ERROR;
+ testTable = uprv_cnttab_open(testMapping, &status);
+ // This should make a new contraction
+ uprv_cnttab_setContraction(testTable, 1, 0, 0x41, 0x41, &status);
+ if(U_FAILURE(status)) {
+ errln("Error setting a non existing contraction error = %i (%s)\n", status, u_errorName(status));
+ }
+ // if we try to change the non existing offset, we should get an error
+ status = U_ZERO_ERROR;
+ // currently this tests whether there is enough space, maybe it should test whether the element is actually in
+ // range. Also, maybe a silent growing should take place....
+ uprv_cnttab_setContraction(testTable, 1, 0x401, 0x41, 0x41, &status);
+ if(status != U_INDEX_OUTOFBOUNDS_ERROR) {
+ errln("changing a non-existing offset should have resulted in an error\n");
+ }
+ status = U_ZERO_ERROR;
+ uprv_cnttab_close(testTable);
+}
+
+void ContractionTableTest::TestAddATableElement(){
+ UErrorCode status = U_ZERO_ERROR;
+ testTable = uprv_cnttab_open(testMapping, &status);
+ uint32_t i = 0, res = 0;
+
+ // fill up one contraction so that it has to expand
+ for(i = 0; i<0x1000; i++) {
+ uprv_cnttab_addContraction(testTable, i, (UChar)i, i, &status);
+ if(U_FAILURE(status)) {
+ errln("Error occurred at position %i, error = %i (%s)\n", i, status, u_errorName(status));
+ break;
+ }
+ }
+ // test whether the filled up contraction really contains the data we input
+ if(U_SUCCESS(status)) {
+ for(i = 0; i<0x1000; i++) {
+ res = uprv_cnttab_getCE(testTable, i, 0, &status);
+ if(U_FAILURE(status)) {
+ errln("Error occurred at position %i, error = %i (%s)\n", i, status, u_errorName(status));
+ break;
+ }
+ if(res != i) {
+ errln("Error: expected %i, got %i\n", i, res);
+ break;
+ }
+ }
+ }
+ uprv_cnttab_close(testTable);
+}
+
+void ContractionTableTest::TestClone(){
+ UErrorCode status = U_ZERO_ERROR;
+ testTable = uprv_cnttab_open(testMapping, &status);
+ int32_t i = 0, res = 0;
+ // we must construct table in order to copy codepoints and CEs
+ // fill up one contraction so that it has to expand
+ for(i = 0; i<0x500; i++) {
+ uprv_cnttab_addContraction(testTable, i, (UChar)i, i, &status);
+ if(U_FAILURE(status)) {
+ errln("Error occurred at position %i, error = %i (%s)\n", i, status, u_errorName(status));
+ break;
+ }
+ }
+ uprv_cnttab_constructTable(testTable, 0, &status);
+ if(U_FAILURE(status)) {
+ errln("Error constructing table error = %i (%s)\n", status, u_errorName(status));
+ } else {
+ testClone = uprv_cnttab_clone(testTable, &status);
+ if(U_SUCCESS(status)) {
+ for(i = 0; i<0x500; i++) {
+ res = uprv_cnttab_getCE(testTable, i, 0, &status);
+ if(U_FAILURE(status)) {
+ errln("Error occurred at position %i, error = %i (%s)\n", i, status, u_errorName(status));
+ break;
+ }
+ if(res != i) {
+ errln("Error: expected %i, got %i\n", i, res);
+ break;
+ }
+ }
+ }
+ uprv_cnttab_close(testClone);
+ }
+ uprv_cnttab_close(testTable);
+ testTable = uprv_cnttab_open(testMapping, &status);
+ if(U_FAILURE(status)) {
+ errln("Error opening table error = %i (%s)\n", status, u_errorName(status));
+ }
+ uprv_cnttab_close(testTable);
+}
+
+void ContractionTableTest::TestChangeContraction(){
+ UErrorCode status = U_ZERO_ERROR;
+ testTable = uprv_cnttab_open(testMapping, &status);
+ uint32_t i = 0, res = 0;
+ res = uprv_cnttab_changeContraction(testTable, 0, 0x41, 0xAB, &status);
+ if(res != 0) {
+ errln("found a non existing contraction!\n");
+ }
+
+ for(i = 0; i < 0x20; i+=2) {
+ uprv_cnttab_addContraction(testTable, 0, (UChar)i, i, &status);
+ }
+
+ res = uprv_cnttab_changeContraction(testTable, 0, 0x41, 0xAB, &status);
+ if(res != UCOL_NOT_FOUND) {
+ errln("managed to change a non existing contraction!\n");
+ }
+
+ for(i = 1; i < 0x20; i+=2) {
+ res = uprv_cnttab_changeContraction(testTable, 0, (UChar)i, 0xAB, &status);
+ if(res != UCOL_NOT_FOUND) {
+ errln("managed to change a non existing contraction!\n");
+ }
+ }
+ uprv_cnttab_close(testTable);
+}
+
+void ContractionTableTest::TestChangeLastCE(){
+ UErrorCode status = U_ZERO_ERROR;
+ testTable = uprv_cnttab_open(testMapping, &status);
+ uint32_t res = uprv_cnttab_changeLastCE(testTable, 1, 0xABCD, &status);
+ if(res!=0) {
+ errln("managed to change the last CE in an non-existing contraction!\n");
+ }
+ uprv_cnttab_close(testTable);
+}
+
+void ContractionTableTest::TestErrorCodeChecking(){
+ UErrorCode status = U_REGEX_SET_CONTAINS_STRING;
+
+ uprv_cnttab_open(NULL, &status);
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ uprv_cnttab_clone(NULL, &status);
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ uprv_cnttab_changeLastCE(NULL, 0, 0, &status);
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ uprv_cnttab_insertContraction(NULL, 0, 0, 0, &status);
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ uprv_cnttab_addContraction(NULL, 0, 0, 0, &status);
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ uprv_cnttab_setContraction(NULL, 0, 0, 0, 0, &status);
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ uprv_cnttab_findCP(NULL, 0, 0, &status);
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ if (uprv_cnttab_getCE(NULL, 0, 0, &status) != UCOL_NOT_FOUND) {
+ errln("uprv_cnttab_getCE didn't return UCOL_NOT_FOUND\n");
+ }
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ if (uprv_cnttab_findCE(NULL, 0, 0, &status) != UCOL_NOT_FOUND) {
+ errln("uprv_cnttab_findCE didn't return UCOL_NOT_FOUND\n");
+ }
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ uprv_cnttab_isTailored(NULL, 0, NULL, &status);
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+ uprv_cnttab_changeContraction(NULL, 0, 0, 0, &status);
+ if (status != U_REGEX_SET_CONTAINS_STRING) {
+ errln("Status was incorrectly modified to %s\n", u_errorName(status));
+ }
+}
+
+void ContractionTableTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite ContractionTableTest: ");
+ switch (index) {
+ case 0: name = "TestGrowTable"; if (exec) TestGrowTable(/* par */); break;
+ case 1: name = "TestSetContraction"; if (exec) TestSetContraction(/* par */); break;
+ case 2: name = "TestAddATableElement"; if (exec) TestAddATableElement(/* par */); break;
+ case 3: name = "TestClone"; if (exec) TestClone(/* par */); break;
+ case 4: name = "TestChangeContraction"; if (exec) TestChangeContraction(/* par */); break;
+ case 5: name = "TestChangeLastCE"; if (exec) TestChangeLastCE(/* par */); break;
+ case 6: name = "TestErrorCodeChecking"; if (exec) TestErrorCodeChecking(/* par */); break;
+ default: name = ""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/cntabcol.h b/Build/source/libs/icu/icu-xetex/test/intltest/cntabcol.h
new file mode 100644
index 00000000000..0e35d7dec0c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/cntabcol.h
@@ -0,0 +1,41 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#ifndef CONTRACTIONTABLETEST_H
+#define CONTRACTIONTABLETEST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+#include "ucol_cnt.h"
+#include "utrie.h"
+
+class ContractionTableTest: public IntlTestCollator {
+public:
+ ContractionTableTest();
+ virtual ~ContractionTableTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // performs test with strength TERIARY
+ void TestGrowTable(/* char* par */);
+ void TestSetContraction();
+ void TestAddATableElement();
+ void TestClone();
+ void TestChangeContraction();
+ void TestChangeLastCE();
+ void TestErrorCodeChecking();
+private:
+ CntTable *testTable, *testClone;
+ /*CompactEIntArray *testMapping;*/
+ UNewTrie *testMapping;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/convtest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/convtest.cpp
new file mode 100644
index 00000000000..909c951464f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/convtest.cpp
@@ -0,0 +1,1423 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2003-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: convtest.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2003jul15
+* created by: Markus W. Scherer
+*
+* Test file for data-driven conversion tests.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_LEGACY_CONVERSION
+/*
+ * Note: Turning off all of convtest.cpp if !UCONFIG_NO_LEGACY_CONVERSION
+ * is slightly unnecessary - it removes tests for Unicode charsets
+ * like UTF-8 that should work.
+ * However, there is no easy way for the test to detect whether a test case
+ * is for a Unicode charset, so it would be difficult to only exclude those.
+ * Also, regular testing of ICU is done with all modules on, therefore
+ * not testing conversion for a custom configuration like this should be ok.
+ */
+
+#include "unicode/ucnv.h"
+#include "unicode/unistr.h"
+#include "unicode/parsepos.h"
+#include "unicode/uniset.h"
+#include "unicode/ustring.h"
+#include "unicode/ures.h"
+#include "convtest.h"
+#include "unicode/tstdtmod.h"
+#include <string.h>
+#include <stdlib.h>
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+enum {
+ // characters used in test data for callbacks
+ SUB_CB='?',
+ SKIP_CB='0',
+ STOP_CB='.',
+ ESC_CB='&'
+};
+
+ConversionTest::ConversionTest() {
+ UErrorCode errorCode=U_ZERO_ERROR;
+ utf8Cnv=ucnv_open("UTF-8", &errorCode);
+ ucnv_setToUCallBack(utf8Cnv, UCNV_TO_U_CALLBACK_STOP, NULL, NULL, NULL, &errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("unable to open UTF-8 converter");
+ }
+}
+
+ConversionTest::~ConversionTest() {
+ ucnv_close(utf8Cnv);
+}
+
+void
+ConversionTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) {
+ if (exec) logln("TestSuite ConversionTest: ");
+ switch (index) {
+ case 0: name="TestToUnicode"; if (exec) TestToUnicode(); break;
+ case 1: name="TestFromUnicode"; if (exec) TestFromUnicode(); break;
+ case 2: name="TestGetUnicodeSet"; if (exec) TestGetUnicodeSet(); break;
+ default: name=""; break; //needed to end loop
+ }
+}
+
+// test data interface ----------------------------------------------------- ***
+
+void
+ConversionTest::TestToUnicode() {
+ ConversionCase cc;
+ char charset[100], cbopt[4];
+ const char *option;
+ UnicodeString s, unicode;
+ int32_t offsetsLength;
+ UConverterToUCallback callback;
+
+ TestDataModule *dataModule;
+ TestData *testData;
+ const DataMap *testCase;
+ UErrorCode errorCode;
+ int32_t i;
+
+ errorCode=U_ZERO_ERROR;
+ dataModule=TestDataModule::getTestDataModule("conversion", *this, errorCode);
+ if(U_SUCCESS(errorCode)) {
+ testData=dataModule->createTestData("toUnicode", errorCode);
+ if(U_SUCCESS(errorCode)) {
+ for(i=0; testData->nextCase(testCase, errorCode); ++i) {
+ if(U_FAILURE(errorCode)) {
+ errln("error retrieving conversion/toUnicode test case %d - %s",
+ i, u_errorName(errorCode));
+ errorCode=U_ZERO_ERROR;
+ continue;
+ }
+
+ cc.caseNr=i;
+
+ s=testCase->getString("charset", errorCode);
+ s.extract(0, 0x7fffffff, charset, sizeof(charset), "");
+ cc.charset=charset;
+
+ cc.bytes=testCase->getBinary(cc.bytesLength, "bytes", errorCode);
+ unicode=testCase->getString("unicode", errorCode);
+ cc.unicode=unicode.getBuffer();
+ cc.unicodeLength=unicode.length();
+
+ offsetsLength=0;
+ cc.offsets=testCase->getIntVector(offsetsLength, "offsets", errorCode);
+ if(offsetsLength==0) {
+ cc.offsets=NULL;
+ } else if(offsetsLength!=unicode.length()) {
+ errln("toUnicode[%d] unicode[%d] and offsets[%d] must have the same length",
+ i, unicode.length(), offsetsLength);
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ cc.finalFlush= 0!=testCase->getInt28("flush", errorCode);
+ cc.fallbacks= 0!=testCase->getInt28("fallbacks", errorCode);
+
+ s=testCase->getString("errorCode", errorCode);
+ if(s==UNICODE_STRING("invalid", 7)) {
+ cc.outErrorCode=U_INVALID_CHAR_FOUND;
+ } else if(s==UNICODE_STRING("illegal", 7)) {
+ cc.outErrorCode=U_ILLEGAL_CHAR_FOUND;
+ } else if(s==UNICODE_STRING("truncated", 9)) {
+ cc.outErrorCode=U_TRUNCATED_CHAR_FOUND;
+ } else if(s==UNICODE_STRING("illesc", 6)) {
+ cc.outErrorCode=U_ILLEGAL_ESCAPE_SEQUENCE;
+ } else if(s==UNICODE_STRING("unsuppesc", 9)) {
+ cc.outErrorCode=U_UNSUPPORTED_ESCAPE_SEQUENCE;
+ } else {
+ cc.outErrorCode=U_ZERO_ERROR;
+ }
+
+ s=testCase->getString("callback", errorCode);
+ s.extract(0, 0x7fffffff, cbopt, sizeof(cbopt), "");
+ cc.cbopt=cbopt;
+ switch(cbopt[0]) {
+ case SUB_CB:
+ callback=UCNV_TO_U_CALLBACK_SUBSTITUTE;
+ break;
+ case SKIP_CB:
+ callback=UCNV_TO_U_CALLBACK_SKIP;
+ break;
+ case STOP_CB:
+ callback=UCNV_TO_U_CALLBACK_STOP;
+ break;
+ case ESC_CB:
+ callback=UCNV_TO_U_CALLBACK_ESCAPE;
+ break;
+ default:
+ callback=NULL;
+ break;
+ }
+ option=callback==NULL ? cbopt : cbopt+1;
+ if(*option==0) {
+ option=NULL;
+ }
+
+ cc.invalidChars=testCase->getBinary(cc.invalidLength, "invalidChars", errorCode);
+
+ if(U_FAILURE(errorCode)) {
+ errln("error parsing conversion/toUnicode test case %d - %s",
+ i, u_errorName(errorCode));
+ errorCode=U_ZERO_ERROR;
+ } else {
+ logln("TestToUnicode[%d] %s", i, charset);
+ ToUnicodeCase(cc, callback, option);
+ }
+ }
+ delete testData;
+ }
+ delete dataModule;
+ }
+ else {
+ errln("Failed: could not load test conversion data");
+ }
+}
+
+void
+ConversionTest::TestFromUnicode() {
+ ConversionCase cc;
+ char charset[100], cbopt[4];
+ const char *option;
+ UnicodeString s, unicode, invalidUChars;
+ int32_t offsetsLength, index;
+ UConverterFromUCallback callback;
+
+ TestDataModule *dataModule;
+ TestData *testData;
+ const DataMap *testCase;
+ const UChar *p;
+ UErrorCode errorCode;
+ int32_t i, length;
+
+ errorCode=U_ZERO_ERROR;
+ dataModule=TestDataModule::getTestDataModule("conversion", *this, errorCode);
+ if(U_SUCCESS(errorCode)) {
+ testData=dataModule->createTestData("fromUnicode", errorCode);
+ if(U_SUCCESS(errorCode)) {
+ for(i=0; testData->nextCase(testCase, errorCode); ++i) {
+ if(U_FAILURE(errorCode)) {
+ errln("error retrieving conversion/fromUnicode test case %d - %s",
+ i, u_errorName(errorCode));
+ errorCode=U_ZERO_ERROR;
+ continue;
+ }
+
+ cc.caseNr=i;
+
+ s=testCase->getString("charset", errorCode);
+ s.extract(0, 0x7fffffff, charset, sizeof(charset), "");
+ cc.charset=charset;
+
+ unicode=testCase->getString("unicode", errorCode);
+ cc.unicode=unicode.getBuffer();
+ cc.unicodeLength=unicode.length();
+ cc.bytes=testCase->getBinary(cc.bytesLength, "bytes", errorCode);
+
+ offsetsLength=0;
+ cc.offsets=testCase->getIntVector(offsetsLength, "offsets", errorCode);
+ if(offsetsLength==0) {
+ cc.offsets=NULL;
+ } else if(offsetsLength!=cc.bytesLength) {
+ errln("fromUnicode[%d] bytes[%d] and offsets[%d] must have the same length",
+ i, cc.bytesLength, offsetsLength);
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ cc.finalFlush= 0!=testCase->getInt28("flush", errorCode);
+ cc.fallbacks= 0!=testCase->getInt28("fallbacks", errorCode);
+
+ s=testCase->getString("errorCode", errorCode);
+ if(s==UNICODE_STRING("invalid", 7)) {
+ cc.outErrorCode=U_INVALID_CHAR_FOUND;
+ } else if(s==UNICODE_STRING("illegal", 7)) {
+ cc.outErrorCode=U_ILLEGAL_CHAR_FOUND;
+ } else if(s==UNICODE_STRING("truncated", 9)) {
+ cc.outErrorCode=U_TRUNCATED_CHAR_FOUND;
+ } else {
+ cc.outErrorCode=U_ZERO_ERROR;
+ }
+
+ s=testCase->getString("callback", errorCode);
+ cc.setSub=0; // default: no subchar
+
+ if((index=s.indexOf((UChar)0))>0) {
+ // read NUL-separated subchar first, if any
+ // copy the subchar from Latin-1 characters
+ // start after the NUL
+ p=s.getTerminatedBuffer();
+ length=index+1;
+ p+=length;
+ length=s.length()-length;
+ if(length<=0 || length>=(int32_t)sizeof(cc.subchar)) {
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ int32_t j;
+
+ for(j=0; j<length; ++j) {
+ cc.subchar[j]=(char)p[j];
+ }
+ // NUL-terminate the subchar
+ cc.subchar[j]=0;
+ cc.setSub=1;
+ }
+
+ // remove the NUL and subchar from s
+ s.truncate(index);
+ } else if((index=s.indexOf((UChar)0x3d))>0) /* '=' */ {
+ // read a substitution string, separated by an equal sign
+ p=s.getBuffer()+index+1;
+ length=s.length()-(index+1);
+ if(length<0 || length>=LENGTHOF(cc.subString)) {
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ u_memcpy(cc.subString, p, length);
+ // NUL-terminate the subString
+ cc.subString[length]=0;
+ cc.setSub=-1;
+ }
+
+ // remove the equal sign and subString from s
+ s.truncate(index);
+ }
+
+ s.extract(0, 0x7fffffff, cbopt, sizeof(cbopt), "");
+ cc.cbopt=cbopt;
+ switch(cbopt[0]) {
+ case SUB_CB:
+ callback=UCNV_FROM_U_CALLBACK_SUBSTITUTE;
+ break;
+ case SKIP_CB:
+ callback=UCNV_FROM_U_CALLBACK_SKIP;
+ break;
+ case STOP_CB:
+ callback=UCNV_FROM_U_CALLBACK_STOP;
+ break;
+ case ESC_CB:
+ callback=UCNV_FROM_U_CALLBACK_ESCAPE;
+ break;
+ default:
+ callback=NULL;
+ break;
+ }
+ option=callback==NULL ? cbopt : cbopt+1;
+ if(*option==0) {
+ option=NULL;
+ }
+
+ invalidUChars=testCase->getString("invalidUChars", errorCode);
+ cc.invalidUChars=invalidUChars.getBuffer();
+ cc.invalidLength=invalidUChars.length();
+
+ if(U_FAILURE(errorCode)) {
+ errln("error parsing conversion/fromUnicode test case %d - %s",
+ i, u_errorName(errorCode));
+ errorCode=U_ZERO_ERROR;
+ } else {
+ logln("TestFromUnicode[%d] %s", i, charset);
+ FromUnicodeCase(cc, callback, option);
+ }
+ }
+ delete testData;
+ }
+ delete dataModule;
+ }
+ else {
+ errln("Failed: could not load test conversion data");
+ }
+}
+
+static const UChar ellipsis[]={ 0x2e, 0x2e, 0x2e };
+
+void
+ConversionTest::TestGetUnicodeSet() {
+ char charset[100];
+ UnicodeString s, map, mapnot;
+ int32_t which;
+
+ ParsePosition pos;
+ UnicodeSet cnvSet, mapSet, mapnotSet, diffSet;
+ UnicodeSet *cnvSetPtr = &cnvSet;
+ UConverter *cnv;
+
+ TestDataModule *dataModule;
+ TestData *testData;
+ const DataMap *testCase;
+ UErrorCode errorCode;
+ int32_t i;
+
+ errorCode=U_ZERO_ERROR;
+ dataModule=TestDataModule::getTestDataModule("conversion", *this, errorCode);
+ if(U_SUCCESS(errorCode)) {
+ testData=dataModule->createTestData("getUnicodeSet", errorCode);
+ if(U_SUCCESS(errorCode)) {
+ for(i=0; testData->nextCase(testCase, errorCode); ++i) {
+ if(U_FAILURE(errorCode)) {
+ errln("error retrieving conversion/getUnicodeSet test case %d - %s",
+ i, u_errorName(errorCode));
+ errorCode=U_ZERO_ERROR;
+ continue;
+ }
+
+ s=testCase->getString("charset", errorCode);
+ s.extract(0, 0x7fffffff, charset, sizeof(charset), "");
+
+ map=testCase->getString("map", errorCode);
+ mapnot=testCase->getString("mapnot", errorCode);
+
+ which=testCase->getInt28("which", errorCode);
+
+ if(U_FAILURE(errorCode)) {
+ errln("error parsing conversion/getUnicodeSet test case %d - %s",
+ i, u_errorName(errorCode));
+ errorCode=U_ZERO_ERROR;
+ continue;
+ }
+
+ // test this test case
+ mapSet.clear();
+ mapnotSet.clear();
+
+ pos.setIndex(0);
+ mapSet.applyPattern(map, pos, 0, NULL, errorCode);
+ if(U_FAILURE(errorCode) || pos.getIndex()!=map.length()) {
+ errln("error creating the map set for conversion/getUnicodeSet test case %d - %s\n"
+ " error index %d index %d U+%04x",
+ i, u_errorName(errorCode), pos.getErrorIndex(), pos.getIndex(), map.char32At(pos.getIndex()));
+ errorCode=U_ZERO_ERROR;
+ continue;
+ }
+
+ pos.setIndex(0);
+ mapnotSet.applyPattern(mapnot, pos, 0, NULL, errorCode);
+ if(U_FAILURE(errorCode) || pos.getIndex()!=mapnot.length()) {
+ errln("error creating the mapnot set for conversion/getUnicodeSet test case %d - %s\n"
+ " error index %d index %d U+%04x",
+ i, u_errorName(errorCode), pos.getErrorIndex(), pos.getIndex(), mapnot.char32At(pos.getIndex()));
+ errorCode=U_ZERO_ERROR;
+ continue;
+ }
+
+ logln("TestGetUnicodeSet[%d] %s", i, charset);
+
+ cnv=cnv_open(charset, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("error opening \"%s\" for conversion/getUnicodeSet test case %d - %s",
+ charset, i, u_errorName(errorCode));
+ errorCode=U_ZERO_ERROR;
+ continue;
+ }
+
+ ucnv_getUnicodeSet(cnv, (USet *)cnvSetPtr, (UConverterUnicodeSet)which, &errorCode);
+ ucnv_close(cnv);
+
+ if(U_FAILURE(errorCode)) {
+ errln("error in ucnv_getUnicodeSet(\"%s\") for conversion/getUnicodeSet test case %d - %s",
+ charset, i, u_errorName(errorCode));
+ errorCode=U_ZERO_ERROR;
+ continue;
+ }
+
+ // are there items that must be in cnvSet but are not?
+ (diffSet=mapSet).removeAll(cnvSet);
+ if(!diffSet.isEmpty()) {
+ diffSet.toPattern(s, TRUE);
+ if(s.length()>100) {
+ s.replace(100, 0x7fffffff, ellipsis, LENGTHOF(ellipsis));
+ }
+ errln("error: ucnv_getUnicodeSet(\"%s\") is missing items - conversion/getUnicodeSet test case %d",
+ charset, i);
+ errln(s);
+ }
+
+ // are there items that must not be in cnvSet but are?
+ (diffSet=mapnotSet).retainAll(cnvSet);
+ if(!diffSet.isEmpty()) {
+ diffSet.toPattern(s, TRUE);
+ if(s.length()>100) {
+ s.replace(100, 0x7fffffff, ellipsis, LENGTHOF(ellipsis));
+ }
+ errln("error: ucnv_getUnicodeSet(\"%s\") contains unexpected items - conversion/getUnicodeSet test case %d",
+ charset, i);
+ errln(s);
+ }
+ }
+ delete testData;
+ }
+ delete dataModule;
+ }
+ else {
+ errln("Failed: could not load test conversion data");
+ }
+}
+
+// open testdata or ICU data converter ------------------------------------- ***
+
+UConverter *
+ConversionTest::cnv_open(const char *name, UErrorCode &errorCode) {
+ if(name!=NULL && *name=='*') {
+ /* loadTestData(): set the data directory */
+ return ucnv_openPackage(loadTestData(errorCode), name+1, &errorCode);
+ } else {
+ return ucnv_open(name, &errorCode);
+ }
+}
+
+// output helpers ---------------------------------------------------------- ***
+
+static inline char
+hexDigit(uint8_t digit) {
+ return digit<=9 ? (char)('0'+digit) : (char)('a'-10+digit);
+}
+
+static char *
+printBytes(const uint8_t *bytes, int32_t length, char *out) {
+ uint8_t b;
+
+ if(length>0) {
+ b=*bytes++;
+ --length;
+ *out++=hexDigit((uint8_t)(b>>4));
+ *out++=hexDigit((uint8_t)(b&0xf));
+ }
+
+ while(length>0) {
+ b=*bytes++;
+ --length;
+ *out++=' ';
+ *out++=hexDigit((uint8_t)(b>>4));
+ *out++=hexDigit((uint8_t)(b&0xf));
+ }
+ *out++=0;
+ return out;
+}
+
+static char *
+printUnicode(const UChar *unicode, int32_t length, char *out) {
+ UChar32 c;
+ int32_t i;
+
+ for(i=0; i<length;) {
+ if(i>0) {
+ *out++=' ';
+ }
+ U16_NEXT(unicode, i, length, c);
+ // write 4..6 digits
+ if(c>=0x100000) {
+ *out++='1';
+ }
+ if(c>=0x10000) {
+ *out++=hexDigit((uint8_t)((c>>16)&0xf));
+ }
+ *out++=hexDigit((uint8_t)((c>>12)&0xf));
+ *out++=hexDigit((uint8_t)((c>>8)&0xf));
+ *out++=hexDigit((uint8_t)((c>>4)&0xf));
+ *out++=hexDigit((uint8_t)(c&0xf));
+ }
+ *out++=0;
+ return out;
+}
+
+static char *
+printOffsets(const int32_t *offsets, int32_t length, char *out) {
+ int32_t i, o, d;
+
+ if(offsets==NULL) {
+ length=0;
+ }
+
+ for(i=0; i<length; ++i) {
+ if(i>0) {
+ *out++=' ';
+ }
+ o=offsets[i];
+
+ // print all offsets with 2 characters each (-x, -9..99, xx)
+ if(o<-9) {
+ *out++='-';
+ *out++='x';
+ } else if(o<0) {
+ *out++='-';
+ *out++=(char)('0'-o);
+ } else if(o<=99) {
+ *out++=(d=o/10)==0 ? ' ' : (char)('0'+d);
+ *out++=(char)('0'+o%10);
+ } else /* o>99 */ {
+ *out++='x';
+ *out++='x';
+ }
+ }
+ *out++=0;
+ return out;
+}
+
+// toUnicode test worker functions ----------------------------------------- ***
+
+static int32_t
+stepToUnicode(ConversionCase &cc, UConverter *cnv,
+ UChar *result, int32_t resultCapacity,
+ int32_t *resultOffsets, /* also resultCapacity */
+ int32_t step,
+ UErrorCode *pErrorCode) {
+ const char *source, *sourceLimit, *bytesLimit;
+ UChar *target, *targetLimit, *resultLimit;
+ UBool flush;
+
+ source=(const char *)cc.bytes;
+ target=result;
+ bytesLimit=source+cc.bytesLength;
+ resultLimit=result+resultCapacity;
+
+ if(step>=0) {
+ // call ucnv_toUnicode() with in/out buffers no larger than (step) at a time
+ // move only one buffer (in vs. out) at a time to be extra mean
+ // step==0 performs bulk conversion and generates offsets
+
+ // initialize the partial limits for the loop
+ if(step==0) {
+ // use the entire buffers
+ sourceLimit=bytesLimit;
+ targetLimit=resultLimit;
+ flush=cc.finalFlush;
+ } else {
+ // start with empty partial buffers
+ sourceLimit=source;
+ targetLimit=target;
+ flush=FALSE;
+
+ // output offsets only for bulk conversion
+ resultOffsets=NULL;
+ }
+
+ for(;;) {
+ // resetting the opposite conversion direction must not affect this one
+ ucnv_resetFromUnicode(cnv);
+
+ // convert
+ ucnv_toUnicode(cnv,
+ &target, targetLimit,
+ &source, sourceLimit,
+ resultOffsets,
+ flush, pErrorCode);
+
+ // check pointers and errors
+ if(source>sourceLimit || target>targetLimit) {
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ } else if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+ if(target!=targetLimit) {
+ // buffer overflow must only be set when the target is filled
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ } else if(targetLimit==resultLimit) {
+ // not just a partial overflow
+ break;
+ }
+
+ // the partial target is filled, set a new limit, reset the error and continue
+ targetLimit=(resultLimit-target)>=step ? target+step : resultLimit;
+ *pErrorCode=U_ZERO_ERROR;
+ } else if(U_FAILURE(*pErrorCode)) {
+ // some other error occurred, done
+ break;
+ } else {
+ if(source!=sourceLimit) {
+ // when no error occurs, then the input must be consumed
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ }
+
+ if(sourceLimit==bytesLimit) {
+ // we are done
+ break;
+ }
+
+ // the partial conversion succeeded, set a new limit and continue
+ sourceLimit=(bytesLimit-source)>=step ? source+step : bytesLimit;
+ flush=(UBool)(cc.finalFlush && sourceLimit==bytesLimit);
+ }
+ }
+ } else /* step<0 */ {
+ /*
+ * step==-1: call only ucnv_getNextUChar()
+ * otherwise alternate between ucnv_toUnicode() and ucnv_getNextUChar()
+ * if step==-2 or -3, then give ucnv_toUnicode() the whole remaining input,
+ * else give it at most (-step-2)/2 bytes
+ */
+ UChar32 c;
+
+ // end the loop by getting an index out of bounds error
+ for(;;) {
+ // resetting the opposite conversion direction must not affect this one
+ ucnv_resetFromUnicode(cnv);
+
+ // convert
+ if((step&1)!=0 /* odd: -1, -3, -5, ... */) {
+ sourceLimit=source; // use sourceLimit not as a real limit
+ // but to remember the pre-getNextUChar source pointer
+ c=ucnv_getNextUChar(cnv, &source, bytesLimit, pErrorCode);
+
+ // check pointers and errors
+ if(*pErrorCode==U_INDEX_OUTOFBOUNDS_ERROR) {
+ if(source!=bytesLimit) {
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ } else {
+ *pErrorCode=U_ZERO_ERROR;
+ }
+ break;
+ } else if(U_FAILURE(*pErrorCode)) {
+ break;
+ }
+ // source may not move if c is from previous overflow
+
+ if(target==resultLimit) {
+ *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+ break;
+ }
+ if(c<=0xffff) {
+ *target++=(UChar)c;
+ } else {
+ *target++=U16_LEAD(c);
+ if(target==resultLimit) {
+ *pErrorCode=U_BUFFER_OVERFLOW_ERROR;
+ break;
+ }
+ *target++=U16_TRAIL(c);
+ }
+
+ // alternate between -n-1 and -n but leave -1 alone
+ if(step<-1) {
+ ++step;
+ }
+ } else /* step is even */ {
+ // allow only one UChar output
+ targetLimit=target<resultLimit ? target+1 : resultLimit;
+
+ // as with ucnv_getNextUChar(), we always flush (if we go to bytesLimit)
+ // and never output offsets
+ if(step==-2) {
+ sourceLimit=bytesLimit;
+ } else {
+ sourceLimit=source+(-step-2)/2;
+ if(sourceLimit>bytesLimit) {
+ sourceLimit=bytesLimit;
+ }
+ }
+
+ ucnv_toUnicode(cnv,
+ &target, targetLimit,
+ &source, sourceLimit,
+ NULL, (UBool)(sourceLimit==bytesLimit), pErrorCode);
+
+ // check pointers and errors
+ if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+ if(target!=targetLimit) {
+ // buffer overflow must only be set when the target is filled
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ } else if(targetLimit==resultLimit) {
+ // not just a partial overflow
+ break;
+ }
+
+ // the partial target is filled, set a new limit and continue
+ *pErrorCode=U_ZERO_ERROR;
+ } else if(U_FAILURE(*pErrorCode)) {
+ // some other error occurred, done
+ break;
+ } else {
+ if(source!=sourceLimit) {
+ // when no error occurs, then the input must be consumed
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ }
+
+ // we are done (flush==TRUE) but we continue, to get the index out of bounds error above
+ }
+
+ --step;
+ }
+ }
+ }
+
+ return (int32_t)(target-result);
+}
+
+UBool
+ConversionTest::ToUnicodeCase(ConversionCase &cc, UConverterToUCallback callback, const char *option) {
+ UConverter *cnv;
+ UErrorCode errorCode;
+
+ // open the converter
+ errorCode=U_ZERO_ERROR;
+ cnv=cnv_open(cc.charset, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("toUnicode[%d](%s cb=\"%s\" fb=%d flush=%d) ucnv_open() failed - %s",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, u_errorName(errorCode));
+ return FALSE;
+ }
+
+ // set the callback
+ if(callback!=NULL) {
+ ucnv_setToUCallBack(cnv, callback, option, NULL, NULL, &errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("toUnicode[%d](%s cb=\"%s\" fb=%d flush=%d) ucnv_setToUCallBack() failed - %s",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, u_errorName(errorCode));
+ ucnv_close(cnv);
+ return FALSE;
+ }
+ }
+
+ int32_t resultOffsets[256];
+ UChar result[256];
+ int32_t resultLength;
+ UBool ok;
+
+ static const struct {
+ int32_t step;
+ const char *name;
+ } steps[]={
+ { 0, "bulk" }, // must be first for offsets to be checked
+ { 1, "step=1" },
+ { 3, "step=3" },
+ { 7, "step=7" },
+ { -1, "getNext" },
+ { -2, "toU(bulk)+getNext" },
+ { -3, "getNext+toU(bulk)" },
+ { -4, "toU(1)+getNext" },
+ { -5, "getNext+toU(1)" },
+ { -12, "toU(5)+getNext" },
+ { -13, "getNext+toU(5)" },
+ };
+ int32_t i, step;
+
+ ok=TRUE;
+ for(i=0; i<LENGTHOF(steps) && ok; ++i) {
+ step=steps[i].step;
+ if(step<0 && !cc.finalFlush) {
+ // skip ucnv_getNextUChar() if !finalFlush because
+ // ucnv_getNextUChar() always implies flush
+ continue;
+ }
+ if(step!=0) {
+ // bulk test is first, then offsets are not checked any more
+ cc.offsets=NULL;
+ }
+ else {
+ memset(resultOffsets, -1, LENGTHOF(resultOffsets));
+ }
+ memset(result, -1, LENGTHOF(result));
+ errorCode=U_ZERO_ERROR;
+ resultLength=stepToUnicode(cc, cnv,
+ result, LENGTHOF(result),
+ step==0 ? resultOffsets : NULL,
+ step, &errorCode);
+ ok=checkToUnicode(
+ cc, cnv, steps[i].name,
+ result, resultLength,
+ cc.offsets!=NULL ? resultOffsets : NULL,
+ errorCode);
+ if(U_FAILURE(errorCode) || !cc.finalFlush) {
+ // reset if an error occurred or we did not flush
+ // otherwise do nothing to make sure that flushing resets
+ ucnv_resetToUnicode(cnv);
+ }
+ if (resultOffsets[resultLength] != -1) {
+ errln("toUnicode[%d](%s) Conversion wrote too much to offsets at index %d",
+ cc.caseNr, cc.charset, resultLength);
+ }
+ if (result[resultLength] != (UChar)-1) {
+ errln("toUnicode[%d](%s) Conversion wrote too much to result at index %d",
+ cc.caseNr, cc.charset, resultLength);
+ }
+ }
+
+ // not a real loop, just a convenience for breaking out of the block
+ while(ok && cc.finalFlush) {
+ // test ucnv_toUChars()
+ memset(result, 0, sizeof(result));
+
+ errorCode=U_ZERO_ERROR;
+ resultLength=ucnv_toUChars(cnv,
+ result, LENGTHOF(result),
+ (const char *)cc.bytes, cc.bytesLength,
+ &errorCode);
+ ok=checkToUnicode(
+ cc, cnv, "toUChars",
+ result, resultLength,
+ NULL,
+ errorCode);
+ if(!ok) {
+ break;
+ }
+
+ // test preflighting
+ // keep the correct result for simple checking
+ errorCode=U_ZERO_ERROR;
+ resultLength=ucnv_toUChars(cnv,
+ NULL, 0,
+ (const char *)cc.bytes, cc.bytesLength,
+ &errorCode);
+ if(errorCode==U_STRING_NOT_TERMINATED_WARNING || errorCode==U_BUFFER_OVERFLOW_ERROR) {
+ errorCode=U_ZERO_ERROR;
+ }
+ ok=checkToUnicode(
+ cc, cnv, "preflight toUChars",
+ result, resultLength,
+ NULL,
+ errorCode);
+ break;
+ }
+
+ ucnv_close(cnv);
+ return ok;
+}
+
+UBool
+ConversionTest::checkToUnicode(ConversionCase &cc, UConverter *cnv, const char *name,
+ const UChar *result, int32_t resultLength,
+ const int32_t *resultOffsets,
+ UErrorCode resultErrorCode) {
+ char resultInvalidChars[8];
+ int8_t resultInvalidLength;
+ UErrorCode errorCode;
+
+ const char *msg;
+
+ // reset the message; NULL will mean "ok"
+ msg=NULL;
+
+ errorCode=U_ZERO_ERROR;
+ resultInvalidLength=sizeof(resultInvalidChars);
+ ucnv_getInvalidChars(cnv, resultInvalidChars, &resultInvalidLength, &errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("toUnicode[%d](%s cb=\"%s\" fb=%d flush=%d %s) ucnv_getInvalidChars() failed - %s",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, name, u_errorName(errorCode));
+ return FALSE;
+ }
+
+ // check everything that might have gone wrong
+ if(cc.unicodeLength!=resultLength) {
+ msg="wrong result length";
+ } else if(0!=u_memcmp(cc.unicode, result, cc.unicodeLength)) {
+ msg="wrong result string";
+ } else if(cc.offsets!=NULL && 0!=memcmp(cc.offsets, resultOffsets, cc.unicodeLength*sizeof(*cc.offsets))) {
+ msg="wrong offsets";
+ } else if(cc.outErrorCode!=resultErrorCode) {
+ msg="wrong error code";
+ } else if(cc.invalidLength!=resultInvalidLength) {
+ msg="wrong length of last invalid input";
+ } else if(0!=memcmp(cc.invalidChars, resultInvalidChars, cc.invalidLength)) {
+ msg="wrong last invalid input";
+ }
+
+ if(msg==NULL) {
+ return TRUE;
+ } else {
+ char buffer[2000]; // one buffer for all strings
+ char *s, *bytesString, *unicodeString, *resultString,
+ *offsetsString, *resultOffsetsString,
+ *invalidCharsString, *resultInvalidCharsString;
+
+ bytesString=s=buffer;
+ s=printBytes(cc.bytes, cc.bytesLength, bytesString);
+ s=printUnicode(cc.unicode, cc.unicodeLength, unicodeString=s);
+ s=printUnicode(result, resultLength, resultString=s);
+ s=printOffsets(cc.offsets, cc.unicodeLength, offsetsString=s);
+ s=printOffsets(resultOffsets, resultLength, resultOffsetsString=s);
+ s=printBytes(cc.invalidChars, cc.invalidLength, invalidCharsString=s);
+ s=printBytes((uint8_t *)resultInvalidChars, resultInvalidLength, resultInvalidCharsString=s);
+
+ if((s-buffer)>(int32_t)sizeof(buffer)) {
+ errln("toUnicode[%d](%s cb=\"%s\" fb=%d flush=%d %s) fatal error: checkToUnicode() test output buffer overflow writing %d chars\n",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, name, (int)(s-buffer));
+ exit(1);
+ }
+
+ errln("toUnicode[%d](%s cb=\"%s\" fb=%d flush=%d %s) failed: %s\n"
+ " bytes <%s>[%d]\n"
+ " expected <%s>[%d]\n"
+ " result <%s>[%d]\n"
+ " offsets <%s>\n"
+ " result offsets <%s>\n"
+ " error code expected %s got %s\n"
+ " invalidChars expected <%s> got <%s>\n",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, name, msg,
+ bytesString, cc.bytesLength,
+ unicodeString, cc.unicodeLength,
+ resultString, resultLength,
+ offsetsString,
+ resultOffsetsString,
+ u_errorName(cc.outErrorCode), u_errorName(resultErrorCode),
+ invalidCharsString, resultInvalidCharsString);
+
+ return FALSE;
+ }
+}
+
+// fromUnicode test worker functions --------------------------------------- ***
+
+static int32_t
+stepFromUTF8(ConversionCase &cc,
+ UConverter *utf8Cnv, UConverter *cnv,
+ char *result, int32_t resultCapacity,
+ int32_t step,
+ UErrorCode *pErrorCode) {
+ const char *source, *sourceLimit, *utf8Limit;
+ UChar pivotBuffer[32];
+ UChar *pivotSource, *pivotTarget, *pivotLimit;
+ char *target, *targetLimit, *resultLimit;
+ UBool flush;
+
+ source=cc.utf8;
+ pivotSource=pivotTarget=pivotBuffer;
+ target=result;
+ utf8Limit=source+cc.utf8Length;
+ resultLimit=result+resultCapacity;
+
+ // call ucnv_convertEx() with in/out buffers no larger than (step) at a time
+ // move only one buffer (in vs. out) at a time to be extra mean
+ // step==0 performs bulk conversion
+
+ // initialize the partial limits for the loop
+ if(step==0) {
+ // use the entire buffers
+ sourceLimit=utf8Limit;
+ targetLimit=resultLimit;
+ flush=cc.finalFlush;
+
+ pivotLimit=pivotBuffer+LENGTHOF(pivotBuffer);
+ } else {
+ // start with empty partial buffers
+ sourceLimit=source;
+ targetLimit=target;
+ flush=FALSE;
+
+ // empty pivot is not allowed, make it of length step
+ pivotLimit=pivotBuffer+step;
+ }
+
+ for(;;) {
+ // resetting the opposite conversion direction must not affect this one
+ ucnv_resetFromUnicode(utf8Cnv);
+ ucnv_resetToUnicode(cnv);
+
+ // convert
+ ucnv_convertEx(cnv, utf8Cnv,
+ &target, targetLimit,
+ &source, sourceLimit,
+ pivotBuffer, &pivotSource, &pivotTarget, pivotLimit,
+ FALSE, flush, pErrorCode);
+
+ // check pointers and errors
+ if(source>sourceLimit || target>targetLimit) {
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ } else if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+ if(target!=targetLimit) {
+ // buffer overflow must only be set when the target is filled
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ } else if(targetLimit==resultLimit) {
+ // not just a partial overflow
+ break;
+ }
+
+ // the partial target is filled, set a new limit, reset the error and continue
+ targetLimit=(resultLimit-target)>=step ? target+step : resultLimit;
+ *pErrorCode=U_ZERO_ERROR;
+ } else if(U_FAILURE(*pErrorCode)) {
+ if(pivotSource==pivotBuffer) {
+ // toUnicode error, should not occur
+ // toUnicode errors are tested in cintltst TestConvertExFromUTF8()
+ break;
+ } else {
+ // fromUnicode error
+ // some other error occurred, done
+ break;
+ }
+ } else {
+ if(source!=sourceLimit) {
+ // when no error occurs, then the input must be consumed
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ }
+
+ if(sourceLimit==utf8Limit) {
+ // we are done
+ if(*pErrorCode==U_STRING_NOT_TERMINATED_WARNING) {
+ // ucnv_convertEx() warns about not terminating the output
+ // but ucnv_fromUnicode() does not and so
+ // checkFromUnicode() does not expect it
+ *pErrorCode=U_ZERO_ERROR;
+ }
+ break;
+ }
+
+ // the partial conversion succeeded, set a new limit and continue
+ sourceLimit=(utf8Limit-source)>=step ? source+step : utf8Limit;
+ flush=(UBool)(cc.finalFlush && sourceLimit==utf8Limit);
+ }
+ }
+
+ return (int32_t)(target-result);
+}
+
+static int32_t
+stepFromUnicode(ConversionCase &cc, UConverter *cnv,
+ char *result, int32_t resultCapacity,
+ int32_t *resultOffsets, /* also resultCapacity */
+ int32_t step,
+ UErrorCode *pErrorCode) {
+ const UChar *source, *sourceLimit, *unicodeLimit;
+ char *target, *targetLimit, *resultLimit;
+ UBool flush;
+
+ source=cc.unicode;
+ target=result;
+ unicodeLimit=source+cc.unicodeLength;
+ resultLimit=result+resultCapacity;
+
+ // call ucnv_fromUnicode() with in/out buffers no larger than (step) at a time
+ // move only one buffer (in vs. out) at a time to be extra mean
+ // step==0 performs bulk conversion and generates offsets
+
+ // initialize the partial limits for the loop
+ if(step==0) {
+ // use the entire buffers
+ sourceLimit=unicodeLimit;
+ targetLimit=resultLimit;
+ flush=cc.finalFlush;
+ } else {
+ // start with empty partial buffers
+ sourceLimit=source;
+ targetLimit=target;
+ flush=FALSE;
+
+ // output offsets only for bulk conversion
+ resultOffsets=NULL;
+ }
+
+ for(;;) {
+ // resetting the opposite conversion direction must not affect this one
+ ucnv_resetToUnicode(cnv);
+
+ // convert
+ ucnv_fromUnicode(cnv,
+ &target, targetLimit,
+ &source, sourceLimit,
+ resultOffsets,
+ flush, pErrorCode);
+
+ // check pointers and errors
+ if(source>sourceLimit || target>targetLimit) {
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ } else if(*pErrorCode==U_BUFFER_OVERFLOW_ERROR) {
+ if(target!=targetLimit) {
+ // buffer overflow must only be set when the target is filled
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ } else if(targetLimit==resultLimit) {
+ // not just a partial overflow
+ break;
+ }
+
+ // the partial target is filled, set a new limit, reset the error and continue
+ targetLimit=(resultLimit-target)>=step ? target+step : resultLimit;
+ *pErrorCode=U_ZERO_ERROR;
+ } else if(U_FAILURE(*pErrorCode)) {
+ // some other error occurred, done
+ break;
+ } else {
+ if(source!=sourceLimit) {
+ // when no error occurs, then the input must be consumed
+ *pErrorCode=U_INTERNAL_PROGRAM_ERROR;
+ break;
+ }
+
+ if(sourceLimit==unicodeLimit) {
+ // we are done
+ break;
+ }
+
+ // the partial conversion succeeded, set a new limit and continue
+ sourceLimit=(unicodeLimit-source)>=step ? source+step : unicodeLimit;
+ flush=(UBool)(cc.finalFlush && sourceLimit==unicodeLimit);
+ }
+ }
+
+ return (int32_t)(target-result);
+}
+
+UBool
+ConversionTest::FromUnicodeCase(ConversionCase &cc, UConverterFromUCallback callback, const char *option) {
+ UConverter *cnv;
+ UErrorCode errorCode;
+
+ // open the converter
+ errorCode=U_ZERO_ERROR;
+ cnv=cnv_open(cc.charset, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("fromUnicode[%d](%s cb=\"%s\" fb=%d flush=%d) ucnv_open() failed - %s",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, u_errorName(errorCode));
+ return FALSE;
+ }
+ ucnv_resetToUnicode(utf8Cnv);
+
+ // set the callback
+ if(callback!=NULL) {
+ ucnv_setFromUCallBack(cnv, callback, option, NULL, NULL, &errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("fromUnicode[%d](%s cb=\"%s\" fb=%d flush=%d) ucnv_setFromUCallBack() failed - %s",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, u_errorName(errorCode));
+ ucnv_close(cnv);
+ return FALSE;
+ }
+ }
+
+ // set the fallbacks flag
+ // TODO change with Jitterbug 2401, then add a similar call for toUnicode too
+ ucnv_setFallback(cnv, cc.fallbacks);
+
+ // set the subchar
+ int32_t length;
+
+ if(cc.setSub>0) {
+ length=(int32_t)strlen(cc.subchar);
+ ucnv_setSubstChars(cnv, cc.subchar, (int8_t)length, &errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("fromUnicode[%d](%s cb=\"%s\" fb=%d flush=%d) ucnv_setSubstChars() failed - %s",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, u_errorName(errorCode));
+ ucnv_close(cnv);
+ return FALSE;
+ }
+ } else if(cc.setSub<0) {
+ ucnv_setSubstString(cnv, cc.subString, -1, &errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("fromUnicode[%d](%s cb=\"%s\" fb=%d flush=%d) ucnv_setSubstString() failed - %s",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, u_errorName(errorCode));
+ ucnv_close(cnv);
+ return FALSE;
+ }
+ }
+
+ // convert unicode to utf8
+ char utf8[256];
+ cc.utf8=utf8;
+ u_strToUTF8(utf8, LENGTHOF(utf8), &cc.utf8Length,
+ cc.unicode, cc.unicodeLength,
+ &errorCode);
+ if(U_FAILURE(errorCode)) {
+ // skip UTF-8 testing of a string with an unpaired surrogate,
+ // or of one that's too long
+ // toUnicode errors are tested in cintltst TestConvertExFromUTF8()
+ cc.utf8Length=-1;
+ }
+
+ int32_t resultOffsets[256];
+ char result[256];
+ int32_t resultLength;
+ UBool ok;
+
+ static const struct {
+ int32_t step;
+ const char *name, *utf8Name;
+ } steps[]={
+ { 0, "bulk", "utf8" }, // must be first for offsets to be checked
+ { 1, "step=1", "utf8 step=1" },
+ { 3, "step=3", "utf8 step=3" },
+ { 7, "step=7", "utf8 step=7" }
+ };
+ int32_t i, step;
+
+ ok=TRUE;
+ for(i=0; i<LENGTHOF(steps) && ok; ++i) {
+ step=steps[i].step;
+ memset(resultOffsets, -1, LENGTHOF(resultOffsets));
+ memset(result, -1, LENGTHOF(result));
+ errorCode=U_ZERO_ERROR;
+ resultLength=stepFromUnicode(cc, cnv,
+ result, LENGTHOF(result),
+ step==0 ? resultOffsets : NULL,
+ step, &errorCode);
+ ok=checkFromUnicode(
+ cc, cnv, steps[i].name,
+ (uint8_t *)result, resultLength,
+ cc.offsets!=NULL ? resultOffsets : NULL,
+ errorCode);
+ if(U_FAILURE(errorCode) || !cc.finalFlush) {
+ // reset if an error occurred or we did not flush
+ // otherwise do nothing to make sure that flushing resets
+ ucnv_resetFromUnicode(cnv);
+ }
+ if (resultOffsets[resultLength] != -1) {
+ errln("fromUnicode[%d](%s) Conversion wrote too much to offsets at index %d",
+ cc.caseNr, cc.charset, resultLength);
+ }
+ if (result[resultLength] != (char)-1) {
+ errln("fromUnicode[%d](%s) Conversion wrote too much to result at index %d",
+ cc.caseNr, cc.charset, resultLength);
+ }
+
+ // bulk test is first, then offsets are not checked any more
+ cc.offsets=NULL;
+
+ // test direct conversion from UTF-8
+ if(cc.utf8Length>=0) {
+ errorCode=U_ZERO_ERROR;
+ resultLength=stepFromUTF8(cc, utf8Cnv, cnv,
+ result, LENGTHOF(result),
+ step, &errorCode);
+ ok=checkFromUnicode(
+ cc, cnv, steps[i].utf8Name,
+ (uint8_t *)result, resultLength,
+ NULL,
+ errorCode);
+ if(U_FAILURE(errorCode) || !cc.finalFlush) {
+ // reset if an error occurred or we did not flush
+ // otherwise do nothing to make sure that flushing resets
+ ucnv_resetToUnicode(utf8Cnv);
+ ucnv_resetFromUnicode(cnv);
+ }
+ }
+ }
+
+ // not a real loop, just a convenience for breaking out of the block
+ while(ok && cc.finalFlush) {
+ // test ucnv_fromUChars()
+ memset(result, 0, sizeof(result));
+
+ errorCode=U_ZERO_ERROR;
+ resultLength=ucnv_fromUChars(cnv,
+ result, LENGTHOF(result),
+ cc.unicode, cc.unicodeLength,
+ &errorCode);
+ ok=checkFromUnicode(
+ cc, cnv, "fromUChars",
+ (uint8_t *)result, resultLength,
+ NULL,
+ errorCode);
+ if(!ok) {
+ break;
+ }
+
+ // test preflighting
+ // keep the correct result for simple checking
+ errorCode=U_ZERO_ERROR;
+ resultLength=ucnv_fromUChars(cnv,
+ NULL, 0,
+ cc.unicode, cc.unicodeLength,
+ &errorCode);
+ if(errorCode==U_STRING_NOT_TERMINATED_WARNING || errorCode==U_BUFFER_OVERFLOW_ERROR) {
+ errorCode=U_ZERO_ERROR;
+ }
+ ok=checkFromUnicode(
+ cc, cnv, "preflight fromUChars",
+ (uint8_t *)result, resultLength,
+ NULL,
+ errorCode);
+ break;
+ }
+
+ ucnv_close(cnv);
+ return ok;
+}
+
+UBool
+ConversionTest::checkFromUnicode(ConversionCase &cc, UConverter *cnv, const char *name,
+ const uint8_t *result, int32_t resultLength,
+ const int32_t *resultOffsets,
+ UErrorCode resultErrorCode) {
+ UChar resultInvalidUChars[8];
+ int8_t resultInvalidLength;
+ UErrorCode errorCode;
+
+ const char *msg;
+
+ // reset the message; NULL will mean "ok"
+ msg=NULL;
+
+ errorCode=U_ZERO_ERROR;
+ resultInvalidLength=LENGTHOF(resultInvalidUChars);
+ ucnv_getInvalidUChars(cnv, resultInvalidUChars, &resultInvalidLength, &errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("fromUnicode[%d](%s cb=\"%s\" fb=%d flush=%d %s) ucnv_getInvalidUChars() failed - %s",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, name, u_errorName(errorCode));
+ return FALSE;
+ }
+
+ // check everything that might have gone wrong
+ if(cc.bytesLength!=resultLength) {
+ msg="wrong result length";
+ } else if(0!=memcmp(cc.bytes, result, cc.bytesLength)) {
+ msg="wrong result string";
+ } else if(cc.offsets!=NULL && 0!=memcmp(cc.offsets, resultOffsets, cc.bytesLength*sizeof(*cc.offsets))) {
+ msg="wrong offsets";
+ } else if(cc.outErrorCode!=resultErrorCode) {
+ msg="wrong error code";
+ } else if(cc.invalidLength!=resultInvalidLength) {
+ msg="wrong length of last invalid input";
+ } else if(0!=u_memcmp(cc.invalidUChars, resultInvalidUChars, cc.invalidLength)) {
+ msg="wrong last invalid input";
+ }
+
+ if(msg==NULL) {
+ return TRUE;
+ } else {
+ char buffer[2000]; // one buffer for all strings
+ char *s, *unicodeString, *bytesString, *resultString,
+ *offsetsString, *resultOffsetsString,
+ *invalidCharsString, *resultInvalidUCharsString;
+
+ unicodeString=s=buffer;
+ s=printUnicode(cc.unicode, cc.unicodeLength, unicodeString);
+ s=printBytes(cc.bytes, cc.bytesLength, bytesString=s);
+ s=printBytes(result, resultLength, resultString=s);
+ s=printOffsets(cc.offsets, cc.bytesLength, offsetsString=s);
+ s=printOffsets(resultOffsets, resultLength, resultOffsetsString=s);
+ s=printUnicode(cc.invalidUChars, cc.invalidLength, invalidCharsString=s);
+ s=printUnicode(resultInvalidUChars, resultInvalidLength, resultInvalidUCharsString=s);
+
+ if((s-buffer)>(int32_t)sizeof(buffer)) {
+ errln("fromUnicode[%d](%s cb=\"%s\" fb=%d flush=%d %s) fatal error: checkFromUnicode() test output buffer overflow writing %d chars\n",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, name, (int)(s-buffer));
+ exit(1);
+ }
+
+ errln("fromUnicode[%d](%s cb=\"%s\" fb=%d flush=%d %s) failed: %s\n"
+ " unicode <%s>[%d]\n"
+ " expected <%s>[%d]\n"
+ " result <%s>[%d]\n"
+ " offsets <%s>\n"
+ " result offsets <%s>\n"
+ " error code expected %s got %s\n"
+ " invalidChars expected <%s> got <%s>\n",
+ cc.caseNr, cc.charset, cc.cbopt, cc.fallbacks, cc.finalFlush, name, msg,
+ unicodeString, cc.unicodeLength,
+ bytesString, cc.bytesLength,
+ resultString, resultLength,
+ offsetsString,
+ resultOffsetsString,
+ u_errorName(cc.outErrorCode), u_errorName(resultErrorCode),
+ invalidCharsString, resultInvalidUCharsString);
+
+ return FALSE;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/convtest.h b/Build/source/libs/icu/icu-xetex/test/intltest/convtest.h
new file mode 100644
index 00000000000..888bbc7038e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/convtest.h
@@ -0,0 +1,104 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2003-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: convtest.h
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2003jul15
+ * created by: Markus W. Scherer
+ *
+ * Test file for data-driven conversion tests.
+ */
+
+#ifndef __CONVTEST_H__
+#define __CONVTEST_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_LEGACY_CONVERSION
+
+#include "unicode/ucnv.h"
+#include "intltest.h"
+
+struct ConversionCase {
+ /* setup */
+ int32_t caseNr;
+ const char *charset, *cbopt, *name;
+ UChar subString[16];
+ char subchar[8];
+ int8_t setSub;
+
+ /* input and expected output */
+ const uint8_t *bytes;
+ int32_t bytesLength;
+ const UChar *unicode;
+ int32_t unicodeLength;
+ const int32_t *offsets;
+
+ /* UTF-8 version of unicode[unicodeLength] */
+ const char *utf8;
+ int32_t utf8Length;
+
+ /* options */
+ UBool finalFlush;
+ UBool fallbacks;
+ UErrorCode outErrorCode;
+ const uint8_t *invalidChars;
+ const UChar *invalidUChars;
+ int32_t invalidLength;
+
+ /* actual output */
+ uint8_t resultBytes[200];
+ UChar resultUnicode[200];
+ int32_t resultOffsets[200];
+ int32_t resultLength;
+
+ UErrorCode resultErrorCode;
+};
+
+class ConversionTest : public IntlTest {
+public:
+ ConversionTest();
+ virtual ~ConversionTest();
+
+ void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
+
+ void TestToUnicode();
+ void TestFromUnicode();
+ void TestGetUnicodeSet();
+
+private:
+ UBool
+ ToUnicodeCase(ConversionCase &cc, UConverterToUCallback callback, const char *option);
+
+ UBool
+ FromUnicodeCase(ConversionCase &cc, UConverterFromUCallback callback, const char *option);
+
+ UBool
+ checkToUnicode(ConversionCase &cc, UConverter *cnv, const char *name,
+ const UChar *result, int32_t resultLength,
+ const int32_t *resultOffsets,
+ UErrorCode resultErrorCode);
+
+ UBool
+ checkFromUnicode(ConversionCase &cc, UConverter *cnv, const char *name,
+ const uint8_t *result, int32_t resultLength,
+ const int32_t *resultOffsets,
+ UErrorCode resultErrorCode);
+
+ UConverter *
+ cnv_open(const char *name, UErrorCode &errorCode);
+
+ /* for testing direct UTF-8 conversion */
+ UConverter *utf8Cnv;
+};
+
+#endif /* #if !UCONFIG_NO_LEGACY_CONVERSION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/cpdtrtst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/cpdtrtst.cpp
new file mode 100644
index 00000000000..d02ceed97be
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/cpdtrtst.cpp
@@ -0,0 +1,442 @@
+/***************************************************************************
+*
+* Copyright (C) 2000-2005, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+************************************************************************
+* Date Name Description
+* 03/09/2000 Madhu Creation.
+************************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "cpdtrtst.h"
+#include "unicode/utypes.h"
+#include "unicode/translit.h"
+#include "unicode/uniset.h"
+#include "cpdtrans.h"
+#include "cmemory.h"
+
+//---------------------------------------------
+// runIndexedTest
+//---------------------------------------------
+
+void
+CompoundTransliteratorTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ TESTCASE(0,TestConstruction);
+ TESTCASE(1,TestCloneEqual);
+ TESTCASE(2,TestGetCount);
+ TESTCASE(3,TestGetSetAdoptTransliterator);
+ TESTCASE(4,TestTransliterate);
+ default: name = ""; break;
+ }
+}
+
+void CompoundTransliteratorTest::TestConstruction(){
+ logln("Testing the construction of the compound Transliterator");
+ UnicodeString names[]={"Greek-Latin", "Latin-Devanagari", "Devanagari-Latin", "Latin-Greek"};
+ UParseError parseError;
+ UErrorCode status=U_ZERO_ERROR;
+ Transliterator* t1=Transliterator::createInstance(names[0], UTRANS_FORWARD, parseError, status);
+ Transliterator* t2=Transliterator::createInstance(names[1], UTRANS_FORWARD, parseError, status);
+ Transliterator* t3=Transliterator::createInstance(names[2], UTRANS_FORWARD, parseError, status);
+ Transliterator* t4=Transliterator::createInstance(names[3], UTRANS_FORWARD, parseError, status);
+ if(U_FAILURE(status)){
+ errln("Transliterator construction failed");
+ return;
+ }
+
+
+ Transliterator* transarray1[]={t1};
+ Transliterator* transarray2[]={t1, t4};
+ Transliterator* transarray3[]={t4, t1, t2};
+ Transliterator* transarray4[]={t1, t2, t3, t4};
+
+ Transliterator** transarray[4];
+ transarray[0] = transarray1;
+ transarray[1] = transarray2;
+ transarray[2] = transarray3;
+ transarray[3] = transarray4;
+
+ const UnicodeString IDs[]={
+ names[0],
+ names[0]+";"+names[3],
+ names[3]+";"+names[1]+";"+names[2],
+ names[0]+";"+names[1]+";"+names[2]+";"+names[3]
+ };
+
+ uint16_t i=0;
+ for(i=0; i<4; i++){
+ status = U_ZERO_ERROR;
+ CompoundTransliterator *cpdtrans=new CompoundTransliterator(IDs[i],parseError, status);
+ if (U_FAILURE(status)) {
+ errln("Construction using CompoundTransliterator(UnicodeString&, Direction, UnicodeFilter*) failed");
+ }
+ delete cpdtrans;
+
+ CompoundTransliterator *cpdtrans2=new CompoundTransliterator(transarray[i], i+1);
+ if(cpdtrans2 == 0){
+ errln("Construction using CompoundTransliterator(Transliterator* const transliterators[], "
+ "int32_t count, UnicodeFilter* adoptedFilter = 0) failed");
+ continue;
+ }
+ CompoundTransliterator *copycpd=new CompoundTransliterator(*cpdtrans2);
+ if(copycpd->getCount() != cpdtrans2->getCount() || copycpd->getID() != cpdtrans2->getID()) {
+ errln("Copy construction failed");
+ continue;
+ }
+
+
+ delete copycpd;
+ delete cpdtrans2;
+
+ }
+ {
+ /*Test Jitterbug 914 */
+ UErrorCode err = U_ZERO_ERROR;
+ CompoundTransliterator cpdTrans(UnicodeString("Latin-Hangul"),UTRANS_REVERSE,NULL,parseError,err);
+ UnicodeString newID =cpdTrans.getID();
+ if(newID!=UnicodeString("Hangul-Latin")){
+ errln(UnicodeString("Test for Jitterbug 914 for cpdTrans(UnicodeString(\"Latin-Hangul\"),UTRANS_REVERSE,NULL,err) failed"));
+ }
+ }
+ delete t1;
+ delete t2;
+ delete t3;
+ delete t4;
+
+}
+
+void CompoundTransliteratorTest::TestCloneEqual(){
+ logln("Testing the clone() and equality operator functions of Compound Transliterator");
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ CompoundTransliterator *ct1=new CompoundTransliterator("Greek-Latin;Latin-Devanagari",parseError,status);
+ if(U_FAILURE(status)){
+ errln("construction failed");
+ delete ct1;
+ return;
+ }
+ CompoundTransliterator *ct2=new CompoundTransliterator("Greek-Latin", parseError, status);
+ if(U_FAILURE(status)){
+ errln("construction failed");
+ delete ct1;
+ delete ct2;
+ return;
+ }
+ CompoundTransliterator *copyct1=new CompoundTransliterator(*ct1);
+ if(copyct1 == 0){
+ errln("copy construction failed");
+ return;
+ }
+ CompoundTransliterator *copyct2=new CompoundTransliterator(*ct2);
+ if(copyct2 == 0){
+ errln("copy construction failed");
+ return;
+ }
+ CompoundTransliterator equalct1=*copyct1;
+ CompoundTransliterator equalct2=*copyct2;
+
+ if(copyct1->getID() != ct1->getID() || copyct2->getID() != ct2->getID() ||
+ copyct1->getCount() != ct1->getCount() || copyct2->getCount() != ct2->getCount() ||
+ copyct2->getID() == ct1->getID() || copyct1->getID() == ct2->getID() ||
+ copyct2->getCount() == ct1->getCount() || copyct1->getCount() == ct2->getCount() ){
+ errln("Error: copy constructors failed");
+ }
+
+ if(equalct1.getID() != ct1->getID() || equalct2.getID() != ct2->getID() ||
+ equalct1.getID() != copyct1->getID() || equalct2.getID() != copyct2->getID() ||
+ equalct1.getCount() != ct1->getCount() || equalct2.getCount() != ct2->getCount() ||
+ copyct2->getID() == ct1->getID() || copyct1->getID() == ct2->getID() ||
+ equalct1.getCount() != copyct1->getCount() || equalct2.getCount() != copyct2->getCount() ||
+ equalct2.getCount() == ct1->getCount() || equalct1.getCount() == ct2->getCount() ) {
+ errln("Error: =operator or copy constructor failed");
+ }
+
+ CompoundTransliterator *clonect1a=(CompoundTransliterator*)ct1->clone();
+ CompoundTransliterator *clonect1b=(CompoundTransliterator*)equalct1.clone();
+ CompoundTransliterator *clonect2a=(CompoundTransliterator*)ct2->clone();
+ CompoundTransliterator *clonect2b=(CompoundTransliterator*)copyct2->clone();
+
+
+ if(clonect1a->getID() != ct1->getID() || clonect1a->getCount() != ct1->getCount() ||
+ clonect1a->getID() != clonect1b->getID() || clonect1a->getCount() != clonect1b->getCount() ||
+ clonect1a->getID() != equalct1.getID() || clonect1a->getCount() != equalct1.getCount() ||
+ clonect1a->getID() != copyct1->getID() || clonect1a->getCount() != copyct1->getCount() ||
+
+ clonect2b->getID() != ct2->getID() || clonect2a->getCount() != ct2->getCount() ||
+ clonect2a->getID() != clonect2b->getID() || clonect2a->getCount() != clonect2b->getCount() ||
+ clonect2a->getID() != equalct2.getID() || clonect2a->getCount() != equalct2.getCount() ||
+ clonect2b->getID() != copyct2->getID() || clonect2b->getCount() != copyct2->getCount() ) {
+ errln("Error: clone() failed");
+ }
+
+ delete ct1;
+ delete ct2;
+ delete copyct1;
+ delete copyct2;
+ delete clonect1a;
+ delete clonect1b;
+ delete clonect2a;
+ delete clonect2b;
+
+}
+
+void CompoundTransliteratorTest::TestGetCount(){
+ logln("Testing the getCount() API of CompoundTransliterator");
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ CompoundTransliterator *ct1=new CompoundTransliterator("Halfwidth-Fullwidth;Fullwidth-Halfwidth", parseError, status);
+ CompoundTransliterator *ct2=new CompoundTransliterator("Any-Hex;Hex-Any;Cyrillic-Latin;Latin-Cyrillic", parseError, status);
+ CompoundTransliterator *ct3=(CompoundTransliterator*)ct1;
+ if (U_FAILURE(status)) {
+ errln("FAILED: CompoundTransliterator constructor failed");
+ return;
+ }
+ CompoundTransliterator *ct4=new CompoundTransliterator("Latin-Devanagari", parseError, status);
+ CompoundTransliterator *ct5=new CompoundTransliterator(*ct4);
+
+ if (U_FAILURE(status)) {
+ errln("FAILED: CompoundTransliterator constructor failed");
+ return;
+ }
+ if(ct1->getCount() == ct2->getCount() || ct1->getCount() != ct3->getCount() ||
+ ct2->getCount() == ct3->getCount() ||
+ ct4->getCount() != ct5->getCount() || ct4->getCount() == ct1->getCount() ||
+ ct4->getCount() == ct2->getCount() || ct4->getCount() == ct3->getCount() ||
+ ct5->getCount() == ct2->getCount() || ct5->getCount() == ct3->getCount() ) {
+ errln("Error: getCount() failed");
+ }
+
+ /* Quick test getTargetSet(), only test that it doesn't die. TODO: a better test. */
+ UnicodeSet ts;
+ UnicodeSet *retUS = NULL;
+ retUS = &ct1->getTargetSet(ts);
+ if (retUS != &ts || ts.size() == 0) {
+ errln("CompoundTransliterator::getTargetSet() failed.\n");
+ }
+
+ /* Quick test getSourceSet(), only test that it doesn't die. TODO: a better test. */
+ UnicodeSet ss;
+ retUS = NULL;
+ retUS = &ct1->getSourceSet(ss);
+ if (retUS != &ss || ss.size() == 0) {
+ errln("CompoundTransliterator::getSourceSet() failed.\n");
+ }
+
+ delete ct1;
+ delete ct2;
+ delete ct4;
+ delete ct5;
+}
+
+void CompoundTransliteratorTest::TestGetSetAdoptTransliterator(){
+ logln("Testing the getTransliterator() API of CompoundTransliterator");
+ UnicodeString ID("Latin-Greek;Greek-Latin;Latin-Devanagari;Devanagari-Latin;Latin-Cyrillic;Cyrillic-Latin;Any-Hex;Hex-Any");
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ CompoundTransliterator *ct1=new CompoundTransliterator(ID, parseError, status);
+ if(U_FAILURE(status)){
+ errln("CompoundTransliterator construction failed");
+ return;
+ }
+ int32_t count=ct1->getCount();
+ UnicodeString *array=split(ID, 0x003b, count);
+ int i;
+ for(i=0; i < count; i++){
+ UnicodeString child= ct1->getTransliterator(i).getID();
+ if(child != *(array+i)){
+ errln("Error getTransliterator() failed: Expected->" + *(array+i) + " Got->" + child);
+ }else {
+ logln("OK: getTransliterator() passed: Expected->" + *(array+i) + " Got->" + child);
+ }
+ }
+ delete []array;
+
+ logln("Testing setTransliterator() API of CompoundTransliterator");
+ UnicodeString ID2("Hex-Any;Any-Hex;Latin-Cyrillic;Cyrillic-Latin;Halfwidth-Fullwidth;Fullwidth-Halfwidth");
+ array=split(ID2, 0x003b, count);
+ Transliterator** transarray=new Transliterator*[count];
+ for(i=0;i<count;i++){
+ transarray[i]=Transliterator::createInstance(*(array+i), UTRANS_FORWARD, parseError, status);
+ if(U_FAILURE(status)){
+ errln("Error could not create Transliterator with ID :"+*(array+i));
+ }else{
+ logln("The ID for the transltierator created is " + transarray[i]->getID());
+ }
+ status = U_ZERO_ERROR;
+ }
+
+ /*setTransliterator and adoptTransliterator */
+
+ ct1->setTransliterators(transarray, count);
+ if(ct1->getCount() != count || ct1->getID() != ID2){
+ errln((UnicodeString)"Error: setTransliterators() failed.\n\t Count:- expected->" + count + (UnicodeString)". got->" + ct1->getCount() +
+ (UnicodeString)"\n\tID :- expected->" + ID2 + (UnicodeString)". got->" + ct1->getID());
+ }
+ else{
+ logln("OK: setTransliterators() passed");
+ }
+ /*UnicodeString temp;
+ for(i=0;i<count-1;i++){
+ temp.append(ct1->getTransliterator(i).getID());
+ temp.append(";");
+ }
+ temp.append(ct1->getTransliterator(i).getID());
+ if(temp != ID2){
+ errln("Error: setTransliterator() failed. Expected->" + ID2 + "\nGot->" + temp);
+ }
+ else{
+ logln("OK: setTransliterator() passed");
+ }*/
+ logln("Testing adoptTransliterator() API of CompoundTransliterator");
+ UnicodeString ID3("Latin-Katakana");
+ Transliterator **transarray2=(Transliterator **)uprv_malloc(sizeof(Transliterator*)*1);
+ transarray2[0] = Transliterator::createInstance(ID3,UTRANS_FORWARD,parseError,status);
+ if (transarray2[0] != 0) {
+ ct1->adoptTransliterators(transarray2, 1);
+ }
+ if(ct1->getCount() != 1 || ct1->getID() != ID3){
+ errln((UnicodeString)"Error: adoptTransliterators() failed.\n\t Count:- expected->1" + (UnicodeString)". got->" + ct1->getCount() +
+ (UnicodeString)"\n\tID :- expected->" + ID3 + (UnicodeString)". got->" + ct1->getID());
+ }
+ else{
+ logln("OK: adoptTranslterator() passed");
+ }
+ delete ct1;
+ for(i=0;i<count;i++){
+ delete transarray[i];
+ }
+ delete []transarray;
+ delete []array;
+}
+
+/**
+ * Splits a UnicodeString
+ */
+UnicodeString* CompoundTransliteratorTest::split(const UnicodeString& str, UChar seperator, int32_t& count) {
+
+ //get the count
+ int32_t i;
+ count =1;
+ for(i=0; i<str.length(); i++){
+ if(str.charAt(i) == seperator)
+ count++;
+ }
+ // make an array
+ UnicodeString* result = new UnicodeString[count];
+ int32_t last = 0;
+ int32_t current = 0;
+ for (i = 0; i < str.length(); ++i) {
+ if (str.charAt(i) == seperator) {
+ str.extractBetween(last, i, result[current]);
+ last = i+1;
+ current++;
+ }
+ }
+ str.extractBetween(last, i, result[current]);
+ return result;
+}
+void CompoundTransliteratorTest::TestTransliterate(){
+ logln("Testing the handleTransliterate() API of CompoundTransliterator");
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ CompoundTransliterator *ct1=new CompoundTransliterator("Any-Hex;Hex-Any",parseError, status);
+ if(U_FAILURE(status)){
+ errln("CompoundTransliterator construction failed");
+ }else {
+#if 0
+ // handleTransliterate is a protected method that was erroneously made
+ // public. It is not public API that needs to be tested.
+ UnicodeString s("abcabc");
+ expect(*ct1, s, s);
+ UTransPosition index = { 0, 0, 0, 0 };
+ UnicodeString rsource2(s);
+ UnicodeString expectedResult=s;
+ ct1->handleTransliterate(rsource2, index, FALSE);
+ expectAux(ct1->getID() + ":String, index(0,0,0), incremental=FALSE", rsource2 + "->" + rsource2, rsource2==expectedResult, expectedResult);
+ UTransPosition _index = {1,3,2,3};
+ uprv_memcpy(&index, &_index, sizeof(index));
+ UnicodeString rsource3(s);
+ ct1->handleTransliterate(rsource3, index, TRUE);
+ expectAux(ct1->getID() + ":String, index(1,2,3), incremental=TRUE", rsource3 + "->" + rsource3, rsource3==expectedResult, expectedResult);
+#endif
+ }
+ delete ct1;
+ UnicodeString Data[]={
+ //ID, input string, transliterated string
+ "Any-Hex;Hex-Any;Any-Hex", "hello", UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F", ""),
+ "Any-Hex;Hex-Any", "hello! How are you?", "hello! How are you?",
+ //"Devanagari-Latin;Latin-Devanagari", CharsToUnicodeString("\\u092D\\u0948'\\u0930'\\u0935"), CharsToUnicodeString("\\u092D\\u0948\\u0930\\u0935"), // quotes lost
+ "Latin-Cyrillic;Cyrillic-Latin", "a'b'k'd'e'f'g'h'i'j'Shch'shch'zh'h", "a'b'k'd'e'f'g'h'i'j'Shch'shch'zh'h", //"abkdefghijShchshchzhh",
+ "Latin-Greek;Greek-Latin", "ABGabgAKLMN", "ABGabgAKLMN",
+ //"Latin-Arabic;Arabic-Latin", "Ad'r'a'b'i'k'dh'dd'gh", "Adrabikdhddgh",
+ "Hiragana-Katakana", CharsToUnicodeString("\\u3041\\u308f\\u3099\\u306e\\u304b\\u3092\\u3099"),
+ CharsToUnicodeString("\\u30A1\\u30f7\\u30ce\\u30ab\\u30fa"),
+ "Hiragana-Katakana;Katakana-Hiragana", CharsToUnicodeString("\\u3041\\u308f\\u3099\\u306e\\u304b\\u3051"),
+ CharsToUnicodeString("\\u3041\\u308f\\u3099\\u306e\\u304b\\u3051"),
+ "Katakana-Hiragana;Hiragana-Katakana", CharsToUnicodeString("\\u30A1\\u30f7\\u30ce\\u30f5\\u30f6"),
+ CharsToUnicodeString("\\u30A1\\u30f7\\u30ce\\u30ab\\u30b1"),
+ "Latin-Katakana;Katakana-Latin", CharsToUnicodeString("vavivuvevohuzizuzonyinyunyasesuzezu"),
+ CharsToUnicodeString("vavivuvevohuzizuzonyinyunyasesuzezu"),
+ };
+ uint32_t i;
+ for(i=0; i<sizeof(Data)/sizeof(Data[0]); i=i+3){
+ UErrorCode status = U_ZERO_ERROR;
+
+ CompoundTransliterator *ct2=new CompoundTransliterator(Data[i+0], parseError, status);
+ if(U_FAILURE(status)){
+ errln("CompoundTransliterator construction failed for " + Data[i+0]);
+ } else {
+ expect(*ct2, Data[i+1], Data[i+2]);
+ }
+ delete ct2;
+ }
+
+}
+
+
+
+//======================================================================
+// Support methods
+//======================================================================
+void CompoundTransliteratorTest::expect(const CompoundTransliterator& t,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult) {
+
+ UnicodeString rsource(source);
+ t.transliterate(rsource);
+ expectAux(t.getID() + ":Replaceable", source + "->" + rsource, rsource==expectedResult, expectedResult);
+
+ // Test transliterate (incremental) transliteration --
+ rsource.remove();
+ rsource.append(source);
+ UTransPosition index;
+ index.contextStart =0;
+ index.contextLimit = source.length();
+ index.start = 0;
+ index.limit = source.length();
+ UErrorCode ec = U_ZERO_ERROR;
+ t.transliterate(rsource, index, ec);
+ t.finishTransliteration(rsource,index);
+ expectAux(t.getID() + ":handleTransliterate ", source + "->" + rsource, rsource==expectedResult, expectedResult);
+
+}
+
+void CompoundTransliteratorTest::expectAux(const UnicodeString& tag,
+ const UnicodeString& summary, UBool pass,
+ const UnicodeString& expectedResult) {
+ if (pass) {
+ logln(UnicodeString("(")+tag+") " + prettify(summary));
+ } else {
+ errln(UnicodeString("FAIL: (")+tag+") "
+ + prettify(summary)
+ + ", expected " + prettify(expectedResult));
+ }
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/cpdtrtst.h b/Build/source/libs/icu/icu-xetex/test/intltest/cpdtrtst.h
new file mode 100644
index 00000000000..463a29ebe71
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/cpdtrtst.h
@@ -0,0 +1,64 @@
+
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/***********************************************************************
+************************************************************************
+* Date Name Description
+* 03/09/2000 Madhu Creation.
+************************************************************************/
+
+#ifndef CPDTRTST_H
+#define CPDTRTST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "intltest.h"
+
+/**
+ * @test
+ * @summary General test of Compound Transliterator
+ */
+class CompoundTransliteratorTest : public IntlTest {
+public:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par=NULL);
+
+ /*Tests the constructors */
+ void TestConstruction(void);
+ /*Tests the function clone, and operator==()*/
+ void TestCloneEqual(void);
+ /*Tests the function getCount()*/
+ void TestGetCount(void);
+ /*Tests the function getTransliterator() and setTransliterators() and adoptTransliterators()*/
+ void TestGetSetAdoptTransliterator(void);
+ /*Tests the function handleTransliterate()*/
+ void TestTransliterate(void);
+
+ //======================================================================
+ // Support methods
+ //======================================================================
+
+ /**
+ * Splits a UnicodeString
+ */
+ UnicodeString* split(const UnicodeString& str, UChar seperator, int32_t& count);
+
+ void expect(const CompoundTransliterator& t,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult);
+
+ void expectAux(const UnicodeString& tag,
+ const UnicodeString& summary, UBool pass,
+ const UnicodeString& expectedResult);
+
+
+};
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/csdetest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/csdetest.cpp
new file mode 100644
index 00000000000..1f5992f778f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/csdetest.cpp
@@ -0,0 +1,518 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+
+#include "unicode/utypes.h"
+#include "unicode/ucsdet.h"
+#include "unicode/ucnv.h"
+#include "unicode/unistr.h"
+#include "unicode/putil.h"
+
+#include "intltest.h"
+#include "csdetest.h"
+
+#include "xmlparser.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DEBUG_DETECT
+#include <stdio.h>
+#endif
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define NEW_ARRAY(type,count) (type *) /*uprv_*/malloc((count) * sizeof(type))
+#define DELETE_ARRAY(array) /*uprv_*/free((void *) (array))
+
+#define CH_SPACE 0x0020
+#define CH_SLASH 0x002F
+
+//---------------------------------------------------------------------------
+//
+// Test class boilerplate
+//
+//---------------------------------------------------------------------------
+CharsetDetectionTest::CharsetDetectionTest()
+{
+}
+
+
+CharsetDetectionTest::~CharsetDetectionTest()
+{
+}
+
+
+
+void CharsetDetectionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CharsetDetectionTest: ");
+ switch (index) {
+ case 0: name = "ConstructionTest";
+ if (exec) ConstructionTest();
+ break;
+
+ case 1: name = "UTF8Test";
+ if (exec) UTF8Test();
+ break;
+
+ case 2: name = "UTF16Test";
+ if (exec) UTF16Test();
+ break;
+
+ case 3: name = "C1BytesTest";
+ if (exec) C1BytesTest();
+ break;
+
+ case 4: name = "InputFilterTest";
+ if (exec) InputFilterTest();
+ break;
+
+ case 5: name = "DetectionTest";
+ if (exec) DetectionTest();
+ break;
+
+ default: name = "";
+ break; //needed to end loop
+ }
+}
+
+static UnicodeString *split(const UnicodeString &src, UChar ch, int32_t &splits)
+{
+ int32_t offset = -1;
+
+ splits = 1;
+ while((offset = src.indexOf(ch, offset + 1)) >= 0) {
+ splits += 1;
+ }
+
+ UnicodeString *result = new UnicodeString[splits];
+
+ int32_t start = 0;
+ int32_t split = 0;
+ int32_t end;
+
+ while((end = src.indexOf(ch, start)) >= 0) {
+ src.extractBetween(start, end, result[split++]);
+ start = end + 1;
+ }
+
+ src.extractBetween(start, src.length(), result[split]);
+
+ return result;
+}
+
+static char *extractBytes(const UnicodeString &source, const char *codepage, int32_t &length)
+{
+ int32_t sLength = source.length();
+ char *bytes = NULL;
+
+ length = source.extract(0, sLength, NULL, codepage);
+
+ if (length > 0) {
+ bytes = NEW_ARRAY(char, length + 1);
+ source.extract(0, sLength, bytes, codepage);
+ }
+
+ return bytes;
+}
+
+static void freeBytes(char *bytes)
+{
+ DELETE_ARRAY(bytes);
+}
+
+void CharsetDetectionTest::checkEncoding(const UnicodeString &testString, const UnicodeString &encoding, const UnicodeString &id)
+{
+ int32_t splits = 0;
+ int32_t testLength = testString.length();
+ UnicodeString *eSplit = split(encoding, CH_SLASH, splits);
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t cpLength = eSplit[0].length();
+ char codepage[64];
+
+ u_UCharsToChars(eSplit[0].getBuffer(), codepage, cpLength);
+ codepage[cpLength] = '\0';
+
+ UCharsetDetector *csd = ucsdet_open(&status);
+
+ int32_t byteLength = 0;
+ char *bytes = extractBytes(testString, codepage, byteLength);
+
+ if (bytes == NULL) {
+#if !UCONFIG_NO_LEGACY_CONVERSION
+ errln("Can't open a " + encoding + " converter for " + id);
+#endif
+ return;
+ }
+
+ ucsdet_setText(csd, bytes, byteLength, &status);
+
+ int32_t matchCount = 0;
+ const UCharsetMatch **matches = ucsdet_detectAll(csd, &matchCount, &status);
+
+
+ UnicodeString name(ucsdet_getName(matches[0], &status));
+ UnicodeString lang(ucsdet_getLanguage(matches[0], &status));
+ UChar *decoded = NULL;
+ int32_t dLength = 0;
+
+ if (matchCount == 0) {
+ errln("Encoding detection failure for " + id + ": expected " + eSplit[0] + ", got no matches");
+ goto bail;
+ }
+
+ if (name.compare(eSplit[0]) != 0) {
+ errln("Encoding detection failure for " + id + ": expected " + eSplit[0] + ", got " + name);
+
+#ifdef DEBUG_DETECT
+ for (int32_t m = 0; m < matchCount; m += 1) {
+ const char *name = ucsdet_getName(matches[m], &status);
+ const char *lang = ucsdet_getLanguage(matches[m], &status);
+ int32_t confidence = ucsdet_getConfidence(matches[m], &status);
+
+ printf("%s (%s) %d\n", name, lang, confidence);
+ }
+#endif
+ goto bail;
+ }
+
+ if (splits > 1 && lang.compare(eSplit[1]) != 0) {
+ errln("Language detection failure for " + id + ", " + eSplit[0] + ": expected " + eSplit[1] + ", got " + lang);
+ goto bail;
+ }
+
+ decoded = NEW_ARRAY(UChar, testLength);
+ dLength = ucsdet_getUChars(matches[0], decoded, testLength, &status);
+
+ if (testString.compare(decoded, dLength) != 0) {
+ errln("Round-trip error for " + id + ", " + eSplit[0] + ": getUChars() didn't yeild the original string.");
+
+#ifdef DEBUG_DETECT
+ for(int32_t i = 0; i < testLength; i += 1) {
+ if(testString[i] != decoded[i]) {
+ printf("Strings differ at byte %d\n", i);
+ break;
+ }
+ }
+#endif
+
+ }
+
+ DELETE_ARRAY(decoded);
+
+bail:
+ freeBytes(bytes);
+ ucsdet_close(csd);
+ delete[] eSplit;
+}
+
+const char *CharsetDetectionTest::getPath(char buffer[2048], const char *filename) {
+ UErrorCode status = U_ZERO_ERROR;
+ const char *testDataDirectory = IntlTest::getSourceTestData(status);
+
+ if (U_FAILURE(status)) {
+ errln("ERROR: getPath() failed - %s", u_errorName(status));
+ return NULL;
+ }
+
+ strcpy(buffer, testDataDirectory);
+ strcat(buffer, filename);
+ return buffer;
+}
+
+void CharsetDetectionTest::ConstructionTest()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UCharsetDetector *csd = ucsdet_open(&status);
+ UEnumeration *e = ucsdet_getAllDetectableCharsets(csd, &status);
+ int32_t count = uenum_count(e, &status);
+
+#ifdef DEBUG_DETECT
+ printf("There are %d recognizers.\n", count);
+#endif
+
+ for(int32_t i = 0; i < count; i += 1) {
+ int32_t length;
+ const char *name = uenum_next(e, &length, &status);
+
+ if(name == NULL || length <= 0) {
+ errln("ucsdet_getAllDetectableCharsets() returned a null or empty name!");
+ }
+
+#ifdef DEBUG_DETECT
+ printf("%s\n", name);
+#endif
+ }
+
+ uenum_close(e);
+ ucsdet_close(csd);
+}
+
+void CharsetDetectionTest::UTF8Test()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString ss = "This is a string with some non-ascii characters that will "
+ "be converted to UTF-8, then shoved through the detection process. "
+ "\\u0391\\u0392\\u0393\\u0394\\u0395"
+ "Sure would be nice if our source could contain Unicode directly!";
+ UnicodeString s = ss.unescape();
+ int32_t byteLength = 0, sLength = s.length();
+ char *bytes = extractBytes(s, "UTF-8", byteLength);
+ UCharsetDetector *csd = ucsdet_open(&status);
+ const UCharsetMatch *match;
+ UChar *detected = NEW_ARRAY(UChar, sLength);
+
+ ucsdet_setText(csd, bytes, byteLength, &status);
+ match = ucsdet_detect(csd, &status);
+
+ if (match == NULL) {
+ errln("Detection failure for UTF-8: got no matches.");
+ goto bail;
+ }
+
+ ucsdet_getUChars(match, detected, sLength, &status);
+
+ if (s.compare(detected, sLength) != 0) {
+ errln("Round-trip test failed!");
+ }
+
+ ucsdet_setDeclaredEncoding(csd, "UTF-8", 5, &status); /* for coverage */
+
+bail:
+ DELETE_ARRAY(detected);
+ freeBytes(bytes);
+ ucsdet_close(csd);
+}
+
+void CharsetDetectionTest::UTF16Test()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ /* Notice the BOM on the start of this string */
+ UChar chars[] = {
+ 0xFEFF, 0x0623, 0x0648, 0x0631, 0x0648, 0x0628, 0x0627, 0x002C,
+ 0x0020, 0x0628, 0x0631, 0x0645, 0x062c, 0x064a, 0x0627, 0x062a,
+ 0x0020, 0x0627, 0x0644, 0x062d, 0x0627, 0x0633, 0x0648, 0x0628,
+ 0x0020, 0x002b, 0x0020, 0x0627, 0x0646, 0x062a, 0x0631, 0x0646,
+ 0x064a, 0x062a, 0x0000};
+ UnicodeString s(chars);
+ int32_t beLength = 0, leLength = 0;
+ char *beBytes = extractBytes(s, "UTF-16BE", beLength);
+ char *leBytes = extractBytes(s, "UTF-16LE", leLength);
+ UCharsetDetector *csd = ucsdet_open(&status);
+ const UCharsetMatch *match;
+ const char *name;
+ int32_t conf;
+
+ ucsdet_setText(csd, beBytes, beLength, &status);
+ match = ucsdet_detect(csd, &status);
+
+ if (match == NULL) {
+ errln("Encoding detection failure for UTF-16BE: got no matches.");
+ goto try_le;
+ }
+
+ name = ucsdet_getName(match, &status);
+ conf = ucsdet_getConfidence(match, &status);
+
+ if (strcmp(name, "UTF-16BE") != 0) {
+ errln("Encoding detection failure for UTF-16BE: got %s", name);
+ goto try_le; // no point in looking at confidence if we got the wrong character set.
+ }
+
+ if (conf != 100) {
+ errln("Did not get 100%% confidence for UTF-16BE: got %d", conf);
+ }
+
+try_le:
+ ucsdet_setText(csd, leBytes, leLength, &status);
+ match = ucsdet_detect(csd, &status);
+
+ if (match == NULL) {
+ errln("Encoding detection failure for UTF-16LE: got no matches.");
+ goto bail;
+ }
+
+ name = ucsdet_getName(match, &status);
+ conf = ucsdet_getConfidence(match, &status);
+
+
+ if (strcmp(name, "UTF-16LE") != 0) {
+ errln("Enconding detection failure for UTF-16LE: got %s", name);
+ goto bail; // no point in looking at confidence if we got the wrong character set.
+ }
+
+ if (conf != 100) {
+ errln("Did not get 100%% confidence for UTF-16LE: got %d", conf);
+ }
+
+bail:
+ freeBytes(leBytes);
+ freeBytes(beBytes);
+ ucsdet_close(csd);
+}
+
+void CharsetDetectionTest::InputFilterTest()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString ss = "<a> <lot> <of> <English> <inside> <the> <markup> Un tr\\u00E8s petit peu de Fran\\u00E7ais. <to> <confuse> <the> <detector>";
+ UnicodeString s = ss.unescape();
+ int32_t byteLength = 0;
+ char *bytes = extractBytes(s, "ISO-8859-1", byteLength);
+ UCharsetDetector *csd = ucsdet_open(&status);
+ const UCharsetMatch *match;
+ const char *lang, *name;
+
+ ucsdet_enableInputFilter(csd, TRUE);
+
+ if (!ucsdet_isInputFilterEnabled(csd)) {
+ errln("ucsdet_enableInputFilter(csd, TRUE) did not enable input filter!");
+ }
+
+
+ ucsdet_setText(csd, bytes, byteLength, &status);
+ match = ucsdet_detect(csd, &status);
+
+ if (match == NULL) {
+ errln("Turning on the input filter resulted in no matches.");
+ goto turn_off;
+ }
+
+ name = ucsdet_getName(match, &status);
+
+ if (name == NULL || strcmp(name, "ISO-8859-1") != 0) {
+ errln("Turning on the input filter resulted in %s rather than ISO-8859-1.", name);
+ } else {
+ lang = ucsdet_getLanguage(match, &status);
+
+ if (lang == NULL || strcmp(lang, "fr") != 0) {
+ errln("Input filter did not strip markup!");
+ }
+ }
+
+turn_off:
+ ucsdet_enableInputFilter(csd, FALSE);
+ ucsdet_setText(csd, bytes, byteLength, &status);
+ match = ucsdet_detect(csd, &status);
+
+ if (match == NULL) {
+ errln("Turning off the input filter resulted in no matches.");
+ goto bail;
+ }
+
+ name = ucsdet_getName(match, &status);
+
+ if (name == NULL || strcmp(name, "ISO-8859-1") != 0) {
+ errln("Turning off the input filter resulted in %s rather than ISO-8859-1.", name);
+ } else {
+ lang = ucsdet_getLanguage(match, &status);
+
+ if (lang == NULL || strcmp(lang, "en") != 0) {
+ errln("Unfiltered input did not detect as English!");
+ }
+ }
+
+bail:
+ freeBytes(bytes);
+ ucsdet_close(csd);
+}
+
+void CharsetDetectionTest::C1BytesTest()
+{
+#if !UCONFIG_NO_LEGACY_CONVERSION
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString sISO = "This is a small sample of some English text. Just enough to be sure that it detects correctly.";
+ UnicodeString ssWindows = "This is another small sample of some English text. Just enough to be sure that it detects correctly. It also includes some \\u201CC1\\u201D bytes.";
+ UnicodeString sWindows = ssWindows.unescape();
+ int32_t lISO = 0, lWindows = 0;
+ char *bISO = extractBytes(sISO, "ISO-8859-1", lISO);
+ char *bWindows = extractBytes(sWindows, "windows-1252", lWindows);
+ UCharsetDetector *csd = ucsdet_open(&status);
+ const UCharsetMatch *match;
+ const char *name;
+
+ ucsdet_setText(csd, bWindows, lWindows, &status);
+ match = ucsdet_detect(csd, &status);
+
+ if (match == NULL) {
+ errln("English test with C1 bytes got no matches.");
+ goto bail;
+ }
+
+ name = ucsdet_getName(match, &status);
+
+ if (strcmp(name, "windows-1252") != 0) {
+ errln("English text with C1 bytes does not detect as windows-1252, but as %s", name);
+ }
+
+ ucsdet_setText(csd, bISO, lISO, &status);
+ match = ucsdet_detect(csd, &status);
+
+ if (match == NULL) {
+ errln("English text without C1 bytes got no matches.");
+ goto bail;
+ }
+
+ name = ucsdet_getName(match, &status);
+
+ if (strcmp(name, "ISO-8859-1") != 0) {
+ errln("English text without C1 bytes does not detect as ISO-8859-1, but as %s", name);
+ }
+
+bail:
+ freeBytes(bWindows);
+ freeBytes(bISO);
+
+ ucsdet_close(csd);
+#endif
+}
+
+void CharsetDetectionTest::DetectionTest()
+{
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+ UErrorCode status = U_ZERO_ERROR;
+ char path[2048];
+ const char *testFilePath = getPath(path, "csdetest.xml");
+
+ if (testFilePath == NULL) {
+ return; /* Couldn't get path: error message already output. */
+ }
+
+ UXMLParser *parser = UXMLParser::createParser(status);
+ if (!assertSuccess("UXMLParser::createParser",status)) return;
+ UXMLElement *root = parser->parseFile(testFilePath, status);
+ if (!assertSuccess( "parseFile",status)) return;
+
+ UnicodeString test_case = UNICODE_STRING_SIMPLE("test-case");
+ UnicodeString id_attr = UNICODE_STRING_SIMPLE("id");
+ UnicodeString enc_attr = UNICODE_STRING_SIMPLE("encodings");
+
+ const UXMLElement *testCase;
+ int32_t tc = 0;
+
+ while((testCase = root->nextChildElement(tc)) != NULL) {
+ if (testCase->getTagName().compare(test_case) == 0) {
+ const UnicodeString *id = testCase->getAttribute(id_attr);
+ const UnicodeString *encodings = testCase->getAttribute(enc_attr);
+ const UnicodeString text = testCase->getText(TRUE);
+ int32_t encodingCount;
+ UnicodeString *encodingList = split(*encodings, CH_SPACE, encodingCount);
+
+ for(int32_t e = 0; e < encodingCount; e += 1) {
+ checkEncoding(text, encodingList[e], *id);
+ }
+
+ delete[] encodingList;
+ }
+ }
+
+ delete root;
+ delete parser;
+#endif
+}
+
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/csdetest.h b/Build/source/libs/icu/icu-xetex/test/intltest/csdetest.h
new file mode 100644
index 00000000000..223a640a57b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/csdetest.h
@@ -0,0 +1,39 @@
+/*
+ **********************************************************************
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __CSDETEST_H
+#define __CSDETEST_H
+
+#include "unicode/utypes.h"
+#include "unicode/unistr.h"
+
+#include "intltest.h"
+
+class CharsetDetectionTest: public IntlTest {
+public:
+
+ CharsetDetectionTest();
+ virtual ~CharsetDetectionTest();
+
+ virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ virtual void ConstructionTest();
+ virtual void UTF8Test();
+ virtual void UTF16Test();
+ virtual void C1BytesTest();
+ virtual void InputFilterTest();
+ virtual void DetectionTest();
+
+private:
+ void checkEncoding(const UnicodeString &testString,
+ const UnicodeString &encoding, const UnicodeString &id);
+
+ virtual const char *getPath(char buffer[2048], const char *filename);
+
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/currcoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/currcoll.cpp
new file mode 100644
index 00000000000..df5a15f8fda
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/currcoll.cpp
@@ -0,0 +1,158 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#ifndef _COLL
+#include "unicode/coll.h"
+#endif
+
+#ifndef _TBLCOLL
+#include "unicode/tblcoll.h"
+#endif
+
+#ifndef _UNISTR
+#include "unicode/unistr.h"
+#endif
+
+#ifndef _SORTKEY
+#include "unicode/sortkey.h"
+#endif
+
+#ifndef _CURRCOLL
+#include "currcoll.h"
+#endif
+
+#include "sfwdchit.h"
+
+#define ARRAY_LENGTH(array) (sizeof array / sizeof array[0])
+
+CollationCurrencyTest::CollationCurrencyTest()
+{
+}
+
+CollationCurrencyTest::~CollationCurrencyTest()
+{
+}
+
+void CollationCurrencyTest::currencyTest(/*char *par*/)
+{
+ // All the currency symbols, in collation order
+ static const UChar currency[][2] =
+ {
+ { 0x00A4, 0x0000}, /*00A4; L; [14 36, 03, 03] # [082B.0020.0002] # CURRENCY SIGN*/
+ { 0x00A2, 0x0000}, /*00A2; L; [14 38, 03, 03] # [082C.0020.0002] # CENT SIGN*/
+ { 0xFFE0, 0x0000}, /*FFE0; L; [14 38, 03, 05] # [082C.0020.0003] # FULLWIDTH CENT SIGN*/
+ { 0x0024, 0x0000}, /*0024; L; [14 3A, 03, 03] # [082D.0020.0002] # DOLLAR SIGN*/
+ { 0xFF04, 0x0000}, /*FF04; L; [14 3A, 03, 05] # [082D.0020.0003] # FULLWIDTH DOLLAR SIGN*/
+ { 0xFE69, 0x0000}, /*FE69; L; [14 3A, 03, 1D] # [082D.0020.000F] # SMALL DOLLAR SIGN*/
+ { 0x00A3, 0x0000}, /*00A3; L; [14 3C, 03, 03] # [082E.0020.0002] # POUND SIGN*/
+ { 0xFFE1, 0x0000}, /*FFE1; L; [14 3C, 03, 05] # [082E.0020.0003] # FULLWIDTH POUND SIGN*/
+ { 0x00A5, 0x0000}, /*00A5; L; [14 3E, 03, 03] # [082F.0020.0002] # YEN SIGN*/
+ { 0xFFE5, 0x0000}, /*FFE5; L; [14 3E, 03, 05] # [082F.0020.0003] # FULLWIDTH YEN SIGN*/
+ { 0x09F2, 0x0000}, /*09F2; L; [14 40, 03, 03] # [0830.0020.0002] # BENGALI RUPEE MARK*/
+ { 0x09F3, 0x0000}, /*09F3; L; [14 42, 03, 03] # [0831.0020.0002] # BENGALI RUPEE SIGN*/
+ { 0x0E3F, 0x0000}, /*0E3F; L; [14 44, 03, 03] # [0832.0020.0002] # THAI CURRENCY SYMBOL BAHT*/
+ { 0x17DB, 0x0000}, /*17DB; L; [14 46, 03, 03] # [0833.0020.0002] # KHMER CURRENCY SYMBOL RIEL*/
+ { 0x20A0, 0x0000}, /*20A0; L; [14 48, 03, 03] # [0834.0020.0002] # EURO-CURRENCY SIGN*/
+ { 0x20A1, 0x0000}, /*20A1; L; [14 4A, 03, 03] # [0835.0020.0002] # COLON SIGN*/
+ { 0x20A2, 0x0000}, /*20A2; L; [14 4C, 03, 03] # [0836.0020.0002] # CRUZEIRO SIGN*/
+ { 0x20A3, 0x0000}, /*20A3; L; [14 4E, 03, 03] # [0837.0020.0002] # FRENCH FRANC SIGN*/
+ { 0x20A4, 0x0000}, /*20A4; L; [14 50, 03, 03] # [0838.0020.0002] # LIRA SIGN*/
+ { 0x20A5, 0x0000}, /*20A5; L; [14 52, 03, 03] # [0839.0020.0002] # MILL SIGN*/
+ { 0x20A6, 0x0000}, /*20A6; L; [14 54, 03, 03] # [083A.0020.0002] # NAIRA SIGN*/
+ { 0x20A7, 0x0000}, /*20A7; L; [14 56, 03, 03] # [083B.0020.0002] # PESETA SIGN*/
+ { 0x20A9, 0x0000}, /*20A9; L; [14 58, 03, 03] # [083C.0020.0002] # WON SIGN*/
+ { 0xFFE6, 0x0000}, /*FFE6; L; [14 58, 03, 05] # [083C.0020.0003] # FULLWIDTH WON SIGN*/
+ { 0x20AA, 0x0000}, /*20AA; L; [14 5A, 03, 03] # [083D.0020.0002] # NEW SHEQEL SIGN*/
+ { 0x20AB, 0x0000}, /*20AB; L; [14 5C, 03, 03] # [083E.0020.0002] # DONG SIGN*/
+ { 0x20AC, 0x0000}, /*20AC; L; [14 5E, 03, 03] # [083F.0020.0002] # EURO SIGN*/
+ { 0x20AD, 0x0000}, /*20AD; L; [14 60, 03, 03] # [0840.0020.0002] # KIP SIGN*/
+ { 0x20AE, 0x0000}, /*20AE; L; [14 62, 03, 03] # [0841.0020.0002] # TUGRIK SIGN*/
+ { 0x20AF, 0x0000}, /*20AF; L; [14 64, 03, 03] # [0842.0020.0002] # DRACHMA SIGN*/
+ };
+
+
+ uint32_t i, j;
+ UErrorCode status = U_ZERO_ERROR;
+ Collator::EComparisonResult expectedResult = Collator::EQUAL;
+ RuleBasedCollator *c = (RuleBasedCollator *)Collator::createInstance("en_US", status);
+
+ if (U_FAILURE(status))
+ {
+ errln ("Collator::createInstance() failed!");
+ return;
+ }
+
+ // Compare each currency symbol against all the
+ // currency symbols, including itself
+ for (i = 0; i < ARRAY_LENGTH(currency); i += 1)
+ {
+ for (j = 0; j < ARRAY_LENGTH(currency); j += 1)
+ {
+ UnicodeString source(currency[i], 1);
+ UnicodeString target(currency[j], 1);
+
+ if (i < j)
+ {
+ expectedResult = Collator::LESS;
+ }
+ else if ( i == j)
+ {
+ expectedResult = Collator::EQUAL;
+ }
+ else
+ {
+ expectedResult = Collator::GREATER;
+ }
+
+ Collator::EComparisonResult compareResult = c->compare(source, target);
+
+ CollationKey sourceKey, targetKey;
+ UErrorCode status = U_ZERO_ERROR;
+
+ c->getCollationKey(source, sourceKey, status);
+
+ if (U_FAILURE(status))
+ {
+ errln("Couldn't get collationKey for source");
+ continue;
+ }
+
+ c->getCollationKey(target, targetKey, status);
+
+ if (U_FAILURE(status))
+ {
+ errln("Couldn't get collationKey for target");
+ continue;
+ }
+
+ Collator::EComparisonResult keyResult = sourceKey.compareTo(targetKey);
+
+ reportCResult( source, target, sourceKey, targetKey, compareResult, keyResult, compareResult, expectedResult );
+
+ }
+ }
+ delete c;
+}
+
+void CollationCurrencyTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/)
+{
+ if (exec)
+ {
+ logln("Collation Currency Tests: ");
+ }
+
+ switch (index)
+ {
+ case 0: name = "currencyTest"; if (exec) currencyTest(/*par*/); break;
+ default: name = ""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/currcoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/currcoll.h
new file mode 100644
index 00000000000..85abec996ac
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/currcoll.h
@@ -0,0 +1,39 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * Collation currency tests.
+ * (It's important to stay current!)
+ */
+
+#ifndef _CURRCOLL
+#define _CURRCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coleitr.h"
+#include "tscoll.h"
+
+class CollationCurrencyTest: public IntlTestCollator
+{
+public:
+
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationCurrencyTest();
+ virtual ~CollationCurrencyTest();
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL);
+
+ void currencyTest(/*char *par*/);
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dadrcal.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/dadrcal.cpp
new file mode 100644
index 00000000000..da2e567abcf
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dadrcal.cpp
@@ -0,0 +1,457 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/***********************************************************************
+ * Modification history
+ * Date Name Description
+ * 07/09/2007 srl Copied from dadrcoll.cpp
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/tstdtmod.h"
+#include "tsdate.h"
+#include "dadrcal.h"
+#include "unicode/calendar.h"
+#include "intltest.h"
+#include <string.h>
+#include "unicode/schriter.h"
+#include "unicode/regex.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/dbgutil.h"
+
+#include <stdio.h>
+
+DataDrivenCalendarTest::DataDrivenCalendarTest() {
+ UErrorCode status = U_ZERO_ERROR;
+ driver = TestDataModule::getTestDataModule("calendar", *this, status);
+}
+
+DataDrivenCalendarTest::~DataDrivenCalendarTest() {
+ delete driver;
+}
+
+void DataDrivenCalendarTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par */) {
+ if (driver != NULL) {
+ if (exec) {
+ // logln("Begin ");
+ }
+ const DataMap *info= NULL;
+ UErrorCode status= U_ZERO_ERROR;
+ TestData *testData = driver->createTestData(index, status);
+ if (U_SUCCESS(status)) {
+ name = testData->getName();
+ if (testData->getInfo(info, status)) {
+ log(info->getString("Description", status));
+ }
+ if (exec) {
+ log(name);
+ logln("---");
+ logln("");
+
+ processTest(testData);
+ }
+ delete testData;
+ } else {
+ name = "";
+ }
+ } else {
+ errln("format/DataDriven*Test data (calendar.res) not initialized!");
+ name = "";
+ }
+
+}
+
+void DataDrivenCalendarTest::testOps(TestData *testData,
+ const DataMap * /*settings*/) {
+ UErrorCode status = U_ZERO_ERROR;
+ const DataMap *currentCase= NULL;
+ char toCalLoc[256] = "";
+
+ // TODO: static strings?
+ const UnicodeString kADD("add", "");
+ const UnicodeString kROLL("roll", "");
+
+ // Get 'from' time
+ CalendarFieldsSet fromSet, toSet, paramsSet, diffSet;
+ SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"),
+ status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Couldn't create SimpleDateFormat: %s\n",
+ u_errorName(status));
+ return;
+ }
+ // Start the processing
+ int n = 0;
+ while (testData->nextCase(currentCase, status)) {
+ ++n;
+ Calendar *toCalendar= NULL;
+ Calendar *fromCalendar= NULL;
+
+ // load parameters
+ char theCase[200];
+ sprintf(theCase, "[case %d]", n);
+ UnicodeString caseString(theCase, "");
+ // build to calendar
+ // Headers { "locale","from","operation","params","to" }
+ // #1 locale
+ const char *param = "locale";
+ UnicodeString locale;
+ UnicodeString testSetting = currentCase->getString(param, status);
+ if (U_FAILURE(status)) {
+ errln(caseString+": Unable to get param '"+param+"' "
+ + UnicodeString(" - "));
+ continue;
+ }
+ testSetting.extract(0, testSetting.length(), toCalLoc, (const char*)0);
+ fromCalendar = Calendar::createInstance(toCalLoc, status);
+ if (U_FAILURE(status)) {
+ errln(caseString+": Unable to instantiate calendar for "
+ +testSetting);
+ continue;
+ }
+
+ fromSet.clear();
+ // #2 'from' info
+ param = "from";
+ UnicodeString from = testSetting=currentCase->getString(param, status);
+ if (U_FAILURE(status)) {
+ errln(caseString+": Unable to get parameter '"+param+"' "
+ + UnicodeString(" - "));
+ continue;
+ }
+ fromSet.parseFrom(testSetting, status);
+ if (U_FAILURE(status)) {
+ errln(caseString+": Failed to parse '"+param+"' parameter: "
+ +testSetting);
+ continue;
+ }
+
+ // #4 'operation' info
+ param = "operation";
+ UnicodeString operation = testSetting=currentCase->getString(param,
+ status);
+ if (U_FAILURE(status)) {
+ errln(caseString+": Unable to get parameter '"+param+"' "
+ + UnicodeString(" - "));
+ continue;
+ }
+ if (U_FAILURE(status)) {
+ errln(caseString+": Failed to parse '"+param+"' parameter: "
+ +testSetting);
+ continue;
+ }
+
+ paramsSet.clear();
+ // #3 'params' info
+ param = "params";
+ UnicodeString params = testSetting
+ =currentCase->getString(param, status);
+ if (U_FAILURE(status)) {
+ errln(caseString+": Unable to get parameter '"+param+"' "
+ + UnicodeString(" - "));
+ continue;
+ }
+ paramsSet.parseFrom(testSetting, status); // parse with inheritance.
+ if (U_FAILURE(status)) {
+ errln(caseString+": Failed to parse '"+param+"' parameter: "
+ +testSetting);
+ continue;
+ }
+
+ toSet.clear();
+ // #4 'to' info
+ param = "to";
+ UnicodeString to = testSetting=currentCase->getString(param, status);
+ if (U_FAILURE(status)) {
+ errln(caseString+": Unable to get parameter '"+param+"' "
+ + UnicodeString(" - "));
+ continue;
+ }
+ toSet.parseFrom(testSetting, &fromSet, status); // parse with inheritance.
+ if (U_FAILURE(status)) {
+ errln(caseString+": Failed to parse '"+param+"' parameter: "
+ +testSetting);
+ continue;
+ }
+
+ UnicodeString caseContentsString = locale+": from "+from+": "
+ +operation +" [[[ "+params+" ]]] >>> "+to;
+ logln(caseString+": "+caseContentsString);
+
+ // ------
+ // now, do it.
+
+ /// prepare calendar
+ fromSet.setOnCalendar(fromCalendar, status);
+ if (U_FAILURE(status)) {
+ errln(caseString+" FAIL: Failed to set on Source calendar: "
+ + u_errorName(status));
+ return;
+ }
+
+
+ diffSet.clear();
+ // Is the calendar sane after being set?
+ if (!fromSet.matches(fromCalendar, diffSet, status)) {
+ UnicodeString diffs = diffSet.diffFrom(fromSet, status);
+ errln((UnicodeString)"FAIL: "+caseString
+ +", SET SOURCE calendar was not set: Differences: "+ diffs
+ +"', status: "+ u_errorName(status));
+ } else if (U_FAILURE(status)) {
+ errln("FAIL: "+caseString+" SET SOURCE calendar Failed to match: "
+ +u_errorName(status));
+ } else {
+ logln("PASS: "+caseString+" SET SOURCE calendar match.");
+ }
+
+ // to calendar - copy of from calendar
+ toCalendar = fromCalendar->clone();
+
+ /// perform op
+ for (int q=0; q<UCAL_FIELD_COUNT; q++) {
+ if (paramsSet.isSet((UCalendarDateFields)q)) {
+ if (operation == kROLL) {
+ toCalendar->roll((UCalendarDateFields)q,
+ paramsSet.get((UCalendarDateFields)q), status);
+ } else if (operation == kADD) {
+ toCalendar->add((UCalendarDateFields)q,
+ paramsSet.get((UCalendarDateFields)q), status);
+ } else {
+ errln(caseString+ " FAIL: unknown operation "+ operation);
+ }
+ logln(operation + " of "+ paramsSet.get((UCalendarDateFields)q)
+ +" -> "+u_errorName(status));
+ }
+ }
+ if (U_FAILURE(status)) {
+ errln(caseString+" FAIL: after "+operation+" of "+params+" -> "
+ +u_errorName(status));
+ continue;
+ }
+
+ // now - what's the result?
+ diffSet.clear();
+
+ if (!toSet.matches(toCalendar, diffSet, status)) {
+ UnicodeString diffs = diffSet.diffFrom(toSet, status);
+ errln((UnicodeString)"FAIL: "+caseString+" - , "+caseContentsString
+ +" Differences: "+ diffs +"', status: "
+ + u_errorName(status));
+ } else if (U_FAILURE(status)) {
+ errln("FAIL: "+caseString+" Match operation had an error: "
+ +u_errorName(status));
+ } else {
+ logln("PASS: "+caseString+" matched!");
+ }
+
+ delete fromCalendar;
+ delete toCalendar;
+ }
+}
+
+void DataDrivenCalendarTest::testConvert(int32_t n,
+ const CalendarFieldsSet &fromSet, Calendar *fromCalendar,
+ const CalendarFieldsSet &toSet, Calendar *toCalendar, UBool forward) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString thisString = (UnicodeString)"#"+n+" "+(forward ? "forward"
+ : "reverse")+" "+fromCalendar->getType()+"->"+toCalendar->getType();
+
+ fromCalendar->clear();
+
+ fromSet.setOnCalendar(fromCalendar, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Failed to set on Source calendar: %s", u_errorName(status));
+ return;
+ }
+
+ CalendarFieldsSet diffSet;
+
+ diffSet.clear();
+ // Is the calendar sane at the first?
+ if (!fromSet.matches(fromCalendar, diffSet, status)) {
+ UnicodeString diffs = diffSet.diffFrom(fromSet, status);
+ errln((UnicodeString)"FAIL: "+thisString
+ +", SOURCE calendar was not set: Differences: "+ diffs
+ +"', status: "+ u_errorName(status));
+ } else if (U_FAILURE(status)) {
+ errln("FAIL: "+thisString+" SOURCE calendar Failed to match: "
+ +u_errorName(status));
+ } else {
+ logln("PASS: "+thisString+" SOURCE calendar match.");
+ }
+
+ //logln("Set Source calendar: " + from);
+
+ UDate fromTime = fromCalendar->getTime(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Failed to get Source time: %s", u_errorName(status));
+ return;
+ }
+
+ diffSet.clear();
+ // Is the calendar sane after being set?
+ if (!fromSet.matches(fromCalendar, diffSet, status)) {
+ UnicodeString diffs = diffSet.diffFrom(fromSet, status);
+ errln((UnicodeString)"FAIL: "+thisString
+ +", SET SOURCE calendar was not set: Differences: "+ diffs
+ +"', status: "+ u_errorName(status));
+ } else if (U_FAILURE(status)) {
+ errln("FAIL: "+thisString+" SET SOURCE calendar Failed to match: "
+ +u_errorName(status));
+ } else {
+ logln("PASS: "+thisString+" SET SOURCE calendar match.");
+ }
+
+ toCalendar->clear();
+ toCalendar->setTime(fromTime, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Failed to set Target time: %s", u_errorName(status));
+ return;
+ }
+
+ diffSet.clear();
+ if (!toSet.matches(toCalendar, diffSet, status)) {
+ UnicodeString diffs = diffSet.diffFrom(toSet, status);
+ errln((UnicodeString)"FAIL: "+thisString+", Differences: "+ diffs
+ +"', status: "+ u_errorName(status));
+ SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy G"), status);
+ UnicodeString fromString;
+ fmt.format(fromTime, fromString);
+ logln("Source Time: "+fromString+", Source Calendar: "
+ +fromCalendar->getType());
+ } else if (U_FAILURE(status)) {
+ errln("FAIL: "+thisString+" Failed to match: "+u_errorName(status));
+ } else {
+ logln("PASS: "+thisString+" match.");
+ }
+}
+
+void DataDrivenCalendarTest::testConvert(TestData *testData,
+ const DataMap *settings, UBool forward) {
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *toCalendar= NULL;
+ const DataMap *currentCase= NULL;
+ char toCalLoc[256] = "";
+ char fromCalLoc[256] = "";
+ // build to calendar
+ UnicodeString testSetting = settings->getString("ToCalendar", status);
+ if (U_SUCCESS(status)) {
+ testSetting.extract(0, testSetting.length(), toCalLoc, (const char*)0);
+ toCalendar = Calendar::createInstance(toCalLoc, status);
+ if (U_FAILURE(status)) {
+ errln("Unable to instantiate ToCalendar for "+testSetting);
+ return;
+ }
+ }
+
+ CalendarFieldsSet fromSet, toSet, diffSet;
+ SimpleDateFormat fmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"),
+ status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Couldn't create SimpleDateFormat: %s\n",
+ u_errorName(status));
+ return;
+ }
+ // Start the processing
+ int n = 0;
+ while (testData->nextCase(currentCase, status)) {
+ ++n;
+ Calendar *fromCalendar= NULL;
+ UnicodeString locale = currentCase->getString("locale", status);
+ if (U_SUCCESS(status)) {
+ locale.extract(0, locale.length(), fromCalLoc, (const char*)0); // default codepage. Invariant codepage doesn't have '@'!
+ fromCalendar = Calendar::createInstance(fromCalLoc, status);
+ if (U_FAILURE(status)) {
+ errln("Unable to instantiate fromCalendar for "+locale);
+ return;
+ }
+ } else {
+ errln("No 'locale' line.");
+ continue;
+ }
+
+ fromSet.clear();
+ toSet.clear();
+
+ UnicodeString from = currentCase->getString("from", status);
+ if (U_FAILURE(status)) {
+ errln("No 'from' line.");
+ continue;
+ }
+ fromSet.parseFrom(from, status);
+ if (U_FAILURE(status)) {
+ errln("Failed to parse 'from' parameter: "+from);
+ continue;
+ }
+ UnicodeString to = currentCase->getString("to", status);
+ if (U_FAILURE(status)) {
+ errln("No 'to' line.");
+ continue;
+ }
+ toSet.parseFrom(to, &fromSet, status);
+ if (U_FAILURE(status)) {
+ errln("Failed to parse 'to' parameter: "+to);
+ continue;
+ }
+
+ // now, do it.
+ if (forward) {
+ logln((UnicodeString)"#"+n+" "+locale+"/"+from+" >>> "+toCalLoc+"/"
+ +to);
+ testConvert(n, fromSet, fromCalendar, toSet, toCalendar, forward);
+ } else {
+ logln((UnicodeString)"#"+n+" "+locale+"/"+from+" <<< "+toCalLoc+"/"
+ +to);
+ testConvert(n, toSet, toCalendar, fromSet, fromCalendar, forward);
+ }
+
+ delete fromCalendar;
+ }
+ delete toCalendar;
+}
+
+void DataDrivenCalendarTest::processTest(TestData *testData) {
+ //Calendar *cal= NULL;
+ //const UChar *arguments= NULL;
+ //int32_t argLen = 0;
+ char testType[256];
+ const DataMap *settings= NULL;
+ //const UChar *type= NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString testSetting;
+ int n = 0;
+ while (testData->nextSettings(settings, status)) {
+ status = U_ZERO_ERROR;
+ // try to get a locale
+ testSetting = settings->getString("Type", status);
+ if (U_SUCCESS(status)) {
+ if ((++n)>0) {
+ logln("---");
+ }
+ logln(testSetting + "---");
+ testSetting.extract(0, testSetting.length(), testType, "");
+ } else {
+ errln("Unable to extract 'Type'. Skipping..");
+ continue;
+ }
+
+ if (!strcmp(testType, "convert_fwd")) {
+ testConvert(testData, settings, true);
+ } else if (!strcmp(testType, "convert_rev")) {
+ testConvert(testData, settings, false);
+ } else if (!strcmp(testType, "ops")) {
+ testOps(testData, settings);
+ } else {
+ errln("Unknown type: %s", testType);
+ }
+ }
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dadrcal.h b/Build/source/libs/icu/icu-xetex/test/intltest/dadrcal.h
new file mode 100644
index 00000000000..3d59494ccc7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dadrcal.h
@@ -0,0 +1,52 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * DataDrivenCalendarTest is a test class that uses data stored in resource
+ * bundles to perform testing. For more details on data structure, see
+ * source/test/testdata/calendar.txt
+ */
+
+#ifndef _INTLTESTDATADRIVENCALENDAR
+#define _INTLTESTDATADRIVENCALENDAR
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tsdate.h"
+#include "uvector.h"
+#include "unicode/calendar.h"
+#include "fldset.h"
+
+class TestDataModule;
+class TestData;
+class DataMap;
+class CalendarFieldsSet;
+
+class DataDrivenCalendarTest : public IntlTest {
+ void runIndexedTest(int32_t index, UBool exec, const char* &name,
+ char* par = NULL);
+public:
+ DataDrivenCalendarTest();
+ virtual ~DataDrivenCalendarTest();
+protected:
+
+ void DataDrivenTest(char *par);
+ void processTest(TestData *testData);
+private:
+ void testConvert(TestData *testData, const DataMap *settings, UBool fwd);
+ void testOps(TestData *testData, const DataMap *settings);
+ void testConvert(int32_t n, const CalendarFieldsSet &fromSet,
+ Calendar *fromCal, const CalendarFieldsSet &toSet, Calendar *toCal,
+ UBool fwd);
+private:
+ TestDataModule *driver;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dadrcoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/dadrcoll.cpp
new file mode 100644
index 00000000000..1b993840de0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dadrcoll.cpp
@@ -0,0 +1,290 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * IntlTestCollator is the medium level test class for everything in the directory "collate".
+ */
+
+/***********************************************************************
+* Modification history
+* Date Name Description
+* 02/14/2001 synwee Compare with cintltst and commented away tests
+* that are not run.
+***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uchar.h"
+#include "unicode/tstdtmod.h"
+#include "cstring.h"
+#include "ucol_tok.h"
+#include "tscoll.h"
+#include "dadrcoll.h"
+
+U_CDECL_BEGIN
+static void U_CALLCONV deleteSeqElement(void *elem) {
+ delete((SeqElement *)elem);
+}
+U_CDECL_END
+
+DataDrivenCollatorTest::DataDrivenCollatorTest()
+: seq(StringCharacterIterator("")),
+status(U_ZERO_ERROR),
+sequences(status)
+{
+ driver = TestDataModule::getTestDataModule("DataDrivenCollationTest", *this, status);
+ sequences.setDeleter(deleteSeqElement);
+ UCA = (RuleBasedCollator*)Collator::createInstance("root", status);
+}
+
+DataDrivenCollatorTest::~DataDrivenCollatorTest()
+{
+ delete driver;
+ delete UCA;
+}
+
+void DataDrivenCollatorTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par */)
+{
+ if(driver != NULL) {
+ if (exec)
+ {
+ logln("TestSuite Collator: ");
+ }
+ const DataMap *info = NULL;
+ TestData *testData = driver->createTestData(index, status);
+ if(U_SUCCESS(status)) {
+ name = testData->getName();
+ if(testData->getInfo(info, status)) {
+ log(info->getString("Description", status));
+ }
+ if(exec) {
+ log(name);
+ logln("---");
+ logln("");
+ processTest(testData);
+ }
+ delete testData;
+ } else {
+ name = "";
+ }
+ } else {
+ errln("collate/DataDrivenTest data not initialized!");
+ name = "";
+ }
+
+
+}
+
+UBool
+DataDrivenCollatorTest::setTestSequence(const UnicodeString &setSequence, SeqElement &el) {
+ seq.setText(setSequence);
+ return getNextInSequence(el);
+}
+
+// Parses the sequence to be tested
+UBool
+DataDrivenCollatorTest::getNextInSequence(SeqElement &el) {
+ el.source.truncate(0);
+ UBool quoted = FALSE;
+ UBool quotedsingle = FALSE;
+ UChar32 currChar = 0;
+
+ while(currChar != CharacterIterator::DONE) {
+ currChar= seq.next32PostInc();
+ if(!quoted) {
+ if(u_isWhitespace(currChar)) {
+ continue;
+ }
+ switch(currChar) {
+ case CharacterIterator::DONE:
+ break;
+ case 0x003C /* < */:
+ el.relation = Collator::LESS;
+ currChar = CharacterIterator::DONE;
+ break;
+ case 0x003D /* = */:
+ el.relation = Collator::EQUAL;
+ currChar = CharacterIterator::DONE;
+ break;
+ case 0x003E /* > */:
+ el.relation = Collator::GREATER;
+ currChar = CharacterIterator::DONE;
+ break;
+ case 0x0027 /* ' */: /* very basic quoting */
+ quoted = TRUE;
+ quotedsingle = FALSE;
+ break;
+ case 0x005c /* \ */: /* single quote */
+ quoted = TRUE;
+ quotedsingle = TRUE;
+ break;
+ default:
+ el.source.append(currChar);
+ }
+ } else {
+ if(currChar == CharacterIterator::DONE) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ errln("Quote in sequence not closed!");
+ return FALSE;
+ } else if(currChar == 0x0027) {
+ quoted = FALSE;
+ } else {
+ el.source.append(currChar);
+ }
+ if(quotedsingle) {
+ quoted = FALSE;
+ }
+ }
+ }
+ return seq.hasNext();
+}
+
+// Reads the options string and sets appropriate attributes in collator
+void
+DataDrivenCollatorTest::processArguments(Collator *col, const UChar *start, int32_t optLen) {
+ const UChar *end = start+optLen;
+ UColAttribute attrib;
+ UColAttributeValue value;
+
+ if(optLen == 0) {
+ return;
+ }
+
+ start = ucol_tok_getNextArgument(start, end, &attrib, &value, &status);
+ while(start != NULL) {
+ if(U_SUCCESS(status)) {
+ col->setAttribute(attrib, value, status);
+ }
+ start = ucol_tok_getNextArgument(start, end, &attrib, &value, &status);
+ }
+}
+
+void
+DataDrivenCollatorTest::processTest(TestData *testData) {
+ Collator *col = NULL;
+ const UChar *arguments = NULL;
+ int32_t argLen = 0;
+ const DataMap *settings = NULL;
+ const DataMap *currentCase = NULL;
+ UErrorCode intStatus = U_ZERO_ERROR;
+ UnicodeString testSetting;
+ while(testData->nextSettings(settings, status)) {
+ intStatus = U_ZERO_ERROR;
+ // try to get a locale
+ testSetting = settings->getString("TestLocale", intStatus);
+ if(U_SUCCESS(intStatus)) {
+ char localeName[256];
+ testSetting.extract(0, testSetting.length(), localeName, "");
+ col = Collator::createInstance(localeName, status);
+ if(U_SUCCESS(status)) {
+ logln("Testing collator for locale "+testSetting);
+ } else {
+ errln("Unable to instantiate collator for locale "+testSetting);
+ return;
+ }
+ } else {
+ // if no locale, try from rules
+ intStatus = U_ZERO_ERROR;
+ testSetting = settings->getString("Rules", intStatus);
+ if(U_SUCCESS(intStatus)) {
+ col = new RuleBasedCollator(testSetting, status);
+ if(U_SUCCESS(status)) {
+ logln("Testing collator for rules "+testSetting);
+ } else {
+ errln("Unable to instantiate collator for rules "+testSetting);
+ return;
+ }
+ } else {
+ errln("No collator definition!");
+ }
+ }
+
+ int32_t cloneSize = 0;
+ uint8_t* cloneBuf = NULL;
+ RuleBasedCollator* clone = NULL;
+ if(col != NULL){
+ RuleBasedCollator* rbc = (RuleBasedCollator*)col;
+ cloneSize = rbc->cloneBinary(NULL, 0, intStatus);
+ intStatus = U_ZERO_ERROR;
+ cloneBuf = (uint8_t*) malloc(cloneSize);
+ cloneSize = rbc->cloneBinary(cloneBuf, cloneSize, intStatus);
+ clone = new RuleBasedCollator(cloneBuf, cloneSize, UCA, intStatus);
+ if(U_FAILURE(intStatus)){
+ errln("Could not clone the RuleBasedCollator. Error: %s", u_errorName(intStatus));
+ intStatus= U_ZERO_ERROR;
+ }
+ // get attributes
+ testSetting = settings->getString("Arguments", intStatus);
+ if(U_SUCCESS(intStatus)) {
+ logln("Arguments: "+testSetting);
+ argLen = testSetting.length();
+ arguments = testSetting.getBuffer();
+ processArguments(col, arguments, argLen);
+ if(clone != NULL){
+ processArguments(clone, arguments, argLen);
+ }
+ if(U_FAILURE(status)) {
+ errln("Couldn't process arguments");
+ break;
+ }
+ } else {
+ intStatus = U_ZERO_ERROR;
+ }
+ // Start the processing
+ while(testData->nextCase(currentCase, status)) {
+ UnicodeString sequence = currentCase->getString("sequence", status);
+ if(U_SUCCESS(status)) {
+ processSequence(col, sequence);
+ if(clone != NULL){
+ processSequence(clone, sequence);
+ }
+ }
+ }
+ } else {
+ errln("Couldn't instantiate a collator!");
+ }
+ delete clone;
+ free(cloneBuf);
+ delete col;
+ col = NULL;
+ }
+}
+
+
+void
+DataDrivenCollatorTest::processSequence(Collator* col, const UnicodeString &sequence) {
+ Collator::EComparisonResult relation = Collator::EQUAL;
+ UBool hasNext;
+ SeqElement *source = NULL;
+ SeqElement *target = NULL;
+ int32_t j = 0;
+
+ sequences.removeAllElements();
+
+ target = new SeqElement();
+
+ setTestSequence(sequence, *target);
+ sequences.addElement(target, status);
+
+ do {
+ relation = Collator::EQUAL;
+ target = new SeqElement();
+ hasNext = getNextInSequence(*target);
+ for(j = sequences.size(); j > 0; j--) {
+ source = (SeqElement *)sequences.elementAt(j-1);
+ if(relation == Collator::EQUAL && source->relation != Collator::EQUAL) {
+ relation = source->relation;
+ }
+ doTest(col, source->source, target->source, relation);
+ }
+ sequences.addElement(target, status);
+ source = target;
+ } while(hasNext);
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dadrcoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/dadrcoll.h
new file mode 100644
index 00000000000..b76f40db8d1
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dadrcoll.h
@@ -0,0 +1,59 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * DataDrivenCollatorTest is a test class that uses data stored in resource
+ * bundles to perform testing. For more details on data structure, see
+ * source/test/testdata/DataDrivenCollationTest.txt
+ */
+
+#ifndef _INTLTESTDATADRIVENCOLLATOR
+#define _INTLTESTDATADRIVENCOLLATOR
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+#include "uvector.h"
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/sortkey.h"
+#include "unicode/schriter.h"
+
+class TestDataModule;
+class TestData;
+
+class SeqElement {
+public:
+ UnicodeString source;
+ Collator::EComparisonResult relation;
+};
+
+class DataDrivenCollatorTest: public IntlTestCollator {
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL );
+public:
+ DataDrivenCollatorTest();
+ virtual ~DataDrivenCollatorTest();
+protected:
+
+ void DataDrivenTest(char *par);
+ void processSequence(Collator* col, const UnicodeString &sequence);
+ void processTest(TestData *testData);
+ void processArguments(Collator *col, const UChar *start, int32_t optLen);
+ UBool setTestSequence(const UnicodeString &setSequence, SeqElement &el);
+ UBool getNextInSequence(SeqElement &el);
+private:
+ StringCharacterIterator seq;
+ TestDataModule *driver;
+ UErrorCode status;
+ UVector sequences;
+ RuleBasedCollator *UCA; // needed for opening collators from binary images
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dadrfmt.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/dadrfmt.cpp
new file mode 100644
index 00000000000..94a12e21e15
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dadrfmt.cpp
@@ -0,0 +1,318 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/***********************************************************************
+ * Modification history
+ * Date Name Description
+ * 07/09/2007 srl Copied from dadrcoll.cpp
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/tstdtmod.h"
+#include "tsdate.h"
+#include "dadrfmt.h"
+#include "unicode/calendar.h"
+#include "intltest.h"
+#include <string.h>
+#include "unicode/schriter.h"
+#include "unicode/regex.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/dbgutil.h"
+#include "fldset.h"
+
+
+#include <stdio.h>
+
+DataDrivenFormatTest::DataDrivenFormatTest() {
+ UErrorCode status = U_ZERO_ERROR;
+ driver = TestDataModule::getTestDataModule("format", *this, status);
+}
+
+DataDrivenFormatTest::~DataDrivenFormatTest() {
+ delete driver;
+}
+
+void DataDrivenFormatTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par */) {
+ if (driver != NULL) {
+ if (exec) {
+ // logln("Begin ");
+ }
+ const DataMap *info= NULL;
+ UErrorCode status= U_ZERO_ERROR;
+ TestData *testData = driver->createTestData(index, status);
+ if (U_SUCCESS(status)) {
+ name = testData->getName();
+ if (testData->getInfo(info, status)) {
+ log(info->getString("Description", status));
+ }
+ if (exec) {
+ log(name);
+ logln("---");
+ logln("");
+
+ processTest(testData);
+ }
+ delete testData;
+ } else {
+ name = "";
+ }
+ } else {
+ errln("format/DataDriven*Test data (format.res) not initialized!");
+ name = "";
+ }
+
+}
+
+
+
+/*
+ * Headers { "locale","spec", "date", "str"}
+ // locale: locale including calendar type
+ // spec: either 'PATTERN=y mm h' etc, or 'DATE=SHORT,TIME=LONG'
+ // date: either an unsigned long (millis), or a calendar spec ERA=0,YEAR=1, etc.. applied to the calendar type specified by the locale
+ // str: the expected unicode string
+ Cases {
+ {
+ "en_US@calendar=gregorian",
+ "DATE=SHORT,TIME=SHORT",
+ "ERA=1,YEAR=2007,MONTH=AUGUST,DATE=8,HOUR=18,MINUTE=54,SECOND=12",
+ "8/8/2007 6:54pm"
+ },
+ * */
+
+
+void DataDrivenFormatTest::testConvertDate(TestData *testData,
+ const DataMap * /* settings */, UBool fmt) {
+ UnicodeString kPATTERN("PATTERN="); // TODO: static
+ UnicodeString kMILLIS("MILLIS="); // TODO: static
+ UnicodeString kRELATIVE_MILLIS("RELATIVE_MILLIS="); // TODO: static
+
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat basicFmt(UnicodeString("EEE MMM dd yyyy / YYYY'-W'ww-ee"),
+ status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Couldn't create basic SimpleDateFormat: %s\n",
+ u_errorName(status));
+ return;
+ }
+
+ const DataMap *currentCase= NULL;
+ // Start the processing
+ int n = 0;
+ while (testData->nextCase(currentCase, status)) {
+ char calLoc[256] = "";
+ DateTimeStyleSet styleSet;
+ UnicodeString pattern;
+ UBool usePattern = FALSE;
+ CalendarFieldsSet fromSet;
+ UDate fromDate = 0;
+ UBool useDate = FALSE;
+
+ UDate now = Calendar::getNow();
+
+ ++n;
+
+ char theCase[200];
+ sprintf(theCase, "case %d:", n);
+ UnicodeString caseString(theCase, "");
+
+ // load params
+ UnicodeString locale = currentCase->getString("locale", status);
+ if (U_FAILURE(status)) {
+ errln("case %d: No 'locale' line.", n);
+ continue;
+ }
+ UnicodeString spec = currentCase->getString("spec", status);
+ if(U_FAILURE(status)) {
+ errln("case %d: No 'spec' line.", n);
+ continue;
+ }
+ UnicodeString date = currentCase->getString("date", status);
+ if(U_FAILURE(status)) {
+ errln("case %d: No 'date' line.", n);
+ continue;
+ }
+ UnicodeString expectStr= currentCase->getString("str", status);
+ if(U_FAILURE(status)) {
+ errln("case %d: No 'str' line.", n);
+ continue;
+ }
+
+ DateFormat *format = NULL;
+
+ // Process: 'locale'
+ locale.extract(0, locale.length(), calLoc, (const char*)0); // default codepage. Invariant codepage doesn't have '@'!
+ Locale loc(calLoc);
+ if(spec.startsWith(kPATTERN)) {
+ pattern = UnicodeString(spec,kPATTERN.length());
+ usePattern = TRUE;
+ format = new SimpleDateFormat(pattern, loc, status);
+ if(U_FAILURE(status)) {
+ errln("case %d: could not create SimpleDateFormat from pattern: %s", n, u_errorName(status));
+ continue;
+ }
+ } else {
+ if(styleSet.parseFrom(spec, status)<0 || U_FAILURE(status)) {
+ errln("case %d: could not parse spec as style fields: %s", n, u_errorName(status));
+ continue;
+ }
+ format = DateFormat::createDateTimeInstance((DateFormat::EStyle)styleSet.getDateStyle(), (DateFormat::EStyle)styleSet.getTimeStyle(), loc);
+ if(format == NULL ) {
+ errln("case %d: could not create SimpleDateFormat from styles.", n);
+ continue;
+ }
+ }
+
+ // parse 'date'
+ if(date.startsWith(kMILLIS)) {
+ UnicodeString millis = UnicodeString(date, kMILLIS.length());
+ useDate = TRUE;
+ fromDate = udbg_stoi(millis);
+ } else if(date.startsWith(kRELATIVE_MILLIS)) {
+ UnicodeString millis = UnicodeString(date, kRELATIVE_MILLIS.length());
+ useDate = TRUE;
+ fromDate = udbg_stoi(millis) + now;
+ } else if(fromSet.parseFrom(date, status)<0 || U_FAILURE(status)) {
+ errln("case %d: could not parse date as calendar fields: %s", n, u_errorName(status));
+ continue;
+ }
+
+ Calendar *cal = Calendar::createInstance(loc, status);
+ if(U_FAILURE(status)) {
+ errln("case %d: could not create calendar from %s", n, calLoc);
+ }
+ // now, do it.
+ if (fmt) {
+ FieldPosition pos;
+// logln((UnicodeString)"#"+n+" "+locale+"/"+from+" >>> "+toCalLoc+"/"
+// +to);
+ cal->clear();
+ UnicodeString output;
+ output.remove();
+
+ if(useDate) {
+// cal->setTime(fromDate, status);
+// if(U_FAILURE(status)) {
+// errln("case %d: could not set time on calendar: %s", n, u_errorName(status));
+// continue;
+// }
+ format->format(fromDate, output, pos, status);
+ } else {
+ fromSet.setOnCalendar(cal, status);
+ if(U_FAILURE(status)) {
+ errln("case %d: could not set fields on calendar: %s", n, u_errorName(status));
+ continue;
+ }
+ format->format(*cal, output, pos);
+ }
+
+ // check erro result from 'format'
+ if(U_FAILURE(status)) {
+ errln("case %d: could not format(): %s", n, u_errorName(status)); // TODO: use 'pos'
+ }
+// if(pos.getBeginIndex()==0 && pos.getEndIndex()==0) { // TODO: more precise error?
+// errln("WARNING: case %d: format's pos returned (0,0) - error ??", n);
+// }
+
+ if(output == expectStr) {
+ logln(caseString+": format: SUCCESS! "+UnicodeString("expect=output=")+output);
+ } else {
+ UnicodeString result;
+ UnicodeString result2;
+ errln(caseString+": format: output!=expectStr, got " + *udbg_escape(output, &result) + " expected " + *udbg_escape(expectStr, &result2));
+ }
+ } else {
+ cal->clear();
+ ParsePosition pos;
+ format->parse(expectStr,*cal,pos);
+ if(useDate) {
+ UDate gotDate = cal->getTime(status);
+ if(U_FAILURE(status)) {
+ errln(caseString+": parse: could not get time on calendar: "+UnicodeString(u_errorName(status)));
+ continue;
+ }
+ if(gotDate == fromDate) {
+ logln(caseString+": parse: SUCCESS! "+UnicodeString("gotDate=parseDate=")+expectStr);
+ } else {
+ UnicodeString expectDateStr, gotDateStr;
+ basicFmt.format(fromDate,expectDateStr);
+ basicFmt.format(gotDate,gotDateStr);
+ errln(caseString+": parse: FAIL. parsed '"+expectStr+"' and got "+gotDateStr+", expected " + expectDateStr);
+ }
+ } else {
+// Calendar *cal2 = cal->clone();
+// cal2->clear();
+// fromSet.setOnCalendar(cal2, status);
+ if(U_FAILURE(status)) {
+ errln("case %d: parse: could not set fields on calendar: %s", n, u_errorName(status));
+ continue;
+ }
+
+ CalendarFieldsSet diffSet;
+// diffSet.clear();
+ if (!fromSet.matches(cal, diffSet, status)) {
+ UnicodeString diffs = diffSet.diffFrom(fromSet, status);
+ errln((UnicodeString)"FAIL: "+caseString
+ +", Differences: '"+ diffs
+ +"', status: "+ u_errorName(status));
+ } else if (U_FAILURE(status)) {
+ errln("FAIL: "+caseString+" parse SET SOURCE calendar Failed to match: "
+ +u_errorName(status));
+ } else {
+ logln("PASS: "+caseString+" parse.");
+ }
+
+
+
+ }
+ }
+ delete cal;
+ delete format;
+
+ }
+// delete basicFmt;
+}
+
+void DataDrivenFormatTest::processTest(TestData *testData) {
+ //Format *cal= NULL;
+ //const UChar *arguments= NULL;
+ //int32_t argLen = 0;
+ char testType[256];
+ const DataMap *settings= NULL;
+ //const UChar *type= NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString testSetting;
+ int n = 0;
+ while (testData->nextSettings(settings, status)) {
+ status = U_ZERO_ERROR;
+ // try to get a locale
+ testSetting = settings->getString("Type", status);
+ if (U_SUCCESS(status)) {
+ if ((++n)>0) {
+ logln("---");
+ }
+ logln(testSetting + "---");
+ testSetting.extract(0, testSetting.length(), testType, "");
+ } else {
+ errln("Unable to extract 'Type'. Skipping..");
+ continue;
+ }
+
+ if (!strcmp(testType, "date_format")) {
+ testConvertDate(testData, settings, true);
+ } else if (!strcmp(testType, "date_parse")) {
+ testConvertDate(testData, settings, false);
+ } else {
+ errln("Unknown type: %s", testType);
+ }
+ }
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dadrfmt.h b/Build/source/libs/icu/icu-xetex/test/intltest/dadrfmt.h
new file mode 100644
index 00000000000..77f098bbe56
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dadrfmt.h
@@ -0,0 +1,52 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * DataDrivenFormatTest is a test class that uses data stored in resource
+ * bundles to perform testing. For more details on data structure, see
+ * source/test/testdata/calendar.txt
+ */
+
+#ifndef _INTLTESTDATADRIVENFORMAT
+#define _INTLTESTDATADRIVENFORMAT
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tsdate.h"
+#include "uvector.h"
+#include "unicode/format.h"
+//#include "fldset.h"
+
+class TestDataModule;
+class TestData;
+class DataMap;
+//class DateTimeStyle;
+
+class DataDrivenFormatTest : public IntlTest {
+ void runIndexedTest(int32_t index, UBool exec, const char* &name,
+ char* par = NULL);
+public:
+ DataDrivenFormatTest();
+ virtual ~DataDrivenFormatTest();
+protected:
+
+ void DataDrivenTest(char *par);
+ void processTest(TestData *testData);
+private:
+ void testConvertDate(TestData *testData, const DataMap *settings, UBool fmt);
+// void testOps(TestData *testData, const DataMap *settings);
+// void testConvert(int32_t n, const FormatFieldsSet &fromSet,
+// Format *fromCal, const FormatFieldsSet &toSet, Format *toCal,
+// UBool fwd);
+private:
+ TestDataModule *driver;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dcfmapts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/dcfmapts.cpp
new file mode 100644
index 00000000000..792385da664
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dcfmapts.cpp
@@ -0,0 +1,419 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "dcfmapts.h"
+
+#include "unicode/decimfmt.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/parseerr.h"
+
+// This is an API test, not a unit test. It doesn't test very many cases, and doesn't
+// try to test the full functionality. It just calls each function in the class and
+// verifies that it works on a basic level.
+
+void IntlTestDecimalFormatAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln((UnicodeString)"TestSuite DecimalFormatAPI");
+ switch (index) {
+ case 0: name = "DecimalFormat API test";
+ if (exec) {
+ logln((UnicodeString)"DecimalFormat API test---"); logln((UnicodeString)"");
+ UErrorCode status = U_ZERO_ERROR;
+ Locale saveLocale;
+ Locale::setDefault(Locale::getEnglish(), status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: Could not set default locale, test may not give correct results");
+ }
+ testAPI(/*par*/);
+ Locale::setDefault(saveLocale, status);
+ }
+ break;
+ case 1: name = "Rounding test";
+ if(exec) {
+ logln((UnicodeString)"DecimalFormat Rounding test---");
+ testRounding(/*par*/);
+ }
+ break;
+
+ default: name = ""; break;
+ }
+}
+
+/**
+ * This test checks various generic API methods in DecimalFormat to achieve 100%
+ * API coverage.
+ */
+void IntlTestDecimalFormatAPI::testAPI(/*char *par*/)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+// ======= Test constructors
+
+ logln((UnicodeString)"Testing DecimalFormat constructors");
+
+ DecimalFormat def(status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: Could not create DecimalFormat (default)");
+ return;
+ }
+
+ status = U_ZERO_ERROR;
+ const UnicodeString pattern("#,##0.# FF");
+ DecimalFormat pat(pattern, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: Could not create DecimalFormat (pattern)");
+ return;
+ }
+
+ status = U_ZERO_ERROR;
+ DecimalFormatSymbols *symbols = new DecimalFormatSymbols(Locale::getFrench(), status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: Could not create DecimalFormatSymbols (French)");
+ return;
+ }
+
+ status = U_ZERO_ERROR;
+ DecimalFormat cust1(pattern, symbols, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: Could not create DecimalFormat (pattern, symbols*)");
+ }
+
+ status = U_ZERO_ERROR;
+ DecimalFormat cust2(pattern, *symbols, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: Could not create DecimalFormat (pattern, symbols)");
+ }
+
+ DecimalFormat copy(pat);
+
+// ======= Test clone(), assignment, and equality
+
+ logln((UnicodeString)"Testing clone(), assignment and equality operators");
+
+ if( ! (copy == pat) || copy != pat) {
+ errln((UnicodeString)"ERROR: Copy constructor or == failed");
+ }
+
+ copy = cust1;
+ if(copy != cust1) {
+ errln((UnicodeString)"ERROR: Assignment (or !=) failed");
+ }
+
+ Format *clone = def.clone();
+ if( ! (*clone == def) ) {
+ errln((UnicodeString)"ERROR: Clone() failed");
+ }
+ delete clone;
+
+// ======= Test various format() methods
+
+ logln((UnicodeString)"Testing various format() methods");
+
+ double d = -10456.0037;
+ int32_t l = 100000000;
+ Formattable fD(d);
+ Formattable fL(l);
+
+ UnicodeString res1, res2, res3, res4;
+ FieldPosition pos1(0), pos2(0), pos3(0), pos4(0);
+
+ res1 = def.format(d, res1, pos1);
+ logln( (UnicodeString) "" + (int32_t) d + " formatted to " + res1);
+
+ res2 = pat.format(l, res2, pos2);
+ logln((UnicodeString) "" + (int32_t) l + " formatted to " + res2);
+
+ status = U_ZERO_ERROR;
+ res3 = cust1.format(fD, res3, pos3, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: format(Formattable [double]) failed");
+ }
+ logln((UnicodeString) "" + (int32_t) fD.getDouble() + " formatted to " + res3);
+
+ status = U_ZERO_ERROR;
+ res4 = cust2.format(fL, res4, pos4, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: format(Formattable [long]) failed");
+ }
+ logln((UnicodeString) "" + fL.getLong() + " formatted to " + res4);
+
+// ======= Test parse()
+
+ logln((UnicodeString)"Testing parse()");
+
+ UnicodeString text("-10,456.0037");
+ Formattable result1, result2;
+ ParsePosition pos(0);
+ UnicodeString patt("#,##0.#");
+ status = U_ZERO_ERROR;
+ pat.applyPattern(patt, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: applyPattern() failed");
+ }
+ pat.parse(text, result1, pos);
+ if(result1.getType() != Formattable::kDouble && result1.getDouble() != d) {
+ errln((UnicodeString)"ERROR: Roundtrip failed (via parse()) for " + text);
+ }
+ logln(text + " parsed into " + (int32_t) result1.getDouble());
+
+ status = U_ZERO_ERROR;
+ pat.parse(text, result2, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: parse() failed");
+ }
+ if(result2.getType() != Formattable::kDouble && result2.getDouble() != d) {
+ errln((UnicodeString)"ERROR: Roundtrip failed (via parse()) for " + text);
+ }
+ logln(text + " parsed into " + (int32_t) result2.getDouble());
+
+// ======= Test getters and setters
+
+ logln((UnicodeString)"Testing getters and setters");
+
+ const DecimalFormatSymbols *syms = pat.getDecimalFormatSymbols();
+ DecimalFormatSymbols *newSyms = new DecimalFormatSymbols(*syms);
+ def.setDecimalFormatSymbols(*newSyms);
+ def.adoptDecimalFormatSymbols(newSyms); // don't use newSyms after this
+ if( *(pat.getDecimalFormatSymbols()) != *(def.getDecimalFormatSymbols())) {
+ errln((UnicodeString)"ERROR: adopt or set DecimalFormatSymbols() failed");
+ }
+
+ UnicodeString posPrefix;
+ pat.setPositivePrefix("+");
+ posPrefix = pat.getPositivePrefix(posPrefix);
+ logln((UnicodeString)"Positive prefix (should be +): " + posPrefix);
+ if(posPrefix != "+") {
+ errln((UnicodeString)"ERROR: setPositivePrefix() failed");
+ }
+
+ UnicodeString negPrefix;
+ pat.setNegativePrefix("-");
+ negPrefix = pat.getNegativePrefix(negPrefix);
+ logln((UnicodeString)"Negative prefix (should be -): " + negPrefix);
+ if(negPrefix != "-") {
+ errln((UnicodeString)"ERROR: setNegativePrefix() failed");
+ }
+
+ UnicodeString posSuffix;
+ pat.setPositiveSuffix("_");
+ posSuffix = pat.getPositiveSuffix(posSuffix);
+ logln((UnicodeString)"Positive suffix (should be _): " + posSuffix);
+ if(posSuffix != "_") {
+ errln((UnicodeString)"ERROR: setPositiveSuffix() failed");
+ }
+
+ UnicodeString negSuffix;
+ pat.setNegativeSuffix("~");
+ negSuffix = pat.getNegativeSuffix(negSuffix);
+ logln((UnicodeString)"Negative suffix (should be ~): " + negSuffix);
+ if(negSuffix != "~") {
+ errln((UnicodeString)"ERROR: setNegativeSuffix() failed");
+ }
+
+ int32_t multiplier = 0;
+ pat.setMultiplier(8);
+ multiplier = pat.getMultiplier();
+ logln((UnicodeString)"Multiplier (should be 8): " + multiplier);
+ if(multiplier != 8) {
+ errln((UnicodeString)"ERROR: setMultiplier() failed");
+ }
+
+ int32_t groupingSize = 0;
+ pat.setGroupingSize(2);
+ groupingSize = pat.getGroupingSize();
+ logln((UnicodeString)"Grouping size (should be 2): " + (int32_t) groupingSize);
+ if(groupingSize != 2) {
+ errln((UnicodeString)"ERROR: setGroupingSize() failed");
+ }
+
+ pat.setDecimalSeparatorAlwaysShown(TRUE);
+ UBool tf = pat.isDecimalSeparatorAlwaysShown();
+ logln((UnicodeString)"DecimalSeparatorIsAlwaysShown (should be TRUE) is " + (UnicodeString) (tf ? "TRUE" : "FALSE"));
+ if(tf != TRUE) {
+ errln((UnicodeString)"ERROR: setDecimalSeparatorAlwaysShown() failed");
+ }
+ // Added by Ken Liu testing set/isExponentSignAlwaysShown
+ pat.setExponentSignAlwaysShown(TRUE);
+ UBool esas = pat.isExponentSignAlwaysShown();
+ logln((UnicodeString)"ExponentSignAlwaysShown (should be TRUE) is " + (UnicodeString) (esas ? "TRUE" : "FALSE"));
+ if(esas != TRUE) {
+ errln((UnicodeString)"ERROR: ExponentSignAlwaysShown() failed");
+ }
+
+ // Added by Ken Liu testing set/isScientificNotation
+ pat.setScientificNotation(TRUE);
+ UBool sn = pat.isScientificNotation();
+ logln((UnicodeString)"isScientificNotation (should be TRUE) is " + (UnicodeString) (sn ? "TRUE" : "FALSE"));
+ if(sn != TRUE) {
+ errln((UnicodeString)"ERROR: setScientificNotation() failed");
+ }
+
+ // Added by Ken Liu testing set/getMinimumExponentDigits
+ int8_t MinimumExponentDigits = 0;
+ pat.setMinimumExponentDigits(2);
+ MinimumExponentDigits = pat.getMinimumExponentDigits();
+ logln((UnicodeString)"MinimumExponentDigits (should be 2) is " + (int8_t) MinimumExponentDigits);
+ if(MinimumExponentDigits != 2) {
+ errln((UnicodeString)"ERROR: setMinimumExponentDigits() failed");
+ }
+
+ // Added by Ken Liu testing set/getRoundingIncrement
+ double RoundingIncrement = 0.0;
+ pat.setRoundingIncrement(2.0);
+ RoundingIncrement = pat.getRoundingIncrement();
+ logln((UnicodeString)"RoundingIncrement (should be 2.0) is " + (double) RoundingIncrement);
+ if(RoundingIncrement != 2.0) {
+ errln((UnicodeString)"ERROR: setRoundingIncrement() failed");
+ }
+ //end of Ken's Adding
+
+ UnicodeString funkyPat;
+ funkyPat = pat.toPattern(funkyPat);
+ logln((UnicodeString)"Pattern is " + funkyPat);
+
+ UnicodeString locPat;
+ locPat = pat.toLocalizedPattern(locPat);
+ logln((UnicodeString)"Localized pattern is " + locPat);
+
+// ======= Test applyPattern()
+
+ logln((UnicodeString)"Testing applyPattern()");
+
+ UnicodeString p1("#,##0.0#;(#,##0.0#)");
+ logln((UnicodeString)"Applying pattern " + p1);
+ status = U_ZERO_ERROR;
+ pat.applyPattern(p1, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: applyPattern() failed with " + (int32_t) status);
+ }
+ UnicodeString s2;
+ s2 = pat.toPattern(s2);
+ logln((UnicodeString)"Extracted pattern is " + s2);
+ if(s2 != p1) {
+ errln((UnicodeString)"ERROR: toPattern() result did not match pattern applied");
+ }
+
+ if(pat.getSecondaryGroupingSize() != 0) {
+ errln("FAIL: Secondary Grouping Size should be 0, not %d\n", pat.getSecondaryGroupingSize());
+ }
+
+ if(pat.getGroupingSize() != 3) {
+ errln("FAIL: Primary Grouping Size should be 3, not %d\n", pat.getGroupingSize());
+ }
+
+ UnicodeString p2("#,##,##0.0# FF;(#,##,##0.0# FF)");
+ logln((UnicodeString)"Applying pattern " + p2);
+ status = U_ZERO_ERROR;
+ pat.applyLocalizedPattern(p2, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: applyPattern() failed with " + (int32_t) status);
+ }
+ UnicodeString s3;
+ s3 = pat.toLocalizedPattern(s3);
+ logln((UnicodeString)"Extracted pattern is " + s3);
+ if(s3 != p2) {
+ errln((UnicodeString)"ERROR: toLocalizedPattern() result did not match pattern applied");
+ }
+
+ status = U_ZERO_ERROR;
+ UParseError pe;
+ pat.applyLocalizedPattern(p2, pe, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: applyPattern((with ParseError)) failed with " + (int32_t) status);
+ }
+ UnicodeString s4;
+ s4 = pat.toLocalizedPattern(s3);
+ logln((UnicodeString)"Extracted pattern is " + s4);
+ if(s4 != p2) {
+ errln((UnicodeString)"ERROR: toLocalizedPattern(with ParseErr) result did not match pattern applied");
+ }
+
+ if(pat.getSecondaryGroupingSize() != 2) {
+ errln("FAIL: Secondary Grouping Size should be 2, not %d\n", pat.getSecondaryGroupingSize());
+ }
+
+ if(pat.getGroupingSize() != 3) {
+ errln("FAIL: Primary Grouping Size should be 3, not %d\n", pat.getGroupingSize());
+ }
+
+// ======= Test getStaticClassID()
+
+ logln((UnicodeString)"Testing getStaticClassID()");
+
+ status = U_ZERO_ERROR;
+ NumberFormat *test = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: Couldn't create a DecimalFormat");
+ }
+
+ if(test->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ errln((UnicodeString)"ERROR: getDynamicClassID() didn't return the expected value");
+ }
+
+ delete test;
+}
+
+void IntlTestDecimalFormatAPI::testRounding(/*char *par*/)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ double Roundingnumber = 2.55;
+ double Roundingnumber1 = -2.55;
+ //+2.55 results -2.55 results
+ double result[]={ 3.0, -2.0, // kRoundCeiling 0,
+ 2.0, -3.0, // kRoundFloor 1,
+ 2.0, -2.0, // kRoundDown 2,
+ 3.0, -3.0, // kRoundUp 3,
+ 3.0, -3.0, // kRoundHalfEven 4,
+ 3.0, -3.0, // kRoundHalfDown 5,
+ 3.0, -3.0 // kRoundHalfUp 6
+ };
+ DecimalFormat pat(status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: Could not create DecimalFormat (default)");
+ return;
+ }
+ uint16_t mode;
+ uint16_t i=0;
+ UnicodeString message;
+ UnicodeString resultStr;
+ for(mode=0;mode < 7;mode++){
+ pat.setRoundingMode((DecimalFormat::ERoundingMode)mode);
+ if(pat.getRoundingMode() != (DecimalFormat::ERoundingMode)mode){
+ errln((UnicodeString)"SetRoundingMode or GetRoundingMode failed for mode=" + mode);
+ }
+
+
+ //for +2.55 with RoundingIncrement=1.0
+ pat.setRoundingIncrement(1.0);
+ pat.format(Roundingnumber, resultStr);
+ message= (UnicodeString)"round(" + (double)Roundingnumber + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
+ verify(message, resultStr, result[i++]);
+ message.remove();
+ resultStr.remove();
+
+ //for -2.55 with RoundingIncrement=1.0
+ pat.format(Roundingnumber1, resultStr);
+ message= (UnicodeString)"round(" + (double)Roundingnumber1 + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
+ verify(message, resultStr, result[i++]);
+ message.remove();
+ resultStr.remove();
+ }
+
+}
+void IntlTestDecimalFormatAPI::verify(const UnicodeString& message, const UnicodeString& got, double expected){
+ logln((UnicodeString)message + got + (UnicodeString)" Expected : " + expected);
+ UnicodeString expectedStr("");
+ expectedStr=expectedStr + expected;
+ if(got != expectedStr ) {
+ errln((UnicodeString)"ERROR: Round() failed: " + message + got + (UnicodeString)" Expected : " + expectedStr);
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dcfmapts.h b/Build/source/libs/icu/icu-xetex/test/intltest/dcfmapts.h
new file mode 100644
index 00000000000..841b7942d98
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dcfmapts.h
@@ -0,0 +1,35 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#ifndef _INTLTESTDECIMALFORMATAPI
+#define _INTLTESTDECIMALFORMATAPI
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "intltest.h"
+
+
+class IntlTestDecimalFormatAPI: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+public:
+ /**
+ * Tests basic functionality of various API functions for DecimalFormat
+ **/
+ void testAPI(/*char *par*/);
+ void testRounding(/*char *par*/);
+private:
+ /*Helper functions */
+ void verify(const UnicodeString& message, const UnicodeString& got, double expected);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/decoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/decoll.cpp
new file mode 100644
index 00000000000..0b84d2576aa
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/decoll.cpp
@@ -0,0 +1,146 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "decoll.h"
+
+#ifndef _COLL
+#include "unicode/coll.h"
+#endif
+
+#ifndef _TBLCOLL
+#include "unicode/tblcoll.h"
+#endif
+
+#ifndef _UNISTR
+#include "unicode/unistr.h"
+#endif
+
+#ifndef _SORTKEY
+#include "unicode/sortkey.h"
+#endif
+
+#ifndef _DECOLL
+#include "decoll.h"
+#endif
+
+#include "sfwdchit.h"
+
+CollationGermanTest::CollationGermanTest()
+: myCollation(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation = Collator::createInstance(Locale::getGermany(), status);
+ if(!myCollation || U_FAILURE(status)) {
+ errln(__FILE__ "failed to create! err " + UnicodeString(u_errorName(status)));
+ /* if it wasn't already: */
+ delete myCollation;
+ myCollation = NULL;
+ }
+}
+
+CollationGermanTest::~CollationGermanTest()
+{
+ delete myCollation;
+}
+
+const UChar CollationGermanTest::testSourceCases[][CollationGermanTest::MAX_TOKEN_LEN] =
+{
+ {0x47, 0x72, 0x00F6, 0x00DF, 0x65, 0},
+ {0x61, 0x62, 0x63, 0},
+ {0x54, 0x00F6, 0x6e, 0x65, 0},
+ {0x54, 0x00F6, 0x6e, 0x65, 0},
+ {0x54, 0x00F6, 0x6e, 0x65, 0},
+ {0x61, 0x0308, 0x62, 0x63, 0},
+ {0x00E4, 0x62, 0x63, 0},
+ {0x00E4, 0x62, 0x63, 0},
+ {0x53, 0x74, 0x72, 0x61, 0x00DF, 0x65, 0},
+ {0x65, 0x66, 0x67, 0},
+ {0x00E4, 0x62, 0x63, 0},
+ {0x53, 0x74, 0x72, 0x61, 0x00DF, 0x65, 0}
+};
+
+const UChar CollationGermanTest::testTargetCases[][CollationGermanTest::MAX_TOKEN_LEN] =
+{
+ {0x47, 0x72, 0x6f, 0x73, 0x73, 0x69, 0x73, 0x74, 0},
+ {0x61, 0x0308, 0x62, 0x63, 0},
+ {0x54, 0x6f, 0x6e, 0},
+ {0x54, 0x6f, 0x64, 0},
+ {0x54, 0x6f, 0x66, 0x75, 0},
+ {0x41, 0x0308, 0x62, 0x63, 0},
+ {0x61, 0x0308, 0x62, 0x63, 0},
+ {0x61, 0x65, 0x62, 0x63, 0},
+ {0x53, 0x74, 0x72, 0x61, 0x73, 0x73, 0x65, 0},
+ {0x65, 0x66, 0x67, 0},
+ {0x61, 0x65, 0x62, 0x63, 0},
+ {0x53, 0x74, 0x72, 0x61, 0x73, 0x73, 0x65, 0}
+};
+
+const Collator::EComparisonResult CollationGermanTest::results[][2] =
+{
+ // Primary Tertiary
+ { Collator::LESS, Collator::LESS },
+ { Collator::EQUAL, Collator::LESS },
+ { Collator::GREATER, Collator::GREATER },
+ { Collator::GREATER, Collator::GREATER },
+ { Collator::GREATER, Collator::GREATER },
+ { Collator::EQUAL, Collator::LESS },
+ { Collator::EQUAL, Collator::EQUAL },
+ { Collator::LESS, Collator::LESS },
+ { Collator::EQUAL, Collator::GREATER },
+ { Collator::EQUAL, Collator::EQUAL },
+ { Collator::LESS, Collator::LESS },
+ { Collator::EQUAL, Collator::GREATER }
+};
+
+
+void CollationGermanTest::TestTertiary(/* char* par */)
+{
+ if(myCollation == NULL ) {
+ errln("decoll: cannot start test, collator is null\n");
+ return;
+ }
+
+ int32_t i = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation->setStrength(Collator::TERTIARY);
+ myCollation->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ for (i = 0; i < 12 ; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i][1]);
+ }
+}
+void CollationGermanTest::TestPrimary(/* char* par */)
+{
+ if(myCollation == NULL ) {
+ errln("decoll: cannot start test, collator is null\n");
+ return;
+ }
+ int32_t i;
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation->setStrength(Collator::PRIMARY);
+ myCollation->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ for (i = 0; i < 12 ; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i][0]);
+ }
+}
+
+void CollationGermanTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CollationGermanTest: ");
+ switch (index)
+ {
+ case 0: name = "TestPrimary"; if (exec) TestPrimary(/* par */); break;
+ case 1: name = "TestTertiary"; if (exec) TestTertiary(/* par */); break;
+ default: name = ""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/decoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/decoll.h
new file mode 100644
index 00000000000..19513e1bf4f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/decoll.h
@@ -0,0 +1,50 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * CollationGermanTest is a third level test class. This tests the locale
+ * specific primary, secondary and tertiary rules. For example, o-umlaut
+ * is sorted with expanding char e.
+ */
+#ifndef _DECOLL
+#define _DECOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class CollationGermanTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationGermanTest();
+ virtual ~CollationGermanTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // perform test with strength PRIMARY
+ void TestPrimary(/* char* par */);
+
+ // perform test with strength SECONDARY
+ void TestSecondary(/* char* par */);
+
+ // perform tests with strength TERTIARY
+ void TestTertiary(/* char* par */);
+
+private:
+ static const UChar testSourceCases[][MAX_TOKEN_LEN];
+ static const UChar testTargetCases[][MAX_TOKEN_LEN];
+ static const Collator::EComparisonResult results[][2];
+
+ Collator *myCollation;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtfmapts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmapts.cpp
new file mode 100644
index 00000000000..db443f1e446
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmapts.cpp
@@ -0,0 +1,354 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "dtfmapts.h"
+
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/choicfmt.h"
+#include "unicode/msgfmt.h"
+
+
+// This is an API test, not a unit test. It doesn't test very many cases, and doesn't
+// try to test the full functionality. It just calls each function in the class and
+// verifies that it works on a basic level.
+
+void IntlTestDateFormatAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite DateFormatAPI");
+ switch (index) {
+ case 0: name = "DateFormat API test";
+ if (exec) {
+ logln("DateFormat API test---"); logln("");
+ UErrorCode status = U_ZERO_ERROR;
+ Locale saveLocale;
+ Locale::setDefault(Locale::getEnglish(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not set default locale, test may not give correct results");
+ }
+ testAPI(/*par*/);
+ Locale::setDefault(saveLocale, status);
+ }
+ break;
+
+ case 1: name = "TestEquals";
+ if (exec) {
+ logln("TestEquals---"); logln("");
+ TestEquals();
+ }
+ break;
+
+ case 2: name = "TestNameHiding";
+ if (exec) {
+ logln("TestNameHiding---"); logln("");
+ TestNameHiding();
+ }
+ break;
+
+ default: name = ""; break;
+ }
+}
+
+/**
+ * Test that the equals method works correctly.
+ */
+void IntlTestDateFormatAPI::TestEquals(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ // Create two objects at different system times
+ DateFormat *a = DateFormat::createInstance();
+ UDate start = Calendar::getNow();
+ while (Calendar::getNow() == start) ; // Wait for time to change
+ DateFormat *b = DateFormat::createInstance();
+
+ if (a == NULL || b == NULL){
+ dataerrln("Error calling DateFormat::createInstance()");
+ delete a;
+ delete b;
+ return;
+ }
+
+ if (!(*a == *b))
+ errln("FAIL: DateFormat objects created at different times are unequal.");
+
+ if (b->getDynamicClassID() == SimpleDateFormat::getStaticClassID())
+ {
+ double ONE_YEAR = 365*24*60*60*1000.0;
+ ((SimpleDateFormat*)b)->set2DigitYearStart(start + 50*ONE_YEAR, status);
+ if (U_FAILURE(status))
+ errln("FAIL: setTwoDigitStartDate failed.");
+ else if (*a == *b)
+ errln("FAIL: DateFormat objects with different two digit start dates are equal.");
+ }
+ delete a;
+ delete b;
+}
+
+/**
+ * This test checks various generic API methods in DateFormat to achieve 100%
+ * API coverage.
+ */
+void IntlTestDateFormatAPI::testAPI(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+// ======= Test constructors
+
+ logln("Testing DateFormat constructors");
+
+ DateFormat *def = DateFormat::createInstance();
+ DateFormat *fr = DateFormat::createTimeInstance(DateFormat::FULL, Locale::getFrench());
+ DateFormat *it = DateFormat::createDateInstance(DateFormat::MEDIUM, Locale::getItalian());
+ DateFormat *de = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::LONG, Locale::getGerman());
+
+ if (def == NULL || fr == NULL || it == NULL || de == NULL){
+ dataerrln("Error creating instnaces.");
+ }
+
+// ======= Test equality
+if (fr != NULL && def != NULL)
+{
+ logln("Testing equality operator");
+
+ if( *fr == *it ) {
+ errln("ERROR: == failed");
+ }
+}
+
+// ======= Test various format() methods
+if (fr != NULL && it != NULL && de != NULL)
+{
+ logln("Testing various format() methods");
+
+ UDate d = 837039928046.0;
+ Formattable fD(d, Formattable::kIsDate);
+
+ UnicodeString res1, res2, res3;
+ FieldPosition pos1(0), pos2(0);
+
+ status = U_ZERO_ERROR;
+ res1 = fr->format(d, res1, pos1, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: format() failed (French)");
+ }
+ logln( (UnicodeString) "" + d + " formatted to " + res1);
+
+ res2 = it->format(d, res2, pos2);
+ logln( (UnicodeString) "" + d + " formatted to " + res2);
+
+ res3 = de->format(d, res3);
+ logln( (UnicodeString) "" + d + " formatted to " + res3);
+}
+
+// ======= Test parse()
+if (def != NULL)
+{
+ logln("Testing parse()");
+
+ UnicodeString text("02/03/76 2:50 AM, CST");
+ Formattable result1;
+ UDate result2, result3;
+ ParsePosition pos(0), pos01(0);
+ def->parseObject(text, result1, pos);
+ if(result1.getType() != Formattable::kDate) {
+ errln("ERROR: parseObject() failed for " + text);
+ }
+ logln(text + " parsed into " + result1.getDate());
+
+ status = U_ZERO_ERROR;
+ result2 = def->parse(text, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: parse() failed, stopping testing");
+ return;
+ }
+ logln(text + " parsed into " + result2);
+
+ result3 = def->parse(text, pos01);
+ logln(text + " parsed into " + result3);
+}
+
+// ======= Test getters and setters
+if (fr != NULL && it != NULL && de != NULL)
+{
+ logln("Testing getters and setters");
+
+ int32_t count = 0;
+ const Locale *locales = DateFormat::getAvailableLocales(count);
+ logln((UnicodeString) "Got " + count + " locales" );
+ for(int32_t i = 0; i < count; i++) {
+ UnicodeString name;
+ name = locales[i].getName();
+ logln(name);
+ }
+
+ fr->setLenient(it->isLenient());
+ if(fr->isLenient() != it->isLenient()) {
+ errln("ERROR: setLenient() failed");
+ }
+
+ const Calendar *cal = def->getCalendar();
+ Calendar *newCal = cal->clone();
+ de->adoptCalendar(newCal);
+ it->setCalendar(*newCal);
+ if( *(de->getCalendar()) != *(it->getCalendar())) {
+ errln("ERROR: adopt or set Calendar() failed");
+ }
+
+ const NumberFormat *nf = def->getNumberFormat();
+ NumberFormat *newNf = (NumberFormat*) nf->clone();
+ de->adoptNumberFormat(newNf);
+ it->setNumberFormat(*newNf);
+ if( *(de->getNumberFormat()) != *(it->getNumberFormat())) {
+ errln("ERROR: adopt or set NumberFormat() failed");
+ }
+
+ const TimeZone& tz = def->getTimeZone();
+ TimeZone *newTz = tz.clone();
+ de->adoptTimeZone(newTz);
+ it->setTimeZone(*newTz);
+ if( de->getTimeZone() != it->getTimeZone()) {
+ errln("ERROR: adopt or set TimeZone() failed");
+ }
+}
+// ======= Test getStaticClassID()
+
+ logln("Testing getStaticClassID()");
+
+ status = U_ZERO_ERROR;
+ DateFormat *test = new SimpleDateFormat(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Couldn't create a DateFormat");
+ }
+
+ if(test->getDynamicClassID() != SimpleDateFormat::getStaticClassID()) {
+ errln("ERROR: getDynamicClassID() didn't return the expected value");
+ }
+
+ delete test;
+ delete def;
+ delete fr;
+ delete it;
+ delete de;
+}
+
+/**
+ * Test hiding of parse() and format() APIs in the Format hierarchy.
+ * We test the entire hierarchy, even though this test is located in
+ * the DateFormat API test.
+ */
+void
+IntlTestDateFormatAPI::TestNameHiding(void) {
+
+ // N.B.: This test passes if it COMPILES, since it's a test of
+ // compile-time name hiding.
+
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable dateObj(0, Formattable::kIsDate);
+ Formattable numObj(3.1415926535897932384626433832795);
+ Formattable obj;
+ UnicodeString str;
+ FieldPosition fpos;
+ ParsePosition ppos;
+
+ // DateFormat calling Format API
+ {
+ logln("DateFormat");
+ DateFormat *dateFmt = DateFormat::createInstance();
+ if (dateFmt) {
+ dateFmt->format(dateObj, str, status);
+ dateFmt->format(dateObj, str, fpos, status);
+ delete dateFmt;
+ } else {
+ errln("FAIL: Can't create DateFormat");
+ }
+ }
+
+ // SimpleDateFormat calling Format & DateFormat API
+ {
+ logln("SimpleDateFormat");
+ status = U_ZERO_ERROR;
+ SimpleDateFormat sdf(status);
+ // Format API
+ sdf.format(dateObj, str, status);
+ sdf.format(dateObj, str, fpos, status);
+ // DateFormat API
+ sdf.format((UDate)0, str, fpos);
+ sdf.format((UDate)0, str);
+ sdf.parse(str, status);
+ sdf.parse(str, ppos);
+ }
+
+ // NumberFormat calling Format API
+ {
+ logln("NumberFormat");
+ status = U_ZERO_ERROR;
+ NumberFormat *fmt = NumberFormat::createInstance(status);
+ if (fmt) {
+ fmt->format(numObj, str, status);
+ fmt->format(numObj, str, fpos, status);
+ delete fmt;
+ } else {
+ errln("FAIL: Can't create NumberFormat()");
+ }
+ }
+
+ // DecimalFormat calling Format & NumberFormat API
+ {
+ logln("DecimalFormat");
+ status = U_ZERO_ERROR;
+ DecimalFormat fmt(status);
+ if(U_SUCCESS(status)) {
+ // Format API
+ fmt.format(numObj, str, status);
+ fmt.format(numObj, str, fpos, status);
+ // NumberFormat API
+ fmt.format(2.71828, str);
+ fmt.format((int32_t)1234567, str);
+ fmt.format(1.41421, str, fpos);
+ fmt.format((int32_t)9876543, str, fpos);
+ fmt.parse(str, obj, ppos);
+ fmt.parse(str, obj, status);
+ } else {
+ errln("FAIL: Couldn't instantiate DecimalFormat, error %s. Quitting test", u_errorName(status));
+ }
+ }
+
+ // ChoiceFormat calling Format & NumberFormat API
+ {
+ logln("ChoiceFormat");
+ status = U_ZERO_ERROR;
+ ChoiceFormat fmt("0#foo|1#foos|2#foos", status);
+ // Format API
+ fmt.format(numObj, str, status);
+ fmt.format(numObj, str, fpos, status);
+ // NumberFormat API
+ fmt.format(2.71828, str);
+ fmt.format((int32_t)1234567, str);
+ fmt.format(1.41421, str, fpos);
+ fmt.format((int32_t)9876543, str, fpos);
+ fmt.parse(str, obj, ppos);
+ fmt.parse(str, obj, status);
+ }
+
+ // MessageFormat calling Format API
+ {
+ logln("MessageFormat");
+ status = U_ZERO_ERROR;
+ MessageFormat fmt("", status);
+ // Format API
+ // We use dateObj, which MessageFormat should reject.
+ // We're testing name hiding, not the format method.
+ fmt.format(dateObj, str, status);
+ fmt.format(dateObj, str, fpos, status);
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtfmapts.h b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmapts.h
new file mode 100644
index 00000000000..e8a109a578b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmapts.h
@@ -0,0 +1,43 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _INTLTESTDATEFORMATAPI
+#define _INTLTESTDATEFORMATAPI
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+
+/*
+ * This is an API test, not a unit test. It doesn't test very many cases, and doesn't
+ * try to test the full functionality. It just calls each function in the class and
+ * verifies that it works on a basic level.
+ */
+class IntlTestDateFormatAPI: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+private:
+ /**
+ * Tests basic functionality of various generic API methods in DateFormat
+ */
+ void testAPI(/* char* par */);
+ /**
+ * Test that the equals method works correctly.
+ */
+ void TestEquals(void);
+
+ /**
+ * Test that no parse or format methods are hidden.
+ */
+ void TestNameHiding(void);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtfmrgts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmrgts.cpp
new file mode 100644
index 00000000000..96385f40176
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmrgts.cpp
@@ -0,0 +1,1461 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "dtfmrgts.h"
+
+#include "unicode/timezone.h"
+#include "unicode/gregocal.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/datefmt.h"
+#include "unicode/simpletz.h"
+#include "unicode/resbund.h"
+
+// *****************************************************************************
+// class DateFormatRegressionTest
+// *****************************************************************************
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
+
+void
+DateFormatRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite DateFormatRegressionTest");
+ switch (index) {
+ CASE(0,Test4029195)
+ CASE(1,Test4052408)
+ CASE(2,Test4056591)
+ CASE(3,Test4059917)
+ CASE(4,Test4060212)
+ CASE(5,Test4061287)
+ CASE(6,Test4065240)
+ CASE(7,Test4071441)
+ CASE(8,Test4073003)
+ CASE(9,Test4089106)
+ CASE(10,Test4100302)
+ CASE(11,Test4101483)
+ CASE(12,Test4103340)
+ CASE(13,Test4103341)
+ CASE(14,Test4104136)
+ CASE(15,Test4104522)
+ CASE(16,Test4106807)
+ CASE(17,Test4108407)
+ CASE(18,Test4134203)
+ CASE(19,Test4151631)
+ CASE(20,Test4151706)
+ CASE(21,Test4162071)
+ CASE(22,Test4182066)
+ CASE(23,Test4210209)
+ CASE(24,Test714)
+ CASE(25,Test1684)
+ CASE(26,Test5554)
+ default: name = ""; break;
+ }
+}
+
+/**
+ * @bug 4029195
+ */
+void DateFormatRegressionTest::Test4029195(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ UDate today = Calendar::getNow();
+ logln((UnicodeString) "today: " + today);
+
+ SimpleDateFormat *sdf = (SimpleDateFormat*) DateFormat::createDateInstance();
+ if (failure(status, "SimpleDateFormat::createDateInstance")) {
+ return;
+ }
+ UnicodeString pat;
+ if(sdf == NULL){
+ dataerrln("Error calling DateFormat::createDateTimeInstance");
+ return;
+ }
+
+ pat = sdf->toPattern(pat);
+ logln("pattern: " + pat);
+ UnicodeString fmtd;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ fmtd = sdf->format(today, fmtd, pos);
+ logln("today: " + fmtd);
+
+ sdf->applyPattern("G yyyy DDD");
+ UnicodeString todayS;
+ todayS = sdf->format(today, todayS, pos);
+ logln("today: " + todayS);
+ //try {
+ today = sdf->parse(todayS, status);
+ failure(status, "sdf->parse");
+ logln((UnicodeString)"today date: " + today);
+ /*} catch(Exception e) {
+ logln("Error reparsing date: " + e.getMessage());
+ }*/
+
+ //try {
+ UnicodeString rt;
+ rt = sdf->format(sdf->parse(todayS, status), rt, pos);
+ failure(status, "sdf->parse");
+ logln("round trip: " + rt);
+ if(rt != todayS)
+ errln("Fail: Want " + todayS + " Got " + rt);
+ /*}
+ catch (ParseException e) {
+ errln("Fail: " + e);
+ e.printStackTrace();
+ }*/
+
+ delete sdf;
+}
+
+/**
+ * @bug 4052408
+ */
+void DateFormatRegressionTest::Test4052408(void)
+{
+
+ DateFormat *fmt = DateFormat::createDateTimeInstance(DateFormat::SHORT,
+ DateFormat::SHORT, Locale::getUS());
+ if (fmt == NULL) {
+ dataerrln("Error calling DateFormat::createDateTimeInstance");
+ return;
+ }
+
+ UDate dt = date(97, UCAL_MAY, 3, 8, 55);
+ UnicodeString str;
+ str = fmt->format(dt, str);
+ logln(str);
+
+ if(str != "5/3/97 8:55 AM")
+ errln("Fail: Test broken; Want 5/3/97 8:55 AM Got " + str);
+
+ UnicodeString expected[] = {
+ (UnicodeString) "", //"ERA_FIELD",
+ (UnicodeString) "97", //"YEAR_FIELD",
+ (UnicodeString) "5", //"MONTH_FIELD",
+ (UnicodeString) "3", //"DATE_FIELD",
+ (UnicodeString) "", //"HOUR_OF_DAY1_FIELD",
+ (UnicodeString) "", //"HOUR_OF_DAY0_FIELD",
+ (UnicodeString) "55", //"MINUTE_FIELD",
+ (UnicodeString) "", //"SECOND_FIELD",
+ (UnicodeString) "", //"MILLISECOND_FIELD",
+ (UnicodeString) "", //"DAY_OF_WEEK_FIELD",
+ (UnicodeString) "", //"DAY_OF_YEAR_FIELD",
+ (UnicodeString) "", //"DAY_OF_WEEK_IN_MONTH_FIELD",
+ (UnicodeString) "", //"WEEK_OF_YEAR_FIELD",
+ (UnicodeString) "", //"WEEK_OF_MONTH_FIELD",
+ (UnicodeString) "AM", //"AM_PM_FIELD",
+ (UnicodeString) "8", //"HOUR1_FIELD",
+ (UnicodeString) "", //"HOUR0_FIELD",
+ (UnicodeString) "" //"TIMEZONE_FIELD"
+ };
+
+ //Hashtable expected;// = new Hashtable();
+ //expected.put(new LongKey(DateFormat.MONTH_FIELD), "5");
+ //expected.put(new LongKey(DateFormat.DATE_FIELD), "3");
+ //expected.put(new LongKey(DateFormat.YEAR_FIELD), "97");
+ //expected.put(new LongKey(DateFormat.HOUR1_FIELD), "8");
+ //expected.put(new LongKey(DateFormat.MINUTE_FIELD), "55");
+ //expected.put(new LongKey(DateFormat.AM_PM_FIELD), "AM");
+
+ //StringBuffer buf = new StringBuffer();
+ UnicodeString fieldNames[] = {
+ (UnicodeString) "ERA_FIELD",
+ (UnicodeString) "YEAR_FIELD",
+ (UnicodeString) "MONTH_FIELD",
+ (UnicodeString) "DATE_FIELD",
+ (UnicodeString) "HOUR_OF_DAY1_FIELD",
+ (UnicodeString) "HOUR_OF_DAY0_FIELD",
+ (UnicodeString) "MINUTE_FIELD",
+ (UnicodeString) "SECOND_FIELD",
+ (UnicodeString) "MILLISECOND_FIELD",
+ (UnicodeString) "DAY_OF_WEEK_FIELD",
+ (UnicodeString) "DAY_OF_YEAR_FIELD",
+ (UnicodeString) "DAY_OF_WEEK_IN_MONTH_FIELD",
+ (UnicodeString) "WEEK_OF_YEAR_FIELD",
+ (UnicodeString) "WEEK_OF_MONTH_FIELD",
+ (UnicodeString) "AM_PM_FIELD",
+ (UnicodeString) "HOUR1_FIELD",
+ (UnicodeString) "HOUR0_FIELD",
+ (UnicodeString) "TIMEZONE_FIELD"
+ };
+
+ UBool pass = TRUE;
+ for(int i = 0; i <= 17; ++i) {
+ FieldPosition pos(i);
+ UnicodeString buf;
+ fmt->format(dt, buf, pos);
+ //char[] dst = new char[pos.getEndIndex() - pos.getBeginIndex()];
+ UnicodeString dst;
+ buf.extractBetween(pos.getBeginIndex(), pos.getEndIndex(), dst);
+ UnicodeString str(dst);
+ logln((UnicodeString)"" + i + (UnicodeString)": " + fieldNames[i] +
+ (UnicodeString)", \"" + str + (UnicodeString)"\", " +
+ pos.getBeginIndex() + (UnicodeString)", " +
+ pos.getEndIndex());
+ UnicodeString exp = expected[i];
+ if((exp.length() == 0 && str.length() == 0) || str == exp)
+ logln(" ok");
+ else {
+ errln(UnicodeString(" expected ") + exp);
+ pass = FALSE;
+ }
+
+ }
+ if( ! pass)
+ errln("Fail: FieldPosition not set right by DateFormat");
+
+ delete fmt;
+}
+
+/**
+ * @bug 4056591
+ * Verify the function of the [s|g]et2DigitYearStart() API.
+ */
+void DateFormatRegressionTest::Test4056591(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ //try {
+ SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("yyMMdd"), Locale::getUS(), status);
+ failure(status, "new SimpleDateFormat");
+ UDate start = date(1809-1900, UCAL_DECEMBER, 25);
+ fmt->set2DigitYearStart(start, status);
+ failure(status, "fmt->setTwoDigitStartDate");
+ if( (fmt->get2DigitYearStart(status) != start) || failure(status, "get2DigitStartDate"))
+ errln("get2DigitYearStart broken");
+ UDate dates [] = {
+ date(1809-1900, UCAL_DECEMBER, 25),
+ date(1909-1900, UCAL_DECEMBER, 24),
+ date(1809-1900, UCAL_DECEMBER, 26),
+ date(1861-1900, UCAL_DECEMBER, 25),
+ };
+
+ UnicodeString strings [] = {
+ (UnicodeString) "091225",
+ (UnicodeString) "091224",
+ (UnicodeString) "091226",
+ (UnicodeString) "611225"
+ };
+
+ /*Object[] DATA = {
+ "091225", new Date(1809-1900, Calendar.DECEMBER, 25),
+ "091224", new Date(1909-1900, Calendar.DECEMBER, 24),
+ "091226", new Date(1809-1900, Calendar.DECEMBER, 26),
+ "611225", new Date(1861-1900, Calendar.DECEMBER, 25),
+ };*/
+
+ for(int i = 0; i < 4; i++) {
+ UnicodeString s = strings[i];
+ UDate exp = dates[i];
+ UDate got = fmt->parse(s, status);
+ failure(status, "fmt->parse");
+ logln(s + " -> " + got + "; exp " + exp);
+ if(got != exp)
+ errln("set2DigitYearStart broken");
+ }
+ /*}
+ catch (ParseException e) {
+ errln("Fail: " + e);
+ e.printStackTrace();
+ }*/
+
+ delete fmt;
+}
+
+/**
+ * @bug 4059917
+ */
+void DateFormatRegressionTest::Test4059917(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ SimpleDateFormat *fmt;
+ UnicodeString myDate;
+
+ fmt = new SimpleDateFormat( UnicodeString("yyyy/MM/dd"), status );
+ if(failure(status, "new SimpleDateFormat")) return;
+ myDate = "1997/01/01";
+ aux917( fmt, myDate );
+
+ delete fmt;
+ fmt = NULL;
+
+ fmt = new SimpleDateFormat( UnicodeString("yyyyMMdd"), status );
+ if(failure(status, "new SimpleDateFormat")) return;
+ myDate = "19970101";
+ aux917( fmt, myDate );
+
+ delete fmt;
+}
+
+void DateFormatRegressionTest::aux917( SimpleDateFormat *fmt, UnicodeString& str ) {
+ //try {
+ UnicodeString pat;
+ pat = fmt->toPattern(pat);
+ logln( "==================" );
+ logln( "testIt: pattern=" + pat +
+ " string=" + str );
+
+
+ Formattable o;
+ //Object o;
+ ParsePosition pos(0);
+ fmt->parseObject( str, o, pos );
+ //logln( UnicodeString("Parsed object: ") + o );
+
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString formatted;
+ FieldPosition poss(FieldPosition::DONT_CARE);
+ formatted = fmt->format( o, formatted, poss, status );
+ failure(status, "fmt->format");
+ logln( "Formatted string: " + formatted );
+ if( formatted != str)
+ errln("Fail: Want " + str + " Got " + formatted);
+ /*}
+ catch (ParseException e) {
+ errln("Fail: " + e);
+ e.printStackTrace();
+ }*/
+}
+
+/**
+ * @bug 4060212
+ */
+void DateFormatRegressionTest::Test4060212(void)
+{
+ UnicodeString dateString = "1995-040.05:01:29";
+
+ logln( "dateString= " + dateString );
+ logln("Using yyyy-DDD.hh:mm:ss");
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *formatter = new SimpleDateFormat(UnicodeString("yyyy-DDD.hh:mm:ss"), status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ ParsePosition pos(0);
+ UDate myDate = formatter->parse( dateString, pos );
+ UnicodeString myString;
+ DateFormat *fmt = DateFormat::createDateTimeInstance( DateFormat::FULL,
+ DateFormat::LONG);
+ if (fmt == NULL) {
+ dataerrln("Error calling DateFormat::createDateTimeInstance");
+ delete formatter;
+ return;
+ }
+
+ myString = fmt->format( myDate, myString);
+ logln( myString );
+
+ Calendar *cal = new GregorianCalendar(status);
+ failure(status, "new GregorianCalendar");
+ cal->setTime(myDate, status);
+ failure(status, "cal->setTime");
+ if ((cal->get(UCAL_DAY_OF_YEAR, status) != 40) || failure(status, "cal->get"))
+ errln((UnicodeString) "Fail: Got " + cal->get(UCAL_DAY_OF_YEAR, status) +
+ " Want 40");
+
+ logln("Using yyyy-ddd.hh:mm:ss");
+ delete formatter;
+ formatter = NULL;
+ formatter = new SimpleDateFormat(UnicodeString("yyyy-ddd.hh:mm:ss"), status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ pos.setIndex(0);
+ myDate = formatter->parse( dateString, pos );
+ myString = fmt->format( myDate, myString );
+ logln( myString );
+ cal->setTime(myDate, status);
+ failure(status, "cal->setTime");
+ if ((cal->get(UCAL_DAY_OF_YEAR, status) != 40) || failure(status, "cal->get"))
+ errln((UnicodeString) "Fail: Got " + cal->get(UCAL_DAY_OF_YEAR, status) +
+ " Want 40");
+
+ delete formatter;
+ delete fmt;
+ delete cal;
+}
+
+/**
+ * @bug 4061287
+ */
+void DateFormatRegressionTest::Test4061287(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ SimpleDateFormat *df = new SimpleDateFormat(UnicodeString("dd/MM/yyyy"), status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat, error: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new SimpleDateFormat");
+ //try {
+ logln(UnicodeString("") + df->parse("35/01/1971", status));
+ failure(status, "df->parse");
+ //logln(df.parse("35/01/1971").toString());
+ //}
+ /*catch (ParseException e) {
+ errln("Fail: " + e);
+ e.printStackTrace();
+ }*/
+ df->setLenient(FALSE);
+ UBool ok = FALSE;
+ //try {
+ logln(UnicodeString("") + df->parse("35/01/1971", status));
+ if(U_FAILURE(status))
+ ok = TRUE;
+ //logln(df.parse("35/01/1971").toString());
+ //} catch (ParseException e) {ok=TRUE;}
+ if(!ok)
+ errln("Fail: Lenient not working");
+ delete df;
+}
+
+/**
+ * @bug 4065240
+ */
+void DateFormatRegressionTest::Test4065240(void)
+{
+ UDate curDate;
+ DateFormat *shortdate, *fulldate;
+ UnicodeString strShortDate, strFullDate;
+ Locale saveLocale = Locale::getDefault();
+ TimeZone *saveZone = TimeZone::createDefault();
+
+ UErrorCode status = U_ZERO_ERROR;
+ //try {
+ Locale *curLocale = new Locale("de","DE");
+ Locale::setDefault(*curLocale, status);
+ failure(status, "Locale::setDefault");
+ // {sfb} adoptDefault instead of setDefault
+ //TimeZone::setDefault(TimeZone::createTimeZone("EST"));
+ TimeZone::adoptDefault(TimeZone::createTimeZone("EST"));
+ curDate = date(98, 0, 1);
+ shortdate = DateFormat::createDateInstance(DateFormat::SHORT);
+ if (shortdate == NULL){
+ dataerrln("Error calling DateFormat::createDateInstance");
+ return;
+ }
+
+ fulldate = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::LONG);
+ if (fulldate == NULL){
+ dataerrln("Error calling DateFormat::createDateTimeInstance");
+ return;
+ }
+ strShortDate = "The current date (short form) is ";
+ UnicodeString temp;
+ temp = shortdate->format(curDate, temp);
+ strShortDate += temp;
+ strFullDate = "The current date (long form) is ";
+ UnicodeString temp2;
+ fulldate->format(curDate, temp2);
+ strFullDate += temp2;
+
+ logln(strShortDate);
+ logln(strFullDate);
+
+ // {sfb} What to do with resource bundle stuff?????
+
+ // Check to see if the resource is present; if not, we can't test
+ ResourceBundle *bundle = new ResourceBundle(
+ NULL, *curLocale, status);
+ failure(status, "new ResourceBundle");
+ //(UnicodeString) "java.text.resources.DateFormatZoneData", curLocale);
+
+ // {sfb} API change to ResourceBundle -- add getLocale()
+ /*if (bundle->getLocale().getLanguage(temp) == UnicodeString("de")) {
+ // UPDATE THIS AS ZONE NAME RESOURCE FOR <EST> in de_DE is updated
+ if (!strFullDate.endsWith(UnicodeString("GMT-05:00")))
+ errln("Fail: Want GMT-05:00");
+ }
+ else {
+ logln("*** TEST COULD NOT BE COMPLETED BECAUSE DateFormatZoneData ***");
+ logln("*** FOR LOCALE de OR de_DE IS MISSING ***");
+ }*/
+ //}
+ //finally {
+ Locale::setDefault(saveLocale, status);
+ failure(status, "Locale::setDefault");
+ TimeZone::setDefault(*saveZone);
+ //}
+ delete shortdate;
+ delete fulldate;
+ delete saveZone;
+ delete curLocale;
+ delete bundle;
+}
+
+/*
+ DateFormat.equals is too narrowly defined. As a result, MessageFormat
+ does not work correctly. DateFormat.equals needs to be written so
+ that the Calendar sub-object is not compared using Calendar.equals,
+ but rather compared for equivalency. This may necessitate adding a
+ (package private) method to Calendar to test for equivalency.
+
+ Currently this bug breaks MessageFormat.toPattern
+ */
+/**
+ * @bug 4071441
+ */
+void DateFormatRegressionTest::Test4071441(void)
+{
+ DateFormat *fmtA = DateFormat::createInstance();
+ DateFormat *fmtB = DateFormat::createInstance();
+
+ if (fmtA == NULL || fmtB == NULL){
+ dataerrln("Error calling DateFormat::createInstance");
+ delete fmtA;
+ delete fmtB;
+ return;
+ }
+
+ // {sfb} Is it OK to cast away const here?
+ Calendar *calA = (Calendar*) fmtA->getCalendar();
+ Calendar *calB = (Calendar*) fmtB->getCalendar();
+ if(!calA || !calB) {
+ errln("Couldn't get proper calendars, exiting");
+ delete fmtA;
+ delete fmtB;
+ return;
+ }
+ UDate epoch = date(0, 0, 0);
+ UDate xmas = date(61, UCAL_DECEMBER, 25);
+
+ UErrorCode status = U_ZERO_ERROR;
+ calA->setTime(epoch, status);
+ failure(status, "calA->setTime");
+ calB->setTime(epoch, status);
+ failure(status, "calB->setTime");
+ if (*calA != *calB)
+ errln("Fail: Can't complete test; Calendar instances unequal");
+ if (*fmtA != *fmtB)
+ errln("Fail: DateFormat unequal when Calendars equal");
+ calB->setTime(xmas, status);
+ failure(status, "calB->setTime");
+ if (*calA == *calB)
+ errln("Fail: Can't complete test; Calendar instances equal");
+ if (*fmtA != *fmtB)
+ errln("Fail: DateFormat unequal when Calendars equivalent");
+
+ logln("DateFormat.equals ok");
+
+ delete fmtA;
+ delete fmtB;
+}
+
+/* The java.text.DateFormat.parse(String) method expects for the
+ US locale a string formatted according to mm/dd/yy and parses it
+ correctly.
+
+ When given a string mm/dd/yyyy it only parses up to the first
+ two y's, typically resulting in a date in the year 1919.
+
+ Please extend the parsing method(s) to handle strings with
+ four-digit year values (probably also applicable to various
+ other locales. */
+/**
+ * @bug 4073003
+ */
+void DateFormatRegressionTest::Test4073003(void)
+{
+ //try {
+ UErrorCode ec = U_ZERO_ERROR;
+ SimpleDateFormat fmt("dd/MM/yy", Locale::getUK(), ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: SimpleDateFormat constructor");
+ return;
+ }
+ UnicodeString tests [] = {
+ (UnicodeString) "12/25/61",
+ (UnicodeString) "12/25/1961",
+ (UnicodeString) "4/3/2010",
+ (UnicodeString) "4/3/10"
+ };
+ UErrorCode status = U_ZERO_ERROR;
+ for(int i= 0; i < 4; i+=2) {
+ UDate d = fmt.parse(tests[i], status);
+ failure(status, "fmt.parse");
+ UDate dd = fmt.parse(tests[i+1], status);
+ failure(status, "fmt.parse");
+ UnicodeString s;
+ s = fmt.format(d, s);
+ UnicodeString ss;
+ ss = fmt.format(dd, ss);
+ if (d != dd)
+ errln((UnicodeString) "Fail: " + d + " != " + dd);
+ if (s != ss)
+ errln((UnicodeString)"Fail: " + s + " != " + ss);
+ logln("Ok: " + s + " " + d);
+ }
+}
+
+/**
+ * @bug 4089106
+ */
+void DateFormatRegressionTest::Test4089106(void)
+{
+ TimeZone *def = TimeZone::createDefault();
+ //try {
+ TimeZone *z = new SimpleTimeZone((int)(1.25 * 3600000), "FAKEZONE");
+ TimeZone::setDefault(*z);
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *f = new SimpleDateFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat, error %s", u_errorName(status));
+ delete f;
+ delete def;
+ delete z;
+ return;
+ }
+ failure(status, "new SimpleDateFormat");
+ if (f->getTimeZone()!= *z)
+ errln("Fail: SimpleTimeZone should use TimeZone.getDefault()");
+
+ //}
+ //finally {
+ TimeZone::setDefault(*def);
+ //}
+
+ delete z;
+ delete f;
+ delete def;
+}
+
+/**
+ * @bug 4100302
+ */
+
+// {sfb} not applicable in C++??
+
+void DateFormatRegressionTest::Test4100302(void)
+{
+/* Locale locales [] = {
+ Locale::CANADA,
+ Locale::CANADA_FRENCH,
+ Locale::CHINA,
+ Locale::CHINESE,
+ Locale::ENGLISH,
+ Locale::FRANCE,
+ Locale::FRENCH,
+ Locale::GERMAN,
+ Locale::GERMANY,
+ Locale::ITALIAN,
+ Locale::ITALY,
+ Locale::JAPAN,
+ Locale::JAPANESE,
+ Locale::KOREA,
+ Locale::KOREAN,
+ Locale::PRC,
+ Locale::SIMPLIFIED_CHINESE,
+ Locale::TAIWAN,
+ Locale::TRADITIONAL_CHINESE,
+ Locale::UK,
+ Locale::US
+ };
+ //try {
+ UBool pass = TRUE;
+ for(int i = 0; i < 21; i++) {
+
+ Format *format = DateFormat::createDateTimeInstance(DateFormat::FULL,
+ DateFormat::FULL, locales[i]);
+ byte[] bytes;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+
+ oos.writeObject(format);
+ oos.flush();
+
+ baos.close();
+ bytes = baos.toByteArray();
+
+ ObjectInputStream ois =
+ new ObjectInputStream(new ByteArrayInputStream(bytes));
+
+ if (!format.equals(ois.readObject())) {
+ pass = FALSE;
+ logln("DateFormat instance for locale " +
+ locales[i] + " is incorrectly serialized/deserialized.");
+ } else {
+ logln("DateFormat instance for locale " +
+ locales[i] + " is OKAY.");
+ }
+ }
+ if (!pass) errln("Fail: DateFormat serialization/equality bug");
+ }
+ catch (IOException e) {
+ errln("Fail: " + e);
+ e.printStackTrace();
+ }
+ catch (ClassNotFoundException e) {
+ errln("Fail: " + e);
+ e.printStackTrace();
+ }
+*/}
+
+/**
+ * @bug 4101483
+ */
+void DateFormatRegressionTest::Test4101483(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *sdf = new SimpleDateFormat(UnicodeString("z"), Locale::getUS(), status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ FieldPosition fp(UDAT_TIMEZONE_FIELD);
+ //Date d = date(9234567890L);
+ UDate d = 9234567890.0;
+ //StringBuffer buf = new StringBuffer("");
+ UnicodeString buf;
+ sdf->format(d, buf, fp);
+ //logln(sdf.format(d, buf, fp).toString());
+ logln(dateToString(d) + " => " + buf);
+ logln("beginIndex = " + fp.getBeginIndex());
+ logln("endIndex = " + fp.getEndIndex());
+ if (fp.getBeginIndex() == fp.getEndIndex())
+ errln("Fail: Empty field");
+
+ delete sdf;
+}
+
+/**
+ * @bug 4103340
+ * @bug 4138203
+ * This bug really only works in Locale.US, since that's what the locale
+ * used for Date.toString() is. Bug 4138203 reports that it fails on Korean
+ * NT; it would actually have failed on any non-US locale. Now it should
+ * work on all locales.
+ */
+void DateFormatRegressionTest::Test4103340(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ // choose a date that is the FIRST of some month
+ // and some arbitrary time
+ UDate d = date(97, 3, 1, 1, 1, 1);
+ SimpleDateFormat *df = new SimpleDateFormat(UnicodeString("MMMM"), Locale::getUS(), status);
+ if(failure(status, "new SimpleDateFormat")) return;
+
+ UnicodeString s;
+ s = dateToString(d, s);
+ UnicodeString s2;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ s2 = df->format(d, s2, pos);
+ logln("Date=" + s);
+ logln("DF=" + s2);
+ UnicodeString substr;
+ s2.extract(0,2, substr);
+ if (s.indexOf(substr) == -1)
+ errln("Months should match");
+
+ delete df;
+}
+
+/**
+ * @bug 4103341
+ */
+void DateFormatRegressionTest::Test4103341(void)
+{
+ TimeZone *saveZone =TimeZone::createDefault();
+ //try {
+
+ // {sfb} changed from setDefault to adoptDefault
+ TimeZone::adoptDefault(TimeZone::createTimeZone("CST"));
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *simple = new SimpleDateFormat(UnicodeString("MM/dd/yyyy HH:mm"), status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat, error %s", u_errorName(status));
+ delete simple;
+ return;
+ }
+ failure(status, "new SimpleDateFormat");
+ TimeZone *temp = TimeZone::createDefault();
+ if(simple->getTimeZone() != *temp)
+ errln("Fail: SimpleDateFormat not using default zone");
+ //}
+ //finally {
+ TimeZone::adoptDefault(saveZone);
+ //}
+
+ delete temp;
+ delete simple;
+}
+
+/**
+ * @bug 4104136
+ */
+void DateFormatRegressionTest::Test4104136(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *sdf = new SimpleDateFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat, error %s", u_errorName(status));
+ delete sdf;
+ return;
+ }
+ if(failure(status, "new SimpleDateFormat")) return;
+ UnicodeString pattern = "'time' hh:mm";
+ sdf->applyPattern(pattern);
+ logln("pattern: \"" + pattern + "\"");
+
+ UnicodeString strings [] = {
+ (UnicodeString)"time 10:30",
+ (UnicodeString) "time 10:x",
+ (UnicodeString) "time 10x"
+ };
+
+ ParsePosition ppos [] = {
+ ParsePosition(10),
+ ParsePosition(0),
+ ParsePosition(0)
+ };
+
+ UDate dates [] = {
+ date(70, UCAL_JANUARY, 1, 10, 30),
+ -1,
+ -1
+ };
+
+ /*Object[] DATA = {
+ "time 10:30", new ParsePosition(10), new Date(70, Calendar.JANUARY, 1, 10, 30),
+ "time 10:x", new ParsePosition(0), null,
+ "time 10x", new ParsePosition(0), null,
+ };*/
+
+ for(int i = 0; i < 3; i++) {
+ UnicodeString text = strings[i];
+ ParsePosition finish = ppos[i];
+ UDate exp = dates[i];
+
+ ParsePosition pos(0);
+ UDate d = sdf->parse(text, pos);
+ logln(" text: \"" + text + "\"");
+ logln(" index: %d", pos.getIndex());
+ logln((UnicodeString) " result: " + d);
+ if(pos.getIndex() != finish.getIndex())
+ errln("Fail: Expected pos " + finish.getIndex());
+ if (! ((d == 0 && exp == -1) || (d == exp)))
+ errln((UnicodeString) "Fail: Expected result " + exp);
+ }
+
+ delete sdf;
+}
+
+/**
+ * @bug 4104522
+ * CANNOT REPRODUCE
+ * According to the bug report, this test should throw a
+ * StringIndexOutOfBoundsException during the second parse. However,
+ * this is not seen.
+ */
+void DateFormatRegressionTest::Test4104522(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ SimpleDateFormat *sdf = new SimpleDateFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat, error %s", u_errorName(status));
+ delete sdf;
+ return;
+ }
+ failure(status, "new SimpleDateFormat");
+ UnicodeString pattern = "'time' hh:mm";
+ sdf->applyPattern(pattern);
+ logln("pattern: \"" + pattern + "\"");
+
+ // works correctly
+ ParsePosition pp(0);
+ UnicodeString text = "time ";
+ UDate dt = sdf->parse(text, pp);
+ logln(" text: \"" + text + "\"" +
+ " date: " + dt);
+
+ // works wrong
+ pp.setIndex(0);
+ text = "time";
+ dt = sdf->parse(text, pp);
+ logln(" text: \"" + text + "\"" +
+ " date: " + dt);
+
+ delete sdf;
+}
+
+/**
+ * @bug 4106807
+ */
+void DateFormatRegressionTest::Test4106807(void)
+{
+ UDate dt;
+ DateFormat *df = DateFormat::createDateTimeInstance();
+
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *sdfs [] = {
+ new SimpleDateFormat(UnicodeString("yyyyMMddHHmmss"), status),
+ new SimpleDateFormat(UnicodeString("yyyyMMddHHmmss'Z'"), status),
+ new SimpleDateFormat(UnicodeString("yyyyMMddHHmmss''"), status),
+ new SimpleDateFormat(UnicodeString("yyyyMMddHHmmss'a''a'"), status),
+ new SimpleDateFormat(UnicodeString("yyyyMMddHHmmss %"), status)
+ };
+ if(U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat, error %s", u_errorName(status));
+ delete sdfs[0];
+ delete sdfs[1];
+ delete sdfs[2];
+ delete sdfs[3];
+ delete sdfs[4];
+ return;
+ }
+
+ failure(status, "new SimpleDateFormat");
+
+ UnicodeString strings [] = {
+ (UnicodeString) "19980211140000",
+ (UnicodeString) "19980211140000",
+ (UnicodeString) "19980211140000",
+ (UnicodeString) "19980211140000a",
+ (UnicodeString) "19980211140000 "
+ };
+
+ /*Object[] data = {
+ new SimpleDateFormat("yyyyMMddHHmmss"), "19980211140000",
+ new SimpleDateFormat("yyyyMMddHHmmss'Z'"), "19980211140000",
+ new SimpleDateFormat("yyyyMMddHHmmss''"), "19980211140000",
+ new SimpleDateFormat("yyyyMMddHHmmss'a''a'"), "19980211140000a",
+ new SimpleDateFormat("yyyyMMddHHmmss %"), "19980211140000 ",
+ };*/
+ GregorianCalendar *gc = new GregorianCalendar(status);
+ failure(status, "new GregorianCalendar");
+ TimeZone *timeZone = TimeZone::createDefault();
+
+ TimeZone *gmt = timeZone->clone();
+
+ gmt->setRawOffset(0);
+
+ for(int32_t i = 0; i < 5; i++) {
+ SimpleDateFormat *format = sdfs[i];
+ UnicodeString dateString = strings[i];
+ //try {
+ format->setTimeZone(*gmt);
+ dt = format->parse(dateString, status);
+ // {sfb} some of these parses will fail purposely
+ if(U_FAILURE(status))
+ break;
+ status = U_ZERO_ERROR;
+ UnicodeString fmtd;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ fmtd = df->format(dt, fmtd, pos);
+ logln(fmtd);
+ //logln(df->format(dt));
+ gc->setTime(dt, status);
+ failure(status, "gc->getTime");
+ logln(UnicodeString("") + gc->get(UCAL_ZONE_OFFSET, status));
+ failure(status, "gc->get");
+ UnicodeString s;
+ s = format->format(dt, s, pos);
+ logln(s);
+ /*}
+ catch (ParseException e) {
+ logln("No way Jose");
+ }*/
+ }
+
+ delete timeZone;
+ delete df;
+ for(int32_t j = 0; j < 5; j++)
+ delete sdfs [j];
+ delete gc;
+ delete gmt;
+}
+
+/*
+ Synopsis: Chinese time zone CTT is not recogonized correctly.
+ Description: Platform Chinese Windows 95 - ** Time zone set to CST **
+ */
+/**
+ * @bug 4108407
+ */
+
+// {sfb} what to do with this one ??
+void DateFormatRegressionTest::Test4108407(void)
+{
+ /*long l = System.currentTimeMillis();
+ logln("user.timezone = " + System.getProperty("user.timezone", "?"));
+ logln("Time Zone :" +
+ DateFormat.getDateInstance().getTimeZone().getID());
+ logln("Default format :" +
+ DateFormat.getDateInstance().format(new Date(l)));
+ logln("Full format :" +
+ DateFormat.getDateInstance(DateFormat.FULL).format(new
+ Date(l)));
+ logln("*** Set host TZ to CST ***");
+ logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");*/
+}
+
+/**
+ * @bug 4134203
+ * SimpleDateFormat won't parse "GMT"
+ */
+void DateFormatRegressionTest::Test4134203(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString dateFormat = "MM/dd/yy HH:mm:ss zzz";
+ SimpleDateFormat *fmt = new SimpleDateFormat(dateFormat, status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ ParsePosition p0(0);
+ UDate d = fmt->parse("01/22/92 04:52:00 GMT", p0);
+ logln(dateToString(d));
+ if(p0 == ParsePosition(0))
+ errln("Fail: failed to parse 'GMT'");
+ // In the failure case an exception is thrown by parse();
+ // if no exception is thrown, the test passes.
+
+ delete fmt;
+}
+
+/**
+ * @bug 4151631
+ * SimpleDateFormat incorrect handling of 2 single quotes in format()
+ */
+void DateFormatRegressionTest::Test4151631(void)
+{
+ UnicodeString pattern = "'TO_DATE('''dd'-'MM'-'yyyy HH:mm:ss''' , ''DD-MM-YYYY HH:MI:SS'')'";
+ logln("pattern=" + pattern);
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *format = new SimpleDateFormat(pattern, Locale::getUS(), status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ UnicodeString result;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ result = format->format(date(1998-1900, UCAL_JUNE, 30, 13, 30, 0), result, pos);
+ if (result != "TO_DATE('30-06-1998 13:30:00' , 'DD-MM-YYYY HH:MI:SS')") {
+ errln("Fail: result=" + result);
+ }
+ else {
+ logln("Pass: result=" + result);
+ }
+
+ delete format;
+}
+
+/**
+ * @bug 4151706
+ * 'z' at end of date format throws index exception in SimpleDateFormat
+ * CANNOT REPRODUCE THIS BUG ON 1.2FCS
+ */
+void DateFormatRegressionTest::Test4151706(void)
+{
+ UnicodeString dateString("Thursday, 31-Dec-98 23:00:00 GMT");
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat fmt(UnicodeString("EEEE, dd-MMM-yy HH:mm:ss z"), Locale::getUS(), status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ //try {
+ UDate d = fmt.parse(dateString, status);
+ failure(status, "fmt->parse");
+ // {sfb} what about next two lines?
+ //if (d.getTime() != Date.UTC(1998-1900, Calendar.DECEMBER, 31, 23, 0, 0))
+ // errln("Incorrect value: " + d);
+ /*} catch (Exception e) {
+ errln("Fail: " + e);
+ }*/
+ UnicodeString temp;
+ FieldPosition pos(0);
+ logln(dateString + " -> " + fmt.format(d, temp, pos));
+}
+
+/**
+ * @bug 4162071
+ * Cannot reproduce this bug under 1.2 FCS -- it may be a convoluted duplicate
+ * of some other bug that has been fixed.
+ */
+void
+DateFormatRegressionTest::Test4162071(void)
+{
+ UnicodeString dateString("Thu, 30-Jul-1999 11:51:14 GMT");
+ UnicodeString format("EEE', 'dd-MMM-yyyy HH:mm:ss z"); // RFC 822/1123
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat df(format, Locale::getUS(), status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat");
+ return;
+ }
+
+ //try {
+ UDate x = df.parse(dateString, status);
+ if(U_SUCCESS(status))
+ logln("Parse format \"" + format + "\" ok");
+ else
+ errln("Parse format \"" + format + "\" failed.");
+ UnicodeString temp;
+ FieldPosition pos(0);
+ logln(dateString + " -> " + df.format(x, temp, pos));
+ //} catch (Exception e) {
+ // errln("Parse format \"" + format + "\" failed.");
+ //}
+}
+
+/**
+ * DateFormat shouldn't parse year "-1" as a two-digit year (e.g., "-1" -> 1999).
+ */
+void DateFormatRegressionTest::Test4182066(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat fmt("MM/dd/yy", Locale::getUS(), status);
+ SimpleDateFormat dispFmt("MMM dd yyyy GG", Locale::getUS(), status);
+ if (U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat");
+ return;
+ }
+
+ /* We expect 2-digit year formats to put 2-digit years in the right
+ * window. Out of range years, that is, anything less than "00" or
+ * greater than "99", are treated as literal years. So "1/2/3456"
+ * becomes 3456 AD. Likewise, "1/2/-3" becomes -3 AD == 2 BC.
+ */
+ const char* STRINGS[] = {
+ "02/29/00",
+ "01/23/01",
+ "04/05/-1",
+ "01/23/-9",
+ "11/12/1314",
+ "10/31/1",
+ "09/12/+1",
+ "09/12/001",
+ };
+ int32_t STRINGS_COUNT = (int32_t)(sizeof(STRINGS) / sizeof(STRINGS[0]));
+ UDate FAIL_DATE = (UDate) 0;
+ UDate DATES[] = {
+ date(2000-1900, UCAL_FEBRUARY, 29),
+ date(2001-1900, UCAL_JANUARY, 23),
+ date( -1-1900, UCAL_APRIL, 5),
+ date( -9-1900, UCAL_JANUARY, 23),
+ date(1314-1900, UCAL_NOVEMBER, 12),
+ date( 1-1900, UCAL_OCTOBER, 31),
+ FAIL_DATE, // "+1" isn't recognized by US NumberFormat
+ date( 1-1900, UCAL_SEPTEMBER,12),
+ };
+
+ UnicodeString out;
+ UBool pass = TRUE;
+ for (int32_t i=0; i<STRINGS_COUNT; ++i) {
+ UnicodeString str(STRINGS[i]);
+ UDate expected = DATES[i];
+ status = U_ZERO_ERROR;
+ UDate actual = fmt.parse(str, status);
+ if (U_FAILURE(status)) {
+ actual = FAIL_DATE;
+ }
+ UnicodeString actStr;
+ if (actual == FAIL_DATE) {
+ actStr.append("null");
+ } else {
+ // Yuck: See j25
+ ((DateFormat*)&dispFmt)->format(actual, actStr);
+ }
+
+ if (expected == actual) {
+ out.append(str + " => " + actStr + "\n");
+ } else {
+ UnicodeString expStr;
+ if (expected == FAIL_DATE) {
+ expStr.append("null");
+ } else {
+ // Yuck: See j25
+ ((DateFormat*)&dispFmt)->format(expected, expStr);
+ }
+ out.append("FAIL: " + str + " => " + actStr
+ + ", expected " + expStr + "\n");
+ pass = FALSE;
+ }
+ }
+ if (pass) {
+ log(out);
+ } else {
+ err(out);
+ }
+}
+
+/**
+ * j32 {JDK Bug 4210209 4209272}
+ * DateFormat cannot parse Feb 29 2000 when setLenient(false)
+ */
+void
+DateFormatRegressionTest::Test4210209(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern("MMM d, yyyy");
+ SimpleDateFormat sfmt(pattern, Locale::getUS(), status);
+ SimpleDateFormat sdisp("MMM dd yyyy GG", Locale::getUS(), status);
+ DateFormat& fmt = *(DateFormat*)&sfmt; // Yuck: See j25
+ DateFormat& disp = *(DateFormat*)&sdisp; // Yuck: See j25
+ if (U_FAILURE(status)) {
+ errln("Couldn't create SimpleDateFormat");
+ return;
+ }
+ Calendar* calx = (Calendar*)fmt.getCalendar(); // cast away const!
+ calx->setLenient(FALSE);
+ UDate d = date(2000-1900, UCAL_FEBRUARY, 29);
+ UnicodeString s, ss;
+ fmt.format(d, s);
+ logln(disp.format(d, ss.remove()) + " f> " + pattern +
+ " => \"" + s + "\"");
+ ParsePosition pos(0);
+ d = fmt.parse(s, pos);
+ logln(UnicodeString("\"") + s + "\" p> " + pattern +
+ " => " + disp.format(d, ss.remove()));
+ logln(UnicodeString("Parse pos = ") + pos.getIndex() +
+ ", error pos = " + pos.getErrorIndex());
+ if (pos.getErrorIndex() != -1) {
+ errln(UnicodeString("FAIL: Error index should be -1"));
+ }
+
+ // The underlying bug is in GregorianCalendar. If the following lines
+ // succeed, the bug is fixed. If the bug isn't fixed, they will throw
+ // an exception.
+ GregorianCalendar cal(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Unable to create Calendar");
+ return;
+ }
+ cal.clear();
+ cal.setLenient(FALSE);
+ cal.set(2000, UCAL_FEBRUARY, 29); // This should work!
+ logln(UnicodeString("Attempt to set Calendar to Feb 29 2000: ") +
+ disp.format(cal.getTime(status), ss.remove()));
+ if (U_FAILURE(status)) {
+ errln("FAIL: Unable to set Calendar to Feb 29 2000");
+ }
+}
+
+void DateFormatRegressionTest::Test714(void)
+{
+ //try {
+ UDate d(978103543000.);
+ DateFormat *fmt = DateFormat::createDateTimeInstance(DateFormat::NONE,
+ DateFormat::MEDIUM,
+ Locale::getUS());
+ if (fmt == NULL) {
+ dataerrln("Error calling DateFormat::createDateTimeInstance");
+ return;
+ }
+
+ UnicodeString s;
+ UnicodeString tests =
+ (UnicodeString) "7:25:43 AM" ;
+ UErrorCode status = U_ZERO_ERROR;
+ fmt->format (d,s);
+ if(U_FAILURE(status))
+ {
+ errln((UnicodeString) "Fail, errmsg " + u_errorName(status));
+ return;
+ }
+
+ if(s != tests)
+ {
+ errln((UnicodeString) "Fail: " + s + " != " + tests);
+ }
+ else
+ {
+ logln("OK: " + s + " == " + tests);
+ }
+
+ delete fmt;
+}
+
+class Test1684Data {
+public:
+ int32_t year;
+ int32_t month;
+ int32_t date;
+ int32_t womyear;
+ int32_t wommon;
+ int32_t wom;
+ int32_t dow;
+ UnicodeString data;
+ UnicodeString normalized;
+
+ Test1684Data(int32_t xyear, int32_t xmonth, int32_t xdate,
+ int32_t xwomyear, int32_t xwommon, int32_t xwom, int32_t xdow,
+ const char *xdata, const char *xnormalized) :
+ year(xyear),
+ month(xmonth-1),
+ date(xdate),
+ womyear(xwomyear),
+ wommon(xwommon-1),
+ wom(xwom),
+ dow(xdow),
+ data(xdata,""),
+ normalized((xnormalized==NULL)?xdata:xnormalized,"")
+ { }
+};
+
+void DateFormatRegressionTest::Test1684(void)
+{
+ // July 2001 August 2001 January 2002
+ // Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
+ // 1 2 3 4 5 6 7 1 2 3 4 1 2 3 4 5
+ // 8 9 10 11 12 13 14 5 6 7 8 9 10 11 6 7 8 9 10 11 12
+ // 15 16 17 18 19 20 21 12 13 14 15 16 17 18 13 14 15 16 17 18 19
+ // 22 23 24 25 26 27 28 19 20 21 22 23 24 25 20 21 22 23 24 25 26
+ // 29 30 31 26 27 28 29 30 31 27 28 29 30 31
+ Test1684Data *tests[] = {
+ new Test1684Data(2001, 8, 6, 2001,8,2,UCAL_MONDAY, "2001 08 02 Mon", NULL),
+ new Test1684Data(2001, 8, 7, 2001,8,2,UCAL_TUESDAY, "2001 08 02 Tue", NULL),
+ new Test1684Data(2001, 8, 5,/*12,*/ 2001,8,2,UCAL_SUNDAY, "2001 08 02 Sun", NULL),
+ new Test1684Data(2001, 8,6, /*7, 30,*/ 2001,7,6,UCAL_MONDAY, "2001 07 06 Mon", "2001 08 02 Mon"),
+ new Test1684Data(2001, 8,7, /*7, 31,*/ 2001,7,6,UCAL_TUESDAY, "2001 07 06 Tue", "2001 08 02 Tue"),
+ new Test1684Data(2001, 8, 5, 2001,7,6,UCAL_SUNDAY, "2001 07 06 Sun", "2001 08 02 Sun"),
+ new Test1684Data(2001, 7, 30, 2001,8,1,UCAL_MONDAY, "2001 08 01 Mon", "2001 07 05 Mon"),
+ new Test1684Data(2001, 7, 31, 2001,8,1,UCAL_TUESDAY, "2001 08 01 Tue", "2001 07 05 Tue"),
+ new Test1684Data(2001, 7,29, /*8, 5,*/ 2001,8,1,UCAL_SUNDAY, "2001 08 01 Sun", "2001 07 05 Sun"),
+ new Test1684Data(2001, 12, 31, 2001,12,6,UCAL_MONDAY, "2001 12 06 Mon", NULL),
+ new Test1684Data(2002, 1, 1, 2002,1,1,UCAL_TUESDAY, "2002 01 01 Tue", NULL),
+ new Test1684Data(2002, 1, 2, 2002,1,1,UCAL_WEDNESDAY, "2002 01 01 Wed", NULL),
+ new Test1684Data(2002, 1, 3, 2002,1,1,UCAL_THURSDAY, "2002 01 01 Thu", NULL),
+ new Test1684Data(2002, 1, 4, 2002,1,1,UCAL_FRIDAY, "2002 01 01 Fri", NULL),
+ new Test1684Data(2002, 1, 5, 2002,1,1,UCAL_SATURDAY, "2002 01 01 Sat", NULL),
+ new Test1684Data(2001,12,30, /*2002, 1, 6,*/ 2002,1,1,UCAL_SUNDAY, "2002 01 01 Sun", "2001 12 06 Sun")
+ };
+
+#define kTest1684Count ((int32_t)(sizeof(tests)/sizeof(tests[0])))
+
+ int32_t pass = 0, error = 0, warning = 0;
+ int32_t i;
+
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern("yyyy MM WW EEE","");
+ Calendar *cal = new GregorianCalendar(status);
+ SimpleDateFormat *sdf = new SimpleDateFormat(pattern,status);
+ if (U_FAILURE(status)) {
+ dataerrln("Error constructing SimpleDateFormat");
+ for(i=0;i<kTest1684Count;i++) {
+ delete tests[i];
+ }
+ delete cal;
+ delete sdf;
+ return;
+ }
+ cal->setFirstDayOfWeek(UCAL_SUNDAY);
+ cal->setMinimalDaysInFirstWeek(1);
+
+ sdf->adoptCalendar(cal);
+
+ cal = sdf->getCalendar()->clone(); // sdf may have deleted calendar
+
+ if(!cal || !sdf || U_FAILURE(status)) {
+ errln(UnicodeString("Error setting up test: ") + u_errorName(status));
+ }
+
+ for (i = 0; i < kTest1684Count; ++i) {
+ Test1684Data &test = *(tests[i]);
+ logln(UnicodeString("#") + i + UnicodeString("\n-----\nTesting round trip of ") + test.year +
+ " " + (test.month + 1) +
+ " " + test.date +
+ " (written as) " + test.data);
+
+ cal->clear();
+ cal->set(test.year, test.month, test.date);
+ UDate ms = cal->getTime(status);
+
+ cal->clear();
+ cal->set(UCAL_YEAR, test.womyear);
+ cal->set(UCAL_MONTH, test.wommon);
+ cal->set(UCAL_WEEK_OF_MONTH, test.wom);
+ cal->set(UCAL_DAY_OF_WEEK, test.dow);
+ UDate ms2 = cal->getTime(status);
+
+ if (ms2 != ms) {
+ errln((UnicodeString)"\nError: GregorianUCAL_DOM gave " + ms +
+ "\n GregorianUCAL_WOM gave " + ms2);
+ error++;
+ } else {
+ pass++;
+ }
+
+ ms2 = sdf->parse(test.data, status);
+ if(U_FAILURE(status)) {
+ errln("parse exception: " + UnicodeString(u_errorName(status)));
+ }
+
+ if (ms2!=ms) {
+ errln((UnicodeString)"\nError: GregorianCalendar gave " + ms +
+ "\n SimpleDateFormat.parse gave " + ms2);
+ error++;
+ } else {
+ pass++;
+ }
+
+ UnicodeString result;
+ sdf->format(ms, result);
+ if (result != test.normalized) {
+ errln("\nWarning: format of '" + test.data + "' gave" +
+ "\n '" + result + "'" +
+ "\n expected '" + test.normalized + "'");
+ warning++;
+ } else {
+ pass++;
+ }
+
+ UDate ms3;
+ ms3 = sdf->parse(result, status);
+ if(U_FAILURE(status)) {
+ errln("parse exception 2: " + (UnicodeString)u_errorName(status));
+ }
+
+ if (ms3!=ms) {
+ error++;
+ errln((UnicodeString)"\nError: Re-parse of '" + result + "' gave time of " +
+ "\n " + ms3 +
+ "\n not " + ms);
+ } else {
+ pass++;
+ }
+ }
+
+ UnicodeString info
+ = UnicodeString("Passed: ") + pass + ", Warnings: " + warning + ", Errors: " + error;
+ if (error > 0) {
+ errln(info);
+ } else {
+ logln(info);
+ }
+
+ for(i=0;i<kTest1684Count;i++) {
+ delete tests[i];
+ }
+ delete cal;
+ delete sdf;
+}
+
+void DateFormatRegressionTest::Test5554(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern("Z","");
+ UnicodeString newfoundland("Canada/Newfoundland", "");
+ TimeZone *zone = TimeZone::createTimeZone(newfoundland);
+ Calendar *cal = new GregorianCalendar(zone, status);
+ SimpleDateFormat *sdf = new SimpleDateFormat(pattern,status);
+ if (U_FAILURE(status)) {
+ dataerrln("Error constructing SimpleDateFormat");
+ delete cal;
+ delete sdf;
+ return;
+ }
+ cal->set(2007, 1, 14);
+ UDate date = cal->getTime(status);
+ if (U_FAILURE(status)) {
+ errln("Error getting time to format");
+ return;
+ };
+ sdf->adoptCalendar(cal);
+ UnicodeString result;
+ UnicodeString correct("-0330", "");
+ sdf->format(date, result);
+ if (result != correct) {
+ errln("\nError: Newfoundland Z of Jan 14, 2007 gave '" + result + "', expected '" + correct + "'");
+ }
+ delete sdf;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtfmrgts.h b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmrgts.h
new file mode 100644
index 00000000000..1a9762c79b5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmrgts.h
@@ -0,0 +1,59 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _DATEFORMATREGRESSIONTEST_
+#define _DATEFORMATREGRESSIONTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/smpdtfmt.h"
+#include "caltztst.h"
+
+/**
+ * Performs regression test for DateFormat
+ **/
+class DateFormatRegressionTest: public CalendarTimeZoneTest {
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+
+ void Test4029195(void);
+ void Test4052408(void);
+ void Test4056591(void);
+ void Test4059917(void);
+ void aux917( SimpleDateFormat *fmt, UnicodeString& str );
+ void Test4060212(void);
+ void Test4061287(void);
+ void Test4065240(void);
+ void Test4071441(void);
+ void Test4073003(void);
+ void Test4089106(void);
+ void Test4100302(void);
+ void Test4101483(void);
+ void Test4103340(void);
+ void Test4103341(void);
+ void Test4104136(void);
+ void Test4104522(void);
+ void Test4106807(void);
+ void Test4108407(void);
+ void Test4134203(void);
+ void Test4151631(void);
+ void Test4151706(void);
+ void Test4162071(void);
+ void Test4182066(void);
+ void Test4210209(void);
+ void Test714(void);
+ void Test1684(void);
+ void Test5554(void);
+ };
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DATEFORMATREGRESSIONTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtfmtrtts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmtrtts.cpp
new file mode 100644
index 00000000000..63f3479a6bb
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmtrtts.cpp
@@ -0,0 +1,558 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/gregocal.h"
+#include "dtfmtrtts.h"
+#include "caltest.h"
+
+#include <stdio.h>
+#include <string.h>
+
+// *****************************************************************************
+// class DateFormatRoundTripTest
+// *****************************************************************************
+
+// Useful for turning up subtle bugs: Change the following to TRUE, recompile,
+// and run while at lunch.
+// Warning -- makes test run infinite loop!!!
+#ifndef INFINITE
+#define INFINITE 0
+#endif
+
+// Define this to test just a single locale
+//#define TEST_ONE_LOC "cs_CZ"
+
+// If SPARSENESS is > 0, we don't run each exhaustive possibility.
+// There are 24 total possible tests per each locale. A SPARSENESS
+// of 12 means we run half of them. A SPARSENESS of 23 means we run
+// 1 of them. SPARSENESS _must_ be in the range 0..23.
+int32_t DateFormatRoundTripTest::SPARSENESS = 0;
+int32_t DateFormatRoundTripTest::TRIALS = 4;
+int32_t DateFormatRoundTripTest::DEPTH = 5;
+
+DateFormatRoundTripTest::DateFormatRoundTripTest() : dateFormat(0) {
+}
+
+DateFormatRoundTripTest::~DateFormatRoundTripTest() {
+ delete dateFormat;
+}
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
+
+void
+DateFormatRoundTripTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+{
+ optionv = (par && *par=='v');
+ switch (index) {
+ CASE(0,TestDateFormatRoundTrip)
+ CASE(1, TestCentury)
+ default: name = ""; break;
+ }
+}
+
+UBool
+DateFormatRoundTripTest::failure(UErrorCode status, const char* msg)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+UBool
+DateFormatRoundTripTest::failure(UErrorCode status, const char* msg, const UnicodeString& str)
+{
+ if(U_FAILURE(status)) {
+ UnicodeString escaped;
+ escape(str,escaped);
+ errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status) + ", str=" + escaped);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void DateFormatRoundTripTest::TestCentury()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Locale locale("es_PA");
+ UnicodeString pattern = "MM/dd/yy hh:mm:ss a z";
+ SimpleDateFormat fmt(pattern, locale, status);
+ if(!assertSuccess("trying to construct", status))return;
+ UDate date[] = {-55018555891590.05, 0, 0};
+ UnicodeString result[2];
+
+ fmt.format(date[0], result[0]);
+ date[1] = fmt.parse(result[0], status);
+ fmt.format(date[1], result[1]);
+ date[2] = fmt.parse(result[1], status);
+
+ /* This test case worked OK by accident before. date[1] != date[0],
+ * because we use -80/+20 year window for 2-digit year parsing.
+ * (date[0] is in year 1926, date[1] is in year 2026.) result[1] set
+ * by the first format call returns "07/13/26 07:48:28 p.m. PST",
+ * which is correct, because DST was not used in year 1926 in zone
+ * America/Los_Angeles. When this is parsed, date[1] becomes a time
+ * in 2026, which is "07/13/26 08:48:28 p.m. PDT". There was a zone
+ * offset calculation bug that observed DST in 1926, which was resolved.
+ * Before the bug was resolved, result[0] == result[1] was true,
+ * but after the bug fix, the expected result is actually
+ * result[0] != result[1]. -Yoshito
+ */
+ /* TODO: We need to review this code and clarify what we really
+ * want to test here.
+ */
+ //if (date[1] != date[2] || result[0] != result[1]) {
+ if (date[1] != date[2]) {
+ errln("Round trip failure: \"%S\" (%f), \"%S\" (%f)", result[0].getBuffer(), date[1], result[1].getBuffer(), date[2]);
+ }
+}
+
+// ==
+
+void DateFormatRoundTripTest::TestDateFormatRoundTrip()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ getFieldCal = Calendar::createInstance(status);
+ failure(status, "Calendar::createInstance");
+ if(!assertSuccess("trying to construct", status))return;
+
+
+ int32_t locCount = 0;
+ const Locale *avail = DateFormat::getAvailableLocales(locCount);
+ logln("DateFormat available locales: %d", locCount);
+ if(quick) {
+ SPARSENESS = 18;
+ logln("Quick mode: only testing SPARSENESS = 18");
+ }
+ TimeZone *tz = TimeZone::createDefault();
+ UnicodeString temp;
+ logln("Default TimeZone: " + tz->getID(temp));
+ delete tz;
+
+#ifdef TEST_ONE_LOC // define this to just test ONE locale.
+ Locale loc(TEST_ONE_LOC);
+ test(loc);
+#if INFINITE
+ for(;;) {
+ test(loc);
+ }
+#endif
+
+#else
+# if INFINITE
+ // Special infinite loop test mode for finding hard to reproduce errors
+ Locale loc = Locale::getDefault();
+ logln("ENTERING INFINITE TEST LOOP FOR Locale: " + loc.getDisplayName(temp));
+ for(;;)
+ test(loc);
+# else
+ test(Locale::getDefault());
+
+#if 1
+ // installed locales
+ for (int i=0; i < locCount; ++i) {
+ test(avail[i]);
+ }
+#endif
+
+#if 1
+ // special locales
+ int32_t jCount = CalendarTest::testLocaleCount();
+ for (int32_t j=0; j < jCount; ++j) {
+ test(Locale(CalendarTest::testLocaleID(j)));
+ }
+#endif
+
+# endif
+#endif
+
+ delete getFieldCal;
+}
+
+static const char *styleName(DateFormat::EStyle s)
+{
+ switch(s)
+ {
+ case DateFormat::SHORT: return "SHORT";
+ case DateFormat::MEDIUM: return "MEDIUM";
+ case DateFormat::LONG: return "LONG";
+ case DateFormat::FULL: return "FULL";
+// case DateFormat::DEFAULT: return "DEFAULT";
+ case DateFormat::DATE_OFFSET: return "DATE_OFFSET";
+ case DateFormat::NONE: return "NONE";
+ case DateFormat::DATE_TIME: return "DATE_TIME";
+ default: return "Unknown";
+ }
+}
+
+void DateFormatRoundTripTest::test(const Locale& loc)
+{
+ UnicodeString temp;
+#if !INFINITE
+ logln("Locale: " + loc.getDisplayName(temp));
+#endif
+
+ // Total possibilities = 24
+ // 4 date
+ // 4 time
+ // 16 date-time
+ UBool TEST_TABLE [24];//= new boolean[24];
+ int32_t i = 0;
+ for(i = 0; i < 24; ++i)
+ TEST_TABLE[i] = TRUE;
+
+ // If we have some sparseness, implement it here. Sparseness decreases
+ // test time by eliminating some tests, up to 23.
+ for(i = 0; i < SPARSENESS; ) {
+ int random = (int)(randFraction() * 24);
+ if (random >= 0 && random < 24 && TEST_TABLE[i]) {
+ TEST_TABLE[i] = FALSE;
+ ++i;
+ }
+ }
+
+ int32_t itable = 0;
+ int32_t style = 0;
+ for(style = DateFormat::FULL; style <= DateFormat::SHORT; ++style) {
+ if(TEST_TABLE[itable++]) {
+ logln("Testing style " + UnicodeString(styleName((DateFormat::EStyle)style)));
+ DateFormat *df = DateFormat::createDateInstance((DateFormat::EStyle)style, loc);
+ if(df == NULL) {
+ errln(UnicodeString("Could not DF::createDateInstance ") + UnicodeString(styleName((DateFormat::EStyle)style)) + " Locale: " + loc.getDisplayName(temp));
+ } else {
+ test(df, loc);
+ delete df;
+ }
+ }
+ }
+
+ for(style = DateFormat::FULL; style <= DateFormat::SHORT; ++style) {
+ if (TEST_TABLE[itable++]) {
+ logln("Testing style " + UnicodeString(styleName((DateFormat::EStyle)style)));
+ DateFormat *df = DateFormat::createTimeInstance((DateFormat::EStyle)style, loc);
+ if(df == NULL) {
+ errln(UnicodeString("Could not DF::createTimeInstance ") + UnicodeString(styleName((DateFormat::EStyle)style)) + " Locale: " + loc.getDisplayName(temp));
+ } else {
+ test(df, loc, TRUE);
+ delete df;
+ }
+ }
+ }
+
+ for(int32_t dstyle = DateFormat::FULL; dstyle <= DateFormat::SHORT; ++dstyle) {
+ for(int32_t tstyle = DateFormat::FULL; tstyle <= DateFormat::SHORT; ++tstyle) {
+ if(TEST_TABLE[itable++]) {
+ logln("Testing dstyle" + UnicodeString(styleName((DateFormat::EStyle)dstyle)) + ", tstyle" + UnicodeString(styleName((DateFormat::EStyle)tstyle)) );
+ DateFormat *df = DateFormat::createDateTimeInstance((DateFormat::EStyle)dstyle, (DateFormat::EStyle)tstyle, loc);
+ if(df == NULL) {
+ errln(UnicodeString("Could not DF::createDateTimeInstance ") + UnicodeString(styleName((DateFormat::EStyle)dstyle)) + ", tstyle" + UnicodeString(styleName((DateFormat::EStyle)tstyle)) + "Locale: " + loc.getDisplayName(temp));
+ } else {
+ test(df, loc);
+ delete df;
+ }
+ }
+ }
+ }
+}
+
+void DateFormatRoundTripTest::test(DateFormat *fmt, const Locale &origLocale, UBool timeOnly)
+{
+ UnicodeString pat;
+ if(fmt->getDynamicClassID() != SimpleDateFormat::getStaticClassID()) {
+ errln("DateFormat wasn't a SimpleDateFormat");
+ return;
+ }
+
+ UBool isGregorian = FALSE;
+ UErrorCode minStatus = U_ZERO_ERROR;
+ UDate minDate = CalendarTest::minDateOfCalendar(*fmt->getCalendar(), isGregorian, minStatus);
+ if(U_FAILURE(minStatus)) {
+ errln((UnicodeString)"Failure getting min date for " + origLocale.getName());
+ return;
+ }
+ //logln(UnicodeString("Min date is ") + fullFormat(minDate) + " for " + origLocale.getName());
+
+ pat = ((SimpleDateFormat*)fmt)->toPattern(pat);
+
+ // NOTE TO MAINTAINER
+ // This indexOf check into the pattern needs to be refined to ignore
+ // quoted characters. Currently, this isn't a problem with the locale
+ // patterns we have, but it may be a problem later.
+
+ UBool hasEra = (pat.indexOf(UnicodeString("G")) != -1);
+ UBool hasZoneDisplayName = (pat.indexOf(UnicodeString("z")) != -1) || (pat.indexOf(UnicodeString("v")) != -1)
+ || (pat.indexOf(UnicodeString("V")) != -1);
+
+ // Because patterns contain incomplete data representing the Date,
+ // we must be careful of how we do the roundtrip. We start with
+ // a randomly generated Date because they're easier to generate.
+ // From this we get a string. The string is our real starting point,
+ // because this string should parse the same way all the time. Note
+ // that it will not necessarily parse back to the original date because
+ // of incompleteness in patterns. For example, a time-only pattern won't
+ // parse back to the same date.
+
+ //try {
+ for(int i = 0; i < TRIALS; ++i) {
+ UDate *d = new UDate [DEPTH];
+ UnicodeString *s = new UnicodeString[DEPTH];
+
+ if(isGregorian == TRUE) {
+ d[0] = generateDate();
+ } else {
+ d[0] = generateDate(minDate);
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ // We go through this loop until we achieve a match or until
+ // the maximum loop count is reached. We record the points at
+ // which the date and the string starts to match. Once matching
+ // starts, it should continue.
+ int loop;
+ int dmatch = 0; // d[dmatch].getTime() == d[dmatch-1].getTime()
+ int smatch = 0; // s[smatch].equals(s[smatch-1])
+ for(loop = 0; loop < DEPTH; ++loop) {
+ if (loop > 0) {
+ d[loop] = fmt->parse(s[loop-1], status);
+ failure(status, "fmt->parse", s[loop-1]+" in locale: " + origLocale.getName());
+ status = U_ZERO_ERROR; /* any error would have been reported */
+ }
+
+ s[loop] = fmt->format(d[loop], s[loop]);
+
+ // For displaying which date is being tested
+ //logln(s[loop] + " = " + fullFormat(d[loop]));
+
+ if(s[loop].length() == 0) {
+ errln("FAIL: fmt->format gave 0-length string in " + pat + " with number " + d[loop] + " in locale " + origLocale.getName());
+ }
+
+ if(loop > 0) {
+ if(smatch == 0) {
+ UBool match = s[loop] == s[loop-1];
+ if(smatch == 0) {
+ if(match)
+ smatch = loop;
+ }
+ else if( ! match)
+ errln("FAIL: String mismatch after match");
+ }
+
+ if(dmatch == 0) {
+ // {sfb} watch out here, this might not work
+ UBool match = d[loop]/*.getTime()*/ == d[loop-1]/*.getTime()*/;
+ if(dmatch == 0) {
+ if(match)
+ dmatch = loop;
+ }
+ else if( ! match)
+ errln("FAIL: Date mismatch after match");
+ }
+
+ if(smatch != 0 && dmatch != 0)
+ break;
+ }
+ }
+ // At this point loop == DEPTH if we've failed, otherwise loop is the
+ // max(smatch, dmatch), that is, the index at which we have string and
+ // date matching.
+
+ // Date usually matches in 2. Exceptions handled below.
+ int maxDmatch = 2;
+ int maxSmatch = 1;
+ if (dmatch > maxDmatch) {
+ // Time-only pattern with zone information and a starting date in PST.
+ if(timeOnly && hasZoneDisplayName
+ && fmt->getTimeZone().inDaylightTime(d[0], status) && ! failure(status, "TimeZone::inDST()")) {
+ maxDmatch = 3;
+ maxSmatch = 2;
+ }
+ }
+
+ // String usually matches in 1. Exceptions are checked for here.
+ if(smatch > maxSmatch) { // Don't compute unless necessary
+ UBool in0;
+ // Starts in BC, with no era in pattern
+ if( ! hasEra && getField(d[0], UCAL_ERA) == GregorianCalendar::BC)
+ maxSmatch = 2;
+ // Starts in DST, no year in pattern
+ else if((in0=fmt->getTimeZone().inDaylightTime(d[0], status)) && ! failure(status, "gettingDaylightTime") &&
+ pat.indexOf(UnicodeString("yyyy")) == -1)
+ maxSmatch = 2;
+ // If we start not in DST, but transition into DST
+ else if (!in0 &&
+ fmt->getTimeZone().inDaylightTime(d[1], status) && !failure(status, "gettingDaylightTime"))
+ maxSmatch = 2;
+ // Two digit year with no time zone change,
+ // unless timezone isn't used or we aren't close to the DST changover
+ else if (pat.indexOf(UnicodeString("y")) != -1
+ && pat.indexOf(UnicodeString("yyyy")) == -1
+ && getField(d[0], UCAL_YEAR)
+ != getField(d[dmatch], UCAL_YEAR)
+ && !failure(status, "error status [smatch>maxSmatch]")
+ && ((hasZoneDisplayName
+ && (fmt->getTimeZone().inDaylightTime(d[0], status)
+ == fmt->getTimeZone().inDaylightTime(d[dmatch], status)
+ || getField(d[0], UCAL_MONTH) == UCAL_APRIL
+ || getField(d[0], UCAL_MONTH) == UCAL_OCTOBER))
+ || !hasZoneDisplayName)
+ )
+ {
+ maxSmatch = 2;
+ }
+ // If zone display name is used, fallback format might be used before 1970
+ else if (hasZoneDisplayName && d[0] < 0) {
+ maxSmatch = 2;
+ }
+ }
+
+ if(dmatch > maxDmatch || smatch > maxSmatch) { // Special case for Japanese and Islamic (could have large negative years)
+ const char *type = fmt->getCalendar()->getType();
+ if(!strcmp(type,"japanese")) {
+ maxSmatch = 4;
+ maxDmatch = 4;
+ }
+ }
+
+ // Use @v to see verbose results on successful cases
+ UBool fail = (dmatch > maxDmatch || smatch > maxSmatch);
+ if (optionv || fail) {
+ if (fail) {
+ errln(UnicodeString("\nFAIL: Pattern: ") + pat +
+ " in Locale: " + origLocale.getName());
+ } else {
+ errln(UnicodeString("\nOk: Pattern: ") + pat +
+ " in Locale: " + origLocale.getName());
+ }
+
+ logln("Date iters until match=%d (max allowed=%d), string iters until match=%d (max allowed=%d)",
+ dmatch,maxDmatch, smatch, maxSmatch);
+
+ for(int j = 0; j <= loop && j < DEPTH; ++j) {
+ UnicodeString temp;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ errln((j>0?" P> ":" ") + fullFormat(d[j]) + " F> " +
+ escape(s[j], temp) + UnicodeString(" d=") + d[j] +
+ (j > 0 && d[j]/*.getTime()*/==d[j-1]/*.getTime()*/?" d==":"") +
+ (j > 0 && s[j] == s[j-1]?" s==":""));
+ }
+ }
+ delete[] d;
+ delete[] s;
+ }
+ /*}
+ catch (ParseException e) {
+ errln("Exception: " + e.getMessage());
+ logln(e.toString());
+ }*/
+}
+
+const UnicodeString& DateFormatRoundTripTest::fullFormat(UDate d) {
+ UErrorCode ec = U_ZERO_ERROR;
+ if (dateFormat == 0) {
+ dateFormat = new SimpleDateFormat((UnicodeString)"EEE MMM dd HH:mm:ss.SSS zzz yyyy G", ec);
+ if (U_FAILURE(ec) || dateFormat == 0) {
+ fgStr = "[FAIL: SimpleDateFormat constructor]";
+ delete dateFormat;
+ dateFormat = 0;
+ return fgStr;
+ }
+ }
+ fgStr.truncate(0);
+ dateFormat->format(d, fgStr);
+ return fgStr;
+}
+
+/**
+ * Return a field of the given date
+ */
+int32_t DateFormatRoundTripTest::getField(UDate d, int32_t f) {
+ // Should be synchronized, but we're single threaded so it's ok
+ UErrorCode status = U_ZERO_ERROR;
+ getFieldCal->setTime(d, status);
+ failure(status, "getfieldCal->setTime");
+ int32_t ret = getFieldCal->get((UCalendarDateFields)f, status);
+ failure(status, "getfieldCal->get");
+ return ret;
+}
+
+UnicodeString& DateFormatRoundTripTest::escape(const UnicodeString& src, UnicodeString& dst )
+{
+ dst.remove();
+ for (int32_t i = 0; i < src.length(); ++i) {
+ UChar c = src[i];
+ if(c < 0x0080)
+ dst += c;
+ else {
+ dst += UnicodeString("[");
+ char buf [8];
+ sprintf(buf, "%#x", c);
+ dst += UnicodeString(buf);
+ dst += UnicodeString("]");
+ }
+ }
+
+ return dst;
+}
+
+#define U_MILLIS_PER_YEAR (365.25 * 24 * 60 * 60 * 1000)
+
+UDate DateFormatRoundTripTest::generateDate(UDate minDate)
+{
+ // Bring range in conformance to generateDate() below.
+ if(minDate < (U_MILLIS_PER_YEAR * -(4000-1970))) {
+ minDate = (U_MILLIS_PER_YEAR * -(4000-1970));
+ }
+ for(int i=0;i<8;i++) {
+ double a = randFraction();
+
+ // Range from (min) to (8000-1970) AD
+ double dateRange = (0.0 - minDate) + (U_MILLIS_PER_YEAR + (8000-1970));
+
+ a *= dateRange;
+
+ // Now offset from minDate
+ a += minDate;
+
+ // Last sanity check
+ if(a>=minDate) {
+ return a;
+ }
+ }
+ return minDate;
+}
+
+UDate DateFormatRoundTripTest::generateDate()
+{
+ double a = randFraction();
+
+ // Now 'a' ranges from 0..1; scale it to range from 0 to 8000 years
+ a *= 8000;
+
+ // Range from (4000-1970) BC to (8000-1970) AD
+ a -= 4000;
+
+ // Now scale up to ms
+ a *= 365.25 * 24 * 60 * 60 * 1000;
+
+ //return new Date((long)a);
+ return a;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtfmtrtts.h b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmtrtts.h
new file mode 100644
index 00000000000..1749d0e6826
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmtrtts.h
@@ -0,0 +1,96 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _DATEFORMATROUNDTRIPTEST_
+#define _DATEFORMATROUNDTRIPTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/calendar.h"
+#include "intltest.h"
+
+/**
+ * Performs round-trip tests for DateFormat
+ **/
+class DateFormatRoundTripTest : public IntlTest {
+
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+
+public:
+ DateFormatRoundTripTest();
+ virtual ~DateFormatRoundTripTest();
+
+ void TestDateFormatRoundTrip(void);
+ void TestCentury(void);
+ void test(const Locale& loc);
+ void test(DateFormat *fmt, const Locale &origLocale, UBool timeOnly = FALSE );
+ int32_t getField(UDate d, int32_t f);
+ UnicodeString& escape(const UnicodeString& src, UnicodeString& dst);
+ UDate generateDate(void);
+ UDate generateDate(UDate minDate);
+
+
+//============================================================
+// statics
+//============================================================
+
+/**
+ * Return a random uint32_t
+ **/
+static uint32_t randLong() {
+ // The portable IntlTest::random() function has sufficient
+ // resolution for a 16-bit value, but not for 32 bits.
+ return ((uint32_t) (IntlTest::random() * (1<<16))) |
+ (((uint32_t) (IntlTest::random() * (1<<16))) << 16);
+}
+
+/**
+ * Return a random double 0 <= x <= 1.0
+ **/
+static double randFraction()
+{
+ return (double)randLong() / (double)0xFFFFFFFF;
+}
+
+/**
+ * Return a random value from -range..+range (closed).
+ **/
+static double randDouble(double range)
+{
+ double a = randFraction();
+ //while(TPlatformUtilities::isInfinite(a) || TPlatformUtilities::isNaN(a))
+ // a = randFraction();
+ return (2.0 * range * a) - range;
+}
+
+protected:
+ UBool failure(UErrorCode status, const char* msg);
+ UBool failure(UErrorCode status, const char* msg, const UnicodeString& str);
+
+ const UnicodeString& fullFormat(UDate d);
+
+private:
+
+ static int32_t SPARSENESS;
+ static int32_t TRIALS;
+ static int32_t DEPTH;
+
+ UBool optionv; // TRUE if @v option is given on command line
+ SimpleDateFormat *dateFormat;
+ UnicodeString fgStr;
+ Calendar *getFieldCal;
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DATEFORMATROUNDTRIPTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtfmttst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmttst.cpp
new file mode 100644
index 00000000000..82e8018420c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmttst.cpp
@@ -0,0 +1,2937 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "dtfmttst.h"
+#include "unicode/timezone.h"
+#include "unicode/gregocal.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/datefmt.h"
+#include "unicode/simpletz.h"
+#include "unicode/strenum.h"
+#include "unicode/dtfmtsym.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "caltest.h" // for fieldName
+#include <stdio.h> // for sprintf
+
+#ifdef U_WINDOWS
+#include "windttst.h"
+#endif
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+#define ASSERT_OK(status) if(U_FAILURE(status)) {errln(#status " = %s @ %s:%d", u_errorName(status), __FILE__, __LINE__); return; }
+
+//--------------------------------------------------------------------
+// Time bomb - allows temporary behavior that expires at a given
+// release
+//--------------------------------------------------------------------
+static const UVersionInfo ICU_39 = {3,9,0,0};
+
+// *****************************************************************************
+// class DateFormatTest
+// *****************************************************************************
+
+void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite DateFormatTest");
+ switch (index) {
+ TESTCASE(0,TestEquals);
+ TESTCASE(1,TestTwoDigitYearDSTParse);
+ TESTCASE(2,TestFieldPosition);
+ TESTCASE(3,TestPartialParse994);
+ TESTCASE(4,TestRunTogetherPattern985);
+ TESTCASE(5,TestRunTogetherPattern917);
+ TESTCASE(6,TestCzechMonths459);
+ TESTCASE(7,TestLetterDPattern212);
+ TESTCASE(8,TestDayOfYearPattern195);
+ TESTCASE(9,TestQuotePattern161);
+ TESTCASE(10,TestBadInput135);
+ TESTCASE(11,TestBadInput135a);
+ TESTCASE(12,TestTwoDigitYear);
+ TESTCASE(13,TestDateFormatZone061);
+ TESTCASE(14,TestDateFormatZone146);
+ TESTCASE(15,TestLocaleDateFormat);
+ TESTCASE(16,TestWallyWedel);
+ TESTCASE(17,TestDateFormatCalendar);
+ TESTCASE(18,TestSpaceParsing);
+ TESTCASE(19,TestExactCountFormat);
+ TESTCASE(20,TestWhiteSpaceParsing);
+ TESTCASE(21,TestInvalidPattern);
+ TESTCASE(22,TestGeneral);
+ TESTCASE(23,TestGreekMay);
+ TESTCASE(24,TestGenericTime);
+ TESTCASE(25,TestGenericTimeZoneOrder);
+ TESTCASE(26,TestHost);
+ TESTCASE(27,TestEras);
+ TESTCASE(28,TestNarrowNames);
+ TESTCASE(29,TestStandAloneDays);
+ TESTCASE(30,TestStandAloneMonths);
+ TESTCASE(31,TestQuarters);
+ TESTCASE(32,TestZTimeZoneParsing);
+ TESTCASE(33,TestRelative);
+ TESTCASE(34,TestRelativeClone);
+ TESTCASE(35,TestHostClone);
+ TESTCASE(36,TestTimeZoneDisplayName);
+ /*
+ TESTCASE(37,TestRelativeError);
+ TESTCASE(38,TestRelativeOther);
+ */
+ default: name = ""; break;
+ }
+}
+
+// Test written by Wally Wedel and emailed to me.
+void DateFormatTest::TestWallyWedel()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ /*
+ * Instantiate a TimeZone so we can get the ids.
+ */
+ TimeZone *tz = new SimpleTimeZone(7,"");
+ /*
+ * Computational variables.
+ */
+ int32_t offset, hours, minutes, seconds;
+ /*
+ * Instantiate a SimpleDateFormat set up to produce a full time
+ zone name.
+ */
+ SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)"zzzz", status);
+ /*
+ * A String array for the time zone ids.
+ */
+ int32_t ids_length;
+ StringEnumeration* ids = TimeZone::createEnumeration();
+ ids_length = ids->count(status);
+ /*
+ * How many ids do we have?
+ */
+ logln("Time Zone IDs size: %d", ids_length);
+ /*
+ * Column headings (sort of)
+ */
+ logln("Ordinal ID offset(h:m) name");
+ /*
+ * Loop through the tzs.
+ */
+ UDate today = Calendar::getNow();
+ Calendar *cal = Calendar::createInstance(status);
+ for (int32_t i = 0; i < ids_length; i++) {
+ // logln(i + " " + ids[i]);
+ const UnicodeString* id = ids->snext(status);
+ TimeZone *ttz = TimeZone::createTimeZone(*id);
+ // offset = ttz.getRawOffset();
+ cal->setTimeZone(*ttz);
+ cal->setTime(today, status);
+ offset = cal->get(UCAL_ZONE_OFFSET, status) + cal->get(UCAL_DST_OFFSET, status);
+ // logln(i + " " + ids[i] + " offset " + offset);
+ const char* sign = "+";
+ if (offset < 0) {
+ sign = "-";
+ offset = -offset;
+ }
+ hours = offset/3600000;
+ minutes = (offset%3600000)/60000;
+ seconds = (offset%60000)/1000;
+ UnicodeString dstOffset = (UnicodeString)"" + sign + (hours < 10 ? "0" : "") +
+ (int32_t)hours + ":" + (minutes < 10 ? "0" : "") + (int32_t)minutes;
+ if (seconds != 0) {
+ dstOffset = dstOffset + ":" + (seconds < 10 ? "0" : "") + seconds;
+ }
+ /*
+ * Instantiate a date so we can display the time zone name.
+ */
+ sdf->setTimeZone(*ttz);
+ /*
+ * Format the output.
+ */
+ UnicodeString fmtOffset;
+ FieldPosition pos(0);
+ sdf->format(today,fmtOffset, pos);
+ // UnicodeString fmtOffset = tzS.toString();
+ UnicodeString *fmtDstOffset = 0;
+ if (fmtOffset.startsWith("GMT"))
+ {
+ //fmtDstOffset = fmtOffset->substring(3);
+ fmtDstOffset = new UnicodeString();
+ fmtOffset.extract(3, fmtOffset.length(), *fmtDstOffset);
+ }
+ /*
+ * Show our result.
+ */
+ UBool ok = fmtDstOffset == 0 || *fmtDstOffset == dstOffset;
+ if (ok)
+ {
+ logln(UnicodeString() + i + " " + *id + " " + dstOffset +
+ " " + fmtOffset +
+ (fmtDstOffset != 0 ? " ok" : " ?"));
+ }
+ else
+ {
+ errln(UnicodeString() + i + " " + *id + " " + dstOffset +
+ " " + fmtOffset + " *** FAIL ***");
+ }
+ delete ttz;
+ delete fmtDstOffset;
+ }
+ delete cal;
+ // delete ids; // TODO: BAD API
+ delete ids;
+ delete sdf;
+ delete tz;
+}
+
+// -------------------------------------
+
+/**
+ * Test operator==
+ */
+void
+DateFormatTest::TestEquals()
+{
+ DateFormat* fmtA = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL);
+ DateFormat* fmtB = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL);
+ if ( fmtA == NULL || fmtB == NULL){
+ dataerrln("Error calling DateFormat::createDateTimeInstance");
+ delete fmtA;
+ delete fmtB;
+ return;
+ }
+
+ if (!(*fmtA == *fmtB)) errln((UnicodeString)"FAIL");
+ delete fmtA;
+ delete fmtB;
+
+ TimeZone* test = TimeZone::createTimeZone("PDT");
+ delete test;
+}
+
+// -------------------------------------
+
+/**
+ * Test the parsing of 2-digit years.
+ */
+void
+DateFormatTest::TestTwoDigitYearDSTParse(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat* fullFmt = new SimpleDateFormat((UnicodeString)"EEE MMM dd HH:mm:ss.SSS zzz yyyy G", status);
+ SimpleDateFormat *fmt = new SimpleDateFormat((UnicodeString)"dd-MMM-yy h:mm:ss 'o''clock' a z", Locale::getEnglish(), status);
+ //DateFormat* fmt = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL, Locale::ENGLISH);
+ UnicodeString* s = new UnicodeString("03-Apr-04 2:20:47 o'clock AM PST", "");
+ TimeZone* defaultTZ = TimeZone::createDefault();
+ TimeZone* PST = TimeZone::createTimeZone("PST");
+ int32_t defaultOffset = defaultTZ->getRawOffset();
+ int32_t PSTOffset = PST->getRawOffset();
+ int32_t hour = 2 + (defaultOffset - PSTOffset) / (60*60*1000);
+ // hour is the expected hour of day, in units of seconds
+ hour = ((hour < 0) ? hour + 24 : hour) * 60*60;
+
+ UnicodeString str;
+
+ if(U_FAILURE(status)) {
+ errln("Could not set up test. exitting");
+ return;
+ }
+
+ UDate d = fmt->parse(*s, status);
+ logln(*s + " P> " + ((DateFormat*)fullFmt)->format(d, str));
+ int32_t y, m, day, hr, min, sec;
+ dateToFields(d, y, m, day, hr, min, sec);
+ hour += defaultTZ->inDaylightTime(d, status) ? 1 : 0;
+ hr = hr*60*60;
+ if (hr != hour)
+ errln((UnicodeString)"FAIL: Should parse to hour " + hour + " but got " + hr);
+
+ if (U_FAILURE(status))
+ errln((UnicodeString)"FAIL: " + (int32_t)status);
+
+ delete s;
+ delete fmt;
+ delete fullFmt;
+ delete PST;
+ delete defaultTZ;
+}
+
+// -------------------------------------
+
+UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
+
+UnicodeString&
+DateFormatTest::escape(UnicodeString& s)
+{
+ UnicodeString buf;
+ for (int32_t i=0; i<s.length(); ++i)
+ {
+ UChar c = s[(int32_t)i];
+ if (c <= (UChar)0x7F) buf += c;
+ else {
+ buf += (UChar)0x5c; buf += (UChar)0x55;
+ buf += toHexString((c & 0xF000) >> 12);
+ buf += toHexString((c & 0x0F00) >> 8);
+ buf += toHexString((c & 0x00F0) >> 4);
+ buf += toHexString(c & 0x000F);
+ }
+ }
+ return (s = buf);
+}
+
+// -------------------------------------
+
+/**
+ * This MUST be kept in sync with DateFormatSymbols.gPatternChars.
+ */
+static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqV";
+
+/**
+ * A list of the names of all the fields in DateFormat.
+ * This MUST be kept in sync with DateFormat.
+ */
+static const char* DATEFORMAT_FIELD_NAMES[] = {
+ "ERA_FIELD",
+ "YEAR_FIELD",
+ "MONTH_FIELD",
+ "DATE_FIELD",
+ "HOUR_OF_DAY1_FIELD",
+ "HOUR_OF_DAY0_FIELD",
+ "MINUTE_FIELD",
+ "SECOND_FIELD",
+ "MILLISECOND_FIELD",
+ "DAY_OF_WEEK_FIELD",
+ "DAY_OF_YEAR_FIELD",
+ "DAY_OF_WEEK_IN_MONTH_FIELD",
+ "WEEK_OF_YEAR_FIELD",
+ "WEEK_OF_MONTH_FIELD",
+ "AM_PM_FIELD",
+ "HOUR1_FIELD",
+ "HOUR0_FIELD",
+ "TIMEZONE_FIELD",
+ "YEAR_WOY_FIELD",
+ "DOW_LOCAL_FIELD",
+ "EXTENDED_YEAR_FIELD",
+ "JULIAN_DAY_FIELD",
+ "MILLISECONDS_IN_DAY_FIELD",
+ "TIMEZONE_RFC_FIELD",
+ "GENERIC_TIMEZONE_FIELD",
+ "STAND_ALONE_DAY_FIELD",
+ "STAND_ALONE_MONTH_FIELD",
+ "QUARTER_FIELD",
+ "STAND_ALONE_QUARTER_FIELD",
+ "TIMEZONE_SPECIAL_FIELD"
+};
+
+static const int32_t DATEFORMAT_FIELD_NAMES_LENGTH =
+ sizeof(DATEFORMAT_FIELD_NAMES) / sizeof(DATEFORMAT_FIELD_NAMES[0]);
+
+/**
+ * Verify that returned field position indices are correct.
+ */
+void DateFormatTest::TestFieldPosition() {
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t i, j, exp;
+ UnicodeString buf;
+
+ // Verify data
+ DateFormatSymbols rootSyms(Locale(""), ec);
+ assertSuccess("DateFormatSymbols", ec);
+
+ // local pattern chars data is not longer loaded
+ // from icu locale bundle
+ assertEquals("patternChars", PATTERN_CHARS, rootSyms.getLocalPatternChars(buf));
+ assertEquals("patternChars", PATTERN_CHARS, DateFormatSymbols::getPatternUChars());
+ assertTrue("DATEFORMAT_FIELD_NAMES", DATEFORMAT_FIELD_NAMES_LENGTH == UDAT_FIELD_COUNT);
+ assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS));
+
+ // Create test formatters
+ const int32_t COUNT = 4;
+ DateFormat* dateFormats[COUNT];
+ dateFormats[0] = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale::getUS());
+ dateFormats[1] = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale::getFrance());
+ // Make the pattern "G y M d..."
+ buf.remove().append(PATTERN_CHARS);
+ for (j=buf.length()-1; j>=0; --j) buf.insert(j, (UChar)32/*' '*/);
+ dateFormats[2] = new SimpleDateFormat(buf, Locale::getUS(), ec);
+ // Make the pattern "GGGG yyyy MMMM dddd..."
+ for (j=buf.length()-1; j>=0; j-=2) {
+ for (i=0; i<3; ++i) {
+ buf.insert(j, buf.charAt(j));
+ }
+ }
+ dateFormats[3] = new SimpleDateFormat(buf, Locale::getUS(), ec);
+ if(U_FAILURE(ec)){
+ errln(UnicodeString("Could not create SimpleDateFormat object for locale en_US. Error: " )+ UnicodeString(u_errorName(ec)));
+ return;
+ }
+ UDate aug13 = 871508052513.0;
+
+ // Expected output field values for above DateFormats on aug13
+ // Fields are given in order of DateFormat field number
+ const char* EXPECTED[] = {
+ "", "1997", "August", "13", "", "", "34", "12", "",
+ "Wednesday", "", "", "", "", "PM", "2", "", "", "", "", "", "", "", "", "PT", "", "", "", "","",
+
+ "", "1997", "ao\\u00FBt", "13", "", "14", "34", "12", "",
+ "mercredi", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "\\u00C9tats-Unis (Los Angeles)", "", "", "", "", "",
+
+ "AD", "1997", "8", "13", "14", "14", "34", "12", "5",
+ "Wed", "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4", "1997", "2450674", "52452513", "-0700", "PT", "4", "8", "3", "3","PDT",
+
+ "Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130",
+ "Wednesday", "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "0004", "1997", "2450674", "52452513", "GMT-07:00",
+ "Pacific Time", "Wednesday", "August", "3rd quarter", "3rd quarter", "United States (Los Angeles)"
+ };
+
+ const int32_t EXPECTED_LENGTH = sizeof(EXPECTED)/sizeof(EXPECTED[0]);
+
+ assertTrue("data size", EXPECTED_LENGTH == COUNT * UDAT_FIELD_COUNT);
+
+ TimeZone* PT = TimeZone::createTimeZone("America/Los_Angeles");
+ for (j = 0, exp = 0; j < COUNT; ++j) {
+ // String str;
+ DateFormat* df = dateFormats[j];
+ df->setTimeZone(*PT);
+ if (df->getDynamicClassID() == SimpleDateFormat::getStaticClassID()) {
+ logln(" Pattern = " + ((SimpleDateFormat*) df)->toPattern(buf.remove()));
+ } else {
+ logln(" Pattern = ? (not a SimpleDateFormat)");
+ }
+ logln((UnicodeString)" Result = " + df->format(aug13, buf.remove()));
+
+ for (i = 0; i < UDAT_FIELD_COUNT; ++i, ++exp) {
+ FieldPosition pos(i);
+ buf.remove();
+ df->format(aug13, buf, pos);
+ UnicodeString field;
+ buf.extractBetween(pos.getBeginIndex(), pos.getEndIndex(), field);
+ assertEquals((UnicodeString)"field #" + i + " " + DATEFORMAT_FIELD_NAMES[i],
+ ctou(EXPECTED[exp]), field);
+ }
+ }
+
+ for (i=0; i<COUNT; ++i) {
+ delete dateFormats[i];
+ }
+ delete PT;
+}
+
+// -------------------------------------
+
+/**
+ * General parse/format tests. Add test cases as needed.
+ */
+void DateFormatTest::TestGeneral() {
+ const char* DATA[] = {
+ "yyyy MM dd HH:mm:ss.SSS",
+
+ // Milliseconds are left-justified, since they format as fractions of a second
+ "y/M/d H:mm:ss.S", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.6", "2004 03 10 16:36:31.600",
+ "y/M/d H:mm:ss.SS", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.57", "2004 03 10 16:36:31.570",
+ "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567",
+ "y/M/d H:mm:ss.SSSS", "pf", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.568", "2004/3/10 16:36:31.5680",
+ };
+ expect(DATA, ARRAY_SIZE(DATA), Locale("en", "", ""));
+}
+
+// -------------------------------------
+
+/**
+ * Verify that strings which contain incomplete specifications are parsed
+ * correctly. In some instances, this means not being parsed at all, and
+ * returning an appropriate error.
+ */
+void
+DateFormatTest::TestPartialParse994()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat* f = new SimpleDateFormat(status);
+ ASSERT_OK(status);
+ UDate null = 0;
+ tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:11:42", date(97, 1 - 1, 17, 10, 11, 42));
+ tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:", null);
+ tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10", null);
+ tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 ", null);
+ tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17", null);
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
+ delete f;
+}
+
+// -------------------------------------
+
+void
+DateFormatTest::tryPat994(SimpleDateFormat* format, const char* pat, const char* str, UDate expected)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UDate null = 0;
+ logln(UnicodeString("Pattern \"") + pat + "\" String \"" + str + "\"");
+ //try {
+ format->applyPattern(pat);
+ UDate date = format->parse(str, status);
+ if (U_FAILURE(status) || date == null)
+ {
+ logln((UnicodeString)"ParseException: " + (int32_t)status);
+ if (expected != null) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
+ }
+ else
+ {
+ UnicodeString f;
+ ((DateFormat*)format)->format(date, f);
+ logln(UnicodeString(" parse(") + str + ") -> " + dateToString(date));
+ logln((UnicodeString)" format -> " + f);
+ if (expected == null ||
+ !(date == expected)) errln((UnicodeString)"FAIL: Expected null");//" + expected);
+ if (!(f == str)) errln(UnicodeString("FAIL: Expected ") + str);
+ }
+ //}
+ //catch(ParseException e) {
+ // logln((UnicodeString)"ParseException: " + e.getMessage());
+ // if (expected != null) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
+ //}
+ //catch(Exception e) {
+ // errln((UnicodeString)"*** Exception:");
+ // e.printStackTrace();
+ //}
+}
+
+// -------------------------------------
+
+/**
+ * Verify the behavior of patterns in which digits for different fields run together
+ * without intervening separators.
+ */
+void
+DateFormatTest::TestRunTogetherPattern985()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString format("yyyyMMddHHmmssSSS");
+ UnicodeString now, then;
+ //UBool flag;
+ SimpleDateFormat *formatter = new SimpleDateFormat(format, status);
+ ASSERT_OK(status);
+ UDate date1 = Calendar::getNow();
+ ((DateFormat*)formatter)->format(date1, now);
+ logln(now);
+ ParsePosition pos(0);
+ UDate date2 = formatter->parse(now, pos);
+ if (date2 == 0) then = "Parse stopped at " + pos.getIndex();
+ else ((DateFormat*)formatter)->format(date2, then);
+ logln(then);
+ if (!(date2 == date1)) errln((UnicodeString)"FAIL");
+ delete formatter;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
+}
+
+// -------------------------------------
+
+/**
+ * Verify the behavior of patterns in which digits for different fields run together
+ * without intervening separators.
+ */
+void
+DateFormatTest::TestRunTogetherPattern917()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat* fmt;
+ UnicodeString myDate;
+ fmt = new SimpleDateFormat((UnicodeString)"yyyy/MM/dd", status);
+ ASSERT_OK(status);
+ myDate = "1997/02/03";
+ testIt917(fmt, myDate, date(97, 2 - 1, 3));
+ delete fmt;
+ fmt = new SimpleDateFormat((UnicodeString)"yyyyMMdd", status);
+ myDate = "19970304";
+ testIt917(fmt, myDate, date(97, 3 - 1, 4));
+ delete fmt;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
+}
+
+// -------------------------------------
+
+void
+DateFormatTest::testIt917(SimpleDateFormat* fmt, UnicodeString& str, UDate expected)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern;
+ logln((UnicodeString)"pattern=" + fmt->toPattern(pattern) + " string=" + str);
+ Formattable o;
+ //try {
+ ((Format*)fmt)->parseObject(str, o, status);
+ //}
+ if (U_FAILURE(status)) return;
+ //catch(ParseException e) {
+ // e.printStackTrace();
+ // return;
+ //}
+ logln((UnicodeString)"Parsed object: " + dateToString(o.getDate()));
+ if (!(o.getDate() == expected)) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
+ UnicodeString formatted; ((Format*)fmt)->format(o, formatted, status);
+ logln((UnicodeString)"Formatted string: " + formatted);
+ if (!(formatted == str)) errln((UnicodeString)"FAIL: Expected " + str);
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
+}
+
+// -------------------------------------
+
+/**
+ * Verify the handling of Czech June and July, which have the unique attribute that
+ * one is a proper prefix substring of the other.
+ */
+void
+DateFormatTest::TestCzechMonths459()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormat* fmt = DateFormat::createDateInstance(DateFormat::FULL, Locale("cs", "", ""));
+ if (fmt == NULL){
+ dataerrln("Error calling DateFormat::createDateInstance()");
+ return;
+ }
+
+ UnicodeString pattern;
+ logln((UnicodeString)"Pattern " + ((SimpleDateFormat*) fmt)->toPattern(pattern));
+ UDate june = date(97, UCAL_JUNE, 15);
+ UDate july = date(97, UCAL_JULY, 15);
+ UnicodeString juneStr; fmt->format(june, juneStr);
+ UnicodeString julyStr; fmt->format(july, julyStr);
+ //try {
+ logln((UnicodeString)"format(June 15 1997) = " + juneStr);
+ UDate d = fmt->parse(juneStr, status);
+ UnicodeString s; fmt->format(d, s);
+ int32_t month,yr,day,hr,min,sec; dateToFields(d,yr,month,day,hr,min,sec);
+ logln((UnicodeString)" -> parse -> " + s + " (month = " + month + ")");
+ if (month != UCAL_JUNE) errln((UnicodeString)"FAIL: Month should be June");
+ logln((UnicodeString)"format(July 15 1997) = " + julyStr);
+ d = fmt->parse(julyStr, status);
+ fmt->format(d, s);
+ dateToFields(d,yr,month,day,hr,min,sec);
+ logln((UnicodeString)" -> parse -> " + s + " (month = " + month + ")");
+ if (month != UCAL_JULY) errln((UnicodeString)"FAIL: Month should be July");
+ //}
+ //catch(ParseException e) {
+ if (U_FAILURE(status))
+ errln((UnicodeString)"Exception: " + (int32_t)status);
+ //}
+ delete fmt;
+}
+
+// -------------------------------------
+
+/**
+ * Test the handling of 'D' in patterns.
+ */
+void
+DateFormatTest::TestLetterDPattern212()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString dateString("1995-040.05:01:29");
+ UnicodeString bigD("yyyy-DDD.hh:mm:ss");
+ UnicodeString littleD("yyyy-ddd.hh:mm:ss");
+ UDate expLittleD = date(95, 0, 1, 5, 1, 29);
+ UDate expBigD = expLittleD + 39 * 24 * 3600000.0;
+ expLittleD = expBigD; // Expect the same, with default lenient parsing
+ logln((UnicodeString)"dateString= " + dateString);
+ SimpleDateFormat *formatter = new SimpleDateFormat(bigD, status);
+ ASSERT_OK(status);
+ ParsePosition pos(0);
+ UDate myDate = formatter->parse(dateString, pos);
+ logln((UnicodeString)"Using " + bigD + " -> " + myDate);
+ if (myDate != expBigD) errln((UnicodeString)"FAIL: Expected " + dateToString(expBigD));
+ delete formatter;
+ formatter = new SimpleDateFormat(littleD, status);
+ ASSERT_OK(status);
+ pos = ParsePosition(0);
+ myDate = formatter->parse(dateString, pos);
+ logln((UnicodeString)"Using " + littleD + " -> " + dateToString(myDate));
+ if (myDate != expLittleD) errln((UnicodeString)"FAIL: Expected " + dateToString(expLittleD));
+ delete formatter;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
+}
+
+// -------------------------------------
+
+/**
+ * Test the day of year pattern.
+ */
+void
+DateFormatTest::TestDayOfYearPattern195()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UDate today = Calendar::getNow();
+ int32_t year,month,day,hour,min,sec; dateToFields(today,year,month,day,hour,min,sec);
+ UDate expected = date(year, month, day);
+ logln((UnicodeString)"Test Date: " + dateToString(today));
+ SimpleDateFormat* sdf = (SimpleDateFormat*)DateFormat::createDateInstance();
+ if (sdf == NULL){
+ dataerrln("Error calling DateFormat::createDateInstance()");
+ return;
+ }
+ tryPattern(*sdf, today, 0, expected);
+ tryPattern(*sdf, today, "G yyyy DDD", expected);
+ delete sdf;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
+}
+
+// -------------------------------------
+
+void
+DateFormatTest::tryPattern(SimpleDateFormat& sdf, UDate d, const char* pattern, UDate expected)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ if (pattern != 0) sdf.applyPattern(pattern);
+ UnicodeString thePat;
+ logln((UnicodeString)"pattern: " + sdf.toPattern(thePat));
+ UnicodeString formatResult; (*(DateFormat*)&sdf).format(d, formatResult);
+ logln((UnicodeString)" format -> " + formatResult);
+ // try {
+ UDate d2 = sdf.parse(formatResult, status);
+ logln((UnicodeString)" parse(" + formatResult + ") -> " + dateToString(d2));
+ if (d2 != expected) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
+ UnicodeString format2; (*(DateFormat*)&sdf).format(d2, format2);
+ logln((UnicodeString)" format -> " + format2);
+ if (!(formatResult == format2)) errln((UnicodeString)"FAIL: Round trip drift");
+ //}
+ //catch(Exception e) {
+ if (U_FAILURE(status))
+ errln((UnicodeString)"Error: " + (int32_t)status);
+ //}
+}
+
+// -------------------------------------
+
+/**
+ * Test the handling of single quotes in patterns.
+ */
+void
+DateFormatTest::TestQuotePattern161()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat* formatter = new SimpleDateFormat((UnicodeString)"MM/dd/yyyy 'at' hh:mm:ss a zzz", status);
+ ASSERT_OK(status);
+ UDate currentTime_1 = date(97, UCAL_AUGUST, 13, 10, 42, 28);
+ UnicodeString dateString; ((DateFormat*)formatter)->format(currentTime_1, dateString);
+ UnicodeString exp("08/13/1997 at 10:42:28 AM ");
+ logln((UnicodeString)"format(" + dateToString(currentTime_1) + ") = " + dateString);
+ if (0 != dateString.compareBetween(0, exp.length(), exp, 0, exp.length())) errln((UnicodeString)"FAIL: Expected " + exp);
+ delete formatter;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
+}
+
+// -------------------------------------
+
+/**
+ * Verify the correct behavior when handling invalid input strings.
+ */
+void
+DateFormatTest::TestBadInput135()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormat::EStyle looks[] = {
+ DateFormat::SHORT, DateFormat::MEDIUM, DateFormat::LONG, DateFormat::FULL
+ };
+ int32_t looks_length = (int32_t)(sizeof(looks) / sizeof(looks[0]));
+ const char* strings[] = {
+ "Mar 15", "Mar 15 1997", "asdf", "3/1/97 1:23:", "3/1/00 1:23:45 AM"
+ };
+ int32_t strings_length = (int32_t)(sizeof(strings) / sizeof(strings[0]));
+ DateFormat *full = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::LONG);
+ if(full==NULL) {
+ errln("could not create date time instance");
+ return;
+ }
+ UnicodeString expected("March 1, 2000 1:23:45 AM ");
+ for (int32_t i = 0; i < strings_length;++i) {
+ const char* text = strings[i];
+ for (int32_t j = 0; j < looks_length;++j) {
+ DateFormat::EStyle dateLook = looks[j];
+ for (int32_t k = 0; k < looks_length;++k) {
+ DateFormat::EStyle timeLook = looks[k];
+ DateFormat *df = DateFormat::createDateTimeInstance(dateLook, timeLook);
+ if (df == NULL){
+ dataerrln("Error calling DateFormat::createDateTimeInstance()");
+ continue;
+ }
+ UnicodeString prefix = UnicodeString(text) + ", " + dateLook + "/" + timeLook + ": ";
+ //try {
+ UDate when = df->parse(text, status);
+ if (when == 0 && U_SUCCESS(status)) {
+ errln(prefix + "SHOULD NOT HAPPEN: parse returned 0.");
+ continue;
+ }
+ if (U_SUCCESS(status))
+ {
+ UnicodeString format;
+ full->format(when, format);
+ logln(prefix + "OK: " + format);
+ if (0!=format.compareBetween(0, expected.length(), expected, 0, expected.length()))
+ errln((UnicodeString)"FAIL: Expected " + expected + " got " + format);
+ }
+ //}
+ //catch(ParseException e) {
+ else
+ status = U_ZERO_ERROR;
+ //}
+ //catch(StringIndexOutOfBoundsException e) {
+ // errln(prefix + "SHOULD NOT HAPPEN: " + (int)status);
+ //}
+ delete df;
+ }
+ }
+ }
+ delete full;
+ if (U_FAILURE(status))
+ errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
+}
+
+static const char* const parseFormats[] = {
+ "MMMM d, yyyy",
+ "MMMM d yyyy",
+ "M/d/yy",
+ "d MMMM, yyyy",
+ "d MMMM yyyy",
+ "d MMMM",
+ "MMMM d",
+ "yyyy",
+ "h:mm a MMMM d, yyyy"
+};
+
+static const char* const inputStrings[] = {
+ "bogus string", 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ "April 1, 1997", "April 1, 1997", 0, 0, 0, 0, 0, "April 1", 0, 0,
+ "Jan 1, 1970", "January 1, 1970", 0, 0, 0, 0, 0, "January 1", 0, 0,
+ "Jan 1 2037", 0, "January 1 2037", 0, 0, 0, 0, "January 1", 0, 0,
+ "1/1/70", 0, 0, "1/1/70", 0, 0, 0, 0, "0001", 0,
+ "5 May 1997", 0, 0, 0, 0, "5 May 1997", "5 May", 0, "0005", 0,
+ "16 May", 0, 0, 0, 0, 0, "16 May", 0, "0016", 0,
+ "April 30", 0, 0, 0, 0, 0, 0, "April 30", 0, 0,
+ "1998", 0, 0, 0, 0, 0, 0, 0, "1998", 0,
+ "1", 0, 0, 0, 0, 0, 0, 0, "0001", 0,
+ "3:00 pm Jan 1, 1997", 0, 0, 0, 0, 0, 0, 0, "0003", "3:00 PM January 1, 1997",
+};
+
+// -------------------------------------
+
+/**
+ * Verify the correct behavior when parsing an array of inputs against an
+ * array of patterns, with known results. The results are encoded after
+ * the input strings in each row.
+ */
+void
+DateFormatTest::TestBadInput135a()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat* dateParse = new SimpleDateFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Failed creating SimpleDateFormat with %s. Quitting test", u_errorName(status));
+ delete dateParse;
+ return;
+ }
+ const char* s;
+ UDate date;
+ const uint32_t PF_LENGTH = (int32_t)(sizeof(parseFormats)/sizeof(parseFormats[0]));
+ const uint32_t INPUT_LENGTH = (int32_t)(sizeof(inputStrings)/sizeof(inputStrings[0]));
+
+ dateParse->applyPattern("d MMMM, yyyy");
+ dateParse->adoptTimeZone(TimeZone::createDefault());
+ s = "not parseable";
+ UnicodeString thePat;
+ logln(UnicodeString("Trying to parse \"") + s + "\" with " + dateParse->toPattern(thePat));
+ //try {
+ date = dateParse->parse(s, status);
+ if (U_SUCCESS(status))
+ errln((UnicodeString)"FAIL: Expected exception during parse");
+ //}
+ //catch(Exception ex) {
+ else
+ logln((UnicodeString)"Exception during parse: " + (int32_t)status);
+ status = U_ZERO_ERROR;
+ //}
+ for (uint32_t i = 0; i < INPUT_LENGTH; i += (PF_LENGTH + 1)) {
+ ParsePosition parsePosition(0);
+ UnicodeString s( inputStrings[i]);
+ for (uint32_t index = 0; index < PF_LENGTH;++index) {
+ const char* expected = inputStrings[i + 1 + index];
+ dateParse->applyPattern(parseFormats[index]);
+ dateParse->adoptTimeZone(TimeZone::createDefault());
+ //try {
+ parsePosition.setIndex(0);
+ date = dateParse->parse(s, parsePosition);
+ if (parsePosition.getIndex() != 0) {
+ UnicodeString s1, s2;
+ s.extract(0, parsePosition.getIndex(), s1);
+ s.extract(parsePosition.getIndex(), s.length(), s2);
+ if (date == 0) {
+ errln((UnicodeString)"ERROR: null result fmt=\"" +
+ parseFormats[index] +
+ "\" pos=" + parsePosition.getIndex() + " " +
+ s1 + "|" + s2);
+ }
+ else {
+ UnicodeString result;
+ ((DateFormat*)dateParse)->format(date, result);
+ logln((UnicodeString)"Parsed \"" + s + "\" using \"" + dateParse->toPattern(thePat) + "\" to: " + result);
+ if (expected == 0)
+ errln((UnicodeString)"FAIL: Expected parse failure");
+ else if (!(result == expected))
+ errln(UnicodeString("FAIL: Expected ") + expected);
+ }
+ }
+ else if (expected != 0) {
+ errln(UnicodeString("FAIL: Expected ") + expected + " from \"" +
+ s + "\" with \"" + dateParse->toPattern(thePat) + "\"");
+ }
+ //}
+ //catch(Exception ex) {
+ if (U_FAILURE(status))
+ errln((UnicodeString)"An exception was thrown during parse: " + (int32_t)status);
+ //}
+ }
+ }
+ delete dateParse;
+ if (U_FAILURE(status))
+ errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
+}
+
+// -------------------------------------
+
+/**
+ * Test the parsing of two-digit years.
+ */
+void
+DateFormatTest::TestTwoDigitYear()
+{
+ UErrorCode ec = U_ZERO_ERROR;
+ SimpleDateFormat fmt("dd/MM/yy", Locale::getUK(), ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: SimpleDateFormat constructor");
+ return;
+ }
+ parse2DigitYear(fmt, "5/6/17", date(117, UCAL_JUNE, 5));
+ parse2DigitYear(fmt, "4/6/34", date(34, UCAL_JUNE, 4));
+}
+
+// -------------------------------------
+
+void
+DateFormatTest::parse2DigitYear(DateFormat& fmt, const char* str, UDate expected)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ //try {
+ UDate d = fmt.parse(str, status);
+ UnicodeString thePat;
+ logln(UnicodeString("Parsing \"") + str + "\" with " + ((SimpleDateFormat*)&fmt)->toPattern(thePat) +
+ " => " + dateToString(d));
+ if (d != expected) errln((UnicodeString)"FAIL: Expected " + expected);
+ //}
+ //catch(ParseException e) {
+ if (U_FAILURE(status))
+ errln((UnicodeString)"FAIL: Got exception");
+ //}
+}
+
+// -------------------------------------
+
+/**
+ * Test the formatting of time zones.
+ */
+void
+DateFormatTest::TestDateFormatZone061()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UDate date;
+ DateFormat *formatter;
+ date= 859248000000.0;
+ logln((UnicodeString)"Date 1997/3/25 00:00 GMT: " + date);
+ formatter = new SimpleDateFormat((UnicodeString)"dd-MMM-yyyyy HH:mm", Locale::getUK(), status);
+ if(U_FAILURE(status)) {
+ errln("Failed creating SimpleDateFormat with %s. Quitting test", u_errorName(status));
+ delete formatter;
+ return;
+ }
+ formatter->adoptTimeZone(TimeZone::createTimeZone("GMT"));
+ UnicodeString temp; formatter->format(date, temp);
+ logln((UnicodeString)"Formatted in GMT to: " + temp);
+ //try {
+ UDate tempDate = formatter->parse(temp, status);
+ logln((UnicodeString)"Parsed to: " + dateToString(tempDate));
+ if (tempDate != date) errln((UnicodeString)"FAIL: Expected " + dateToString(date));
+ //}
+ //catch(Throwable t) {
+ if (U_FAILURE(status))
+ errln((UnicodeString)"Date Formatter throws: " + (int32_t)status);
+ //}
+ delete formatter;
+}
+
+// -------------------------------------
+
+/**
+ * Test the formatting of time zones.
+ */
+void
+DateFormatTest::TestDateFormatZone146()
+{
+ TimeZone *saveDefault = TimeZone::createDefault();
+
+ //try {
+ TimeZone *thedefault = TimeZone::createTimeZone("GMT");
+ TimeZone::setDefault(*thedefault);
+ // java.util.Locale.setDefault(new java.util.Locale("ar", "", ""));
+
+ // check to be sure... its GMT all right
+ TimeZone *testdefault = TimeZone::createDefault();
+ UnicodeString testtimezone;
+ testdefault->getID(testtimezone);
+ if (testtimezone == "GMT")
+ logln("Test timezone = " + testtimezone);
+ else
+ errln("Test timezone should be GMT, not " + testtimezone);
+
+ UErrorCode status = U_ZERO_ERROR;
+ // now try to use the default GMT time zone
+ GregorianCalendar *greenwichcalendar =
+ new GregorianCalendar(1997, 3, 4, 23, 0, status);
+ failure(status, "new GregorianCalendar");
+ //*****************************greenwichcalendar.setTimeZone(TimeZone.getDefault());
+ //greenwichcalendar.set(1997, 3, 4, 23, 0);
+ // try anything to set hour to 23:00 !!!
+ greenwichcalendar->set(UCAL_HOUR_OF_DAY, 23);
+ // get time
+ UDate greenwichdate = greenwichcalendar->getTime(status);
+ // format every way
+ UnicodeString DATA [] = {
+ UnicodeString("simple format: "), UnicodeString("04/04/97 23:00 GMT+00:00"),
+ UnicodeString("MM/dd/yy HH:mm z"),
+ UnicodeString("full format: "), UnicodeString("Friday, April 4, 1997 11:00:00 o'clock PM GMT+00:00"),
+ UnicodeString("EEEE, MMMM d, yyyy h:mm:ss 'o''clock' a z"),
+ UnicodeString("long format: "), UnicodeString("April 4, 1997 11:00:00 PM GMT+00:00"),
+ UnicodeString("MMMM d, yyyy h:mm:ss a z"),
+ UnicodeString("default format: "), UnicodeString("04-Apr-97 11:00:00 PM"),
+ UnicodeString("dd-MMM-yy h:mm:ss a"),
+ UnicodeString("short format: "), UnicodeString("4/4/97 11:00 PM"),
+ UnicodeString("M/d/yy h:mm a")
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ DateFormat *fmt = new SimpleDateFormat(DATA[i+2], Locale::getEnglish(), status);
+ if(failure(status, "new SimpleDateFormat")) break;
+ fmt->setCalendar(*greenwichcalendar);
+ UnicodeString result;
+ result = fmt->format(greenwichdate, result);
+ logln(DATA[i] + result);
+ if (result != DATA[i+1])
+ errln("FAIL: Expected " + DATA[i+1] + ", got " + result);
+ delete fmt;
+ }
+ //}
+ //finally {
+ TimeZone::adoptDefault(saveDefault);
+ //}
+ delete testdefault;
+ delete greenwichcalendar;
+ delete thedefault;
+
+
+}
+
+// -------------------------------------
+
+/**
+ * Test the formatting of dates in different locales.
+ */
+void
+DateFormatTest::TestLocaleDateFormat() // Bug 495
+{
+ UDate testDate = date(97, UCAL_SEPTEMBER, 15);
+ DateFormat *dfFrench = DateFormat::createDateTimeInstance(DateFormat::FULL,
+ DateFormat::FULL, Locale::getFrench());
+ DateFormat *dfUS = DateFormat::createDateTimeInstance(DateFormat::FULL,
+ DateFormat::FULL, Locale::getUS());
+ UnicodeString expectedFRENCH ( "lundi 15 septembre 1997 00:00:00 \\u00C9tats-Unis (Los Angeles)" );
+ expectedFRENCH = expectedFRENCH.unescape();
+ //UnicodeString expectedUS ( "Monday, September 15, 1997 12:00:00 o'clock AM PDT" );
+ UnicodeString expectedUS ( "Monday, September 15, 1997 12:00:00 AM PT" );
+ logln((UnicodeString)"Date set to : " + dateToString(testDate));
+ UnicodeString out;
+ if (dfUS == NULL || dfFrench == NULL){
+ dataerrln("Error calling DateFormat::createDateTimeInstance)");
+ delete dfUS;
+ delete dfFrench;
+ return;
+ }
+
+ dfFrench->format(testDate, out);
+ logln((UnicodeString)"Date Formated with French Locale " + out);
+ if (!(out == expectedFRENCH))
+ errln((UnicodeString)"FAIL: Expected " + expectedFRENCH);
+ out.truncate(0);
+ dfUS->format(testDate, out);
+ logln((UnicodeString)"Date Formated with US Locale " + out);
+ if (!(out == expectedUS))
+ errln((UnicodeString)"FAIL: Expected " + expectedUS);
+ delete dfUS;
+ delete dfFrench;
+}
+
+/**
+ * Test DateFormat(Calendar) API
+ */
+void DateFormatTest::TestDateFormatCalendar() {
+ DateFormat *date=0, *time=0, *full=0;
+ Calendar *cal=0;
+ UnicodeString str;
+ ParsePosition pos;
+ UDate when;
+ UErrorCode ec = U_ZERO_ERROR;
+
+ /* Create a formatter for date fields. */
+ date = DateFormat::createDateInstance(DateFormat::kShort, Locale::getUS());
+ if (date == NULL) {
+ errln("FAIL: createDateInstance failed");
+ goto FAIL;
+ }
+
+ /* Create a formatter for time fields. */
+ time = DateFormat::createTimeInstance(DateFormat::kShort, Locale::getUS());
+ if (time == NULL) {
+ errln("FAIL: createTimeInstance failed");
+ goto FAIL;
+ }
+
+ /* Create a full format for output */
+ full = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull,
+ Locale::getUS());
+ if (full == NULL) {
+ errln("FAIL: createInstance failed");
+ goto FAIL;
+ }
+
+ /* Create a calendar */
+ cal = Calendar::createInstance(Locale::getUS(), ec);
+ if (cal == NULL || U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: Calendar::createInstance failed with " +
+ u_errorName(ec));
+ goto FAIL;
+ }
+
+ /* Parse the date */
+ cal->clear();
+ str = UnicodeString("4/5/2001", "");
+ pos.setIndex(0);
+ date->parse(str, *cal, pos);
+ if (pos.getIndex() != str.length()) {
+ errln((UnicodeString)"FAIL: DateFormat::parse(4/5/2001) failed at " +
+ pos.getIndex());
+ goto FAIL;
+ }
+
+ /* Parse the time */
+ str = UnicodeString("5:45 PM", "");
+ pos.setIndex(0);
+ time->parse(str, *cal, pos);
+ if (pos.getIndex() != str.length()) {
+ errln((UnicodeString)"FAIL: DateFormat::parse(17:45) failed at " +
+ pos.getIndex());
+ goto FAIL;
+ }
+
+ /* Check result */
+ when = cal->getTime(ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: cal->getTime() failed with " + u_errorName(ec));
+ goto FAIL;
+ }
+ str.truncate(0);
+ full->format(when, str);
+ // Thursday, April 5, 2001 5:45:00 PM PDT 986517900000
+ if (when == 986517900000.0) {
+ logln("Ok: Parsed result: " + str);
+ } else {
+ errln("FAIL: Parsed result: " + str + ", exp 4/5/2001 5:45 PM");
+ }
+
+ FAIL:
+ delete date;
+ delete time;
+ delete full;
+ delete cal;
+}
+
+/**
+ * Test DateFormat's parsing of space characters. See jitterbug 1916.
+ */
+void DateFormatTest::TestSpaceParsing() {
+ const char* DATA[] = {
+ "yyyy MM dd HH:mm:ss",
+
+ // pattern, input, expected parse or NULL if expect parse failure
+ "MMMM d yy", " 04 05 06", NULL, // MMMM wants Apr/April
+ NULL, "04 05 06", NULL,
+ "MM d yy", " 04 05 06", "2006 04 05 00:00:00",
+ NULL, "04 05 06", "2006 04 05 00:00:00",
+ "MMMM d yy", " Apr 05 06", "2006 04 05 00:00:00",
+ NULL, "Apr 05 06", "2006 04 05 00:00:00",
+ };
+ const int32_t DATA_len = sizeof(DATA)/sizeof(DATA[0]);
+
+ expectParse(DATA, DATA_len, Locale("en"));
+}
+
+/**
+ * Test handling of "HHmmss" pattern.
+ */
+void DateFormatTest::TestExactCountFormat() {
+ const char* DATA[] = {
+ "yyyy MM dd HH:mm:ss",
+
+ // pattern, input, expected parse or NULL if expect parse failure
+ "HHmmss", "123456", "1970 01 01 12:34:56",
+ NULL, "12345", "1970 01 01 01:23:45",
+ NULL, "1234", NULL,
+ NULL, "00-05", NULL,
+ NULL, "12-34", NULL,
+ NULL, "00+05", NULL,
+ "ahhmm", "PM730", "1970 01 01 19:30:00",
+ };
+ const int32_t DATA_len = sizeof(DATA)/sizeof(DATA[0]);
+
+ expectParse(DATA, DATA_len, Locale("en"));
+}
+
+/**
+ * Test handling of white space.
+ */
+void DateFormatTest::TestWhiteSpaceParsing() {
+ const char* DATA[] = {
+ "yyyy MM dd",
+
+ // pattern, input, expected parse or null if expect parse failure
+
+ // Pattern space run should parse input text space run
+ "MM d yy", " 04 01 03", "2003 04 01",
+ NULL, " 04 01 03 ", "2003 04 01",
+ };
+ const int32_t DATA_len = sizeof(DATA)/sizeof(DATA[0]);
+
+ expectParse(DATA, DATA_len, Locale("en"));
+}
+
+
+void DateFormatTest::TestInvalidPattern() {
+ UErrorCode ec = U_ZERO_ERROR;
+ SimpleDateFormat f(UnicodeString("Yesterday"), ec);
+ ASSERT_OK(ec);
+ UnicodeString out;
+ FieldPosition pos;
+ f.format((UDate)0, out, pos);
+ logln(out);
+ // The bug is that the call to format() will crash. By not
+ // crashing, the test passes.
+}
+
+void DateFormatTest::TestGreekMay() {
+ UErrorCode ec = U_ZERO_ERROR;
+ UDate date = -9896080848000.0;
+ SimpleDateFormat fmt("EEEE, dd MMMM yyyy h:mm:ss a", Locale("el", "", ""), ec);
+ if (!assertSuccess("SimpleDateFormat::ct", ec)) return;
+ UnicodeString str;
+ fmt.format(date, str);
+ ParsePosition pos(0);
+ UDate d2 = fmt.parse(str, pos);
+ if (date != d2) {
+ errln("FAIL: unable to parse strings where case-folding changes length");
+ }
+}
+
+void DateFormatTest::TestStandAloneMonths()
+{
+ const char *EN_DATA[] = {
+ "yyyy MM dd HH:mm:ss",
+
+ "yyyy LLLL dd H:mm:ss", "fp", "2004 03 10 16:36:31", "2004 March 10 16:36:31", "2004 03 10 16:36:31",
+ "yyyy LLL dd H:mm:ss", "fp", "2004 03 10 16:36:31", "2004 Mar 10 16:36:31", "2004 03 10 16:36:31",
+ "yyyy LLLL dd H:mm:ss", "F", "2004 03 10 16:36:31", "2004 March 10 16:36:31",
+ "yyyy LLL dd H:mm:ss", "pf", "2004 Mar 10 16:36:31", "2004 03 10 16:36:31", "2004 Mar 10 16:36:31",
+
+ "LLLL", "fp", "1970 01 01 0:00:00", "January", "1970 01 01 0:00:00",
+ "LLLL", "fp", "1970 02 01 0:00:00", "February", "1970 02 01 0:00:00",
+ "LLLL", "fp", "1970 03 01 0:00:00", "March", "1970 03 01 0:00:00",
+ "LLLL", "fp", "1970 04 01 0:00:00", "April", "1970 04 01 0:00:00",
+ "LLLL", "fp", "1970 05 01 0:00:00", "May", "1970 05 01 0:00:00",
+ "LLLL", "fp", "1970 06 01 0:00:00", "June", "1970 06 01 0:00:00",
+ "LLLL", "fp", "1970 07 01 0:00:00", "July", "1970 07 01 0:00:00",
+ "LLLL", "fp", "1970 08 01 0:00:00", "August", "1970 08 01 0:00:00",
+ "LLLL", "fp", "1970 09 01 0:00:00", "September", "1970 09 01 0:00:00",
+ "LLLL", "fp", "1970 10 01 0:00:00", "October", "1970 10 01 0:00:00",
+ "LLLL", "fp", "1970 11 01 0:00:00", "November", "1970 11 01 0:00:00",
+ "LLLL", "fp", "1970 12 01 0:00:00", "December", "1970 12 01 0:00:00",
+
+ "LLL", "fp", "1970 01 01 0:00:00", "Jan", "1970 01 01 0:00:00",
+ "LLL", "fp", "1970 02 01 0:00:00", "Feb", "1970 02 01 0:00:00",
+ "LLL", "fp", "1970 03 01 0:00:00", "Mar", "1970 03 01 0:00:00",
+ "LLL", "fp", "1970 04 01 0:00:00", "Apr", "1970 04 01 0:00:00",
+ "LLL", "fp", "1970 05 01 0:00:00", "May", "1970 05 01 0:00:00",
+ "LLL", "fp", "1970 06 01 0:00:00", "Jun", "1970 06 01 0:00:00",
+ "LLL", "fp", "1970 07 01 0:00:00", "Jul", "1970 07 01 0:00:00",
+ "LLL", "fp", "1970 08 01 0:00:00", "Aug", "1970 08 01 0:00:00",
+ "LLL", "fp", "1970 09 01 0:00:00", "Sep", "1970 09 01 0:00:00",
+ "LLL", "fp", "1970 10 01 0:00:00", "Oct", "1970 10 01 0:00:00",
+ "LLL", "fp", "1970 11 01 0:00:00", "Nov", "1970 11 01 0:00:00",
+ "LLL", "fp", "1970 12 01 0:00:00", "Dec", "1970 12 01 0:00:00",
+ };
+
+ const char *CS_DATA[] = {
+ "yyyy MM dd HH:mm:ss",
+
+ "yyyy LLLL dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 duben 10 16:36:31", "2004 04 10 16:36:31",
+ "yyyy MMMM dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31", "2004 04 10 16:36:31",
+ "yyyy LLL dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 4. 10 16:36:31", "2004 04 10 16:36:31",
+ "yyyy LLLL dd H:mm:ss", "F", "2004 04 10 16:36:31", "2004 duben 10 16:36:31",
+ "yyyy MMMM dd H:mm:ss", "F", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31",
+ "yyyy LLLL dd H:mm:ss", "pf", "2004 duben 10 16:36:31", "2004 04 10 16:36:31", "2004 duben 10 16:36:31",
+ "yyyy MMMM dd H:mm:ss", "pf", "2004 dubna 10 16:36:31", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31",
+
+ "LLLL", "fp", "1970 01 01 0:00:00", "leden", "1970 01 01 0:00:00",
+ "LLLL", "fp", "1970 02 01 0:00:00", "\\u00FAnor", "1970 02 01 0:00:00",
+ "LLLL", "fp", "1970 03 01 0:00:00", "b\\u0159ezen", "1970 03 01 0:00:00",
+ "LLLL", "fp", "1970 04 01 0:00:00", "duben", "1970 04 01 0:00:00",
+ "LLLL", "fp", "1970 05 01 0:00:00", "kv\\u011Bten", "1970 05 01 0:00:00",
+ "LLLL", "fp", "1970 06 01 0:00:00", "\\u010Derven", "1970 06 01 0:00:00",
+ "LLLL", "fp", "1970 07 01 0:00:00", "\\u010Dervenec", "1970 07 01 0:00:00",
+ "LLLL", "fp", "1970 08 01 0:00:00", "srpen", "1970 08 01 0:00:00",
+ "LLLL", "fp", "1970 09 01 0:00:00", "z\\u00E1\\u0159\\u00ED", "1970 09 01 0:00:00",
+ "LLLL", "fp", "1970 10 01 0:00:00", "\\u0159\\u00EDjen", "1970 10 01 0:00:00",
+ "LLLL", "fp", "1970 11 01 0:00:00", "listopad", "1970 11 01 0:00:00",
+ "LLLL", "fp", "1970 12 01 0:00:00", "prosinec", "1970 12 01 0:00:00",
+
+ "LLL", "fp", "1970 01 01 0:00:00", "1.", "1970 01 01 0:00:00",
+ "LLL", "fp", "1970 02 01 0:00:00", "2.", "1970 02 01 0:00:00",
+ "LLL", "fp", "1970 03 01 0:00:00", "3.", "1970 03 01 0:00:00",
+ "LLL", "fp", "1970 04 01 0:00:00", "4.", "1970 04 01 0:00:00",
+ "LLL", "fp", "1970 05 01 0:00:00", "5.", "1970 05 01 0:00:00",
+ "LLL", "fp", "1970 06 01 0:00:00", "6.", "1970 06 01 0:00:00",
+ "LLL", "fp", "1970 07 01 0:00:00", "7.", "1970 07 01 0:00:00",
+ "LLL", "fp", "1970 08 01 0:00:00", "8.", "1970 08 01 0:00:00",
+ "LLL", "fp", "1970 09 01 0:00:00", "9.", "1970 09 01 0:00:00",
+ "LLL", "fp", "1970 10 01 0:00:00", "10.", "1970 10 01 0:00:00",
+ "LLL", "fp", "1970 11 01 0:00:00", "11.", "1970 11 01 0:00:00",
+ "LLL", "fp", "1970 12 01 0:00:00", "12.", "1970 12 01 0:00:00",
+ };
+
+ expect(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
+ expect(CS_DATA, ARRAY_SIZE(CS_DATA), Locale("cs", "", ""));
+}
+
+void DateFormatTest::TestStandAloneDays()
+{
+ const char *EN_DATA[] = {
+ "yyyy MM dd HH:mm:ss",
+
+ "cccc", "fp", "1970 01 04 0:00:00", "Sunday", "1970 01 04 0:00:00",
+ "cccc", "fp", "1970 01 05 0:00:00", "Monday", "1970 01 05 0:00:00",
+ "cccc", "fp", "1970 01 06 0:00:00", "Tuesday", "1970 01 06 0:00:00",
+ "cccc", "fp", "1970 01 07 0:00:00", "Wednesday", "1970 01 07 0:00:00",
+ "cccc", "fp", "1970 01 01 0:00:00", "Thursday", "1970 01 01 0:00:00",
+ "cccc", "fp", "1970 01 02 0:00:00", "Friday", "1970 01 02 0:00:00",
+ "cccc", "fp", "1970 01 03 0:00:00", "Saturday", "1970 01 03 0:00:00",
+
+ "ccc", "fp", "1970 01 04 0:00:00", "Sun", "1970 01 04 0:00:00",
+ "ccc", "fp", "1970 01 05 0:00:00", "Mon", "1970 01 05 0:00:00",
+ "ccc", "fp", "1970 01 06 0:00:00", "Tue", "1970 01 06 0:00:00",
+ "ccc", "fp", "1970 01 07 0:00:00", "Wed", "1970 01 07 0:00:00",
+ "ccc", "fp", "1970 01 01 0:00:00", "Thu", "1970 01 01 0:00:00",
+ "ccc", "fp", "1970 01 02 0:00:00", "Fri", "1970 01 02 0:00:00",
+ "ccc", "fp", "1970 01 03 0:00:00", "Sat", "1970 01 03 0:00:00",
+ };
+
+ const char *CS_DATA[] = {
+ "yyyy MM dd HH:mm:ss",
+
+ "cccc", "fp", "1970 01 04 0:00:00", "ned\\u011Ble", "1970 01 04 0:00:00",
+ "cccc", "fp", "1970 01 05 0:00:00", "pond\\u011Bl\\u00ED", "1970 01 05 0:00:00",
+ "cccc", "fp", "1970 01 06 0:00:00", "\\u00FAter\\u00FD", "1970 01 06 0:00:00",
+ "cccc", "fp", "1970 01 07 0:00:00", "st\\u0159eda", "1970 01 07 0:00:00",
+ "cccc", "fp", "1970 01 01 0:00:00", "\\u010Dtvrtek", "1970 01 01 0:00:00",
+ "cccc", "fp", "1970 01 02 0:00:00", "p\\u00E1tek", "1970 01 02 0:00:00",
+ "cccc", "fp", "1970 01 03 0:00:00", "sobota", "1970 01 03 0:00:00",
+
+ "ccc", "fp", "1970 01 04 0:00:00", "ne", "1970 01 04 0:00:00",
+ "ccc", "fp", "1970 01 05 0:00:00", "po", "1970 01 05 0:00:00",
+ "ccc", "fp", "1970 01 06 0:00:00", "\\u00FAt", "1970 01 06 0:00:00",
+ "ccc", "fp", "1970 01 07 0:00:00", "st", "1970 01 07 0:00:00",
+ "ccc", "fp", "1970 01 01 0:00:00", "\\u010Dt", "1970 01 01 0:00:00",
+ "ccc", "fp", "1970 01 02 0:00:00", "p\\u00E1", "1970 01 02 0:00:00",
+ "ccc", "fp", "1970 01 03 0:00:00", "so", "1970 01 03 0:00:00",
+ };
+
+ expect(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
+ expect(CS_DATA, ARRAY_SIZE(CS_DATA), Locale("cs", "", ""));
+}
+
+void DateFormatTest::TestNarrowNames()
+{
+ const char *EN_DATA[] = {
+ "yyyy MM dd HH:mm:ss",
+
+ "yyyy MMMMM dd H:mm:ss", "2004 03 10 16:36:31", "2004 M 10 16:36:31",
+ "yyyy LLLLL dd H:mm:ss", "2004 03 10 16:36:31", "2004 M 10 16:36:31",
+
+ "MMMMM", "1970 01 01 0:00:00", "J",
+ "MMMMM", "1970 02 01 0:00:00", "F",
+ "MMMMM", "1970 03 01 0:00:00", "M",
+ "MMMMM", "1970 04 01 0:00:00", "A",
+ "MMMMM", "1970 05 01 0:00:00", "M",
+ "MMMMM", "1970 06 01 0:00:00", "J",
+ "MMMMM", "1970 07 01 0:00:00", "J",
+ "MMMMM", "1970 08 01 0:00:00", "A",
+ "MMMMM", "1970 09 01 0:00:00", "S",
+ "MMMMM", "1970 10 01 0:00:00", "O",
+ "MMMMM", "1970 11 01 0:00:00", "N",
+ "MMMMM", "1970 12 01 0:00:00", "D",
+
+ "LLLLL", "1970 01 01 0:00:00", "J",
+ "LLLLL", "1970 02 01 0:00:00", "F",
+ "LLLLL", "1970 03 01 0:00:00", "M",
+ "LLLLL", "1970 04 01 0:00:00", "A",
+ "LLLLL", "1970 05 01 0:00:00", "M",
+ "LLLLL", "1970 06 01 0:00:00", "J",
+ "LLLLL", "1970 07 01 0:00:00", "J",
+ "LLLLL", "1970 08 01 0:00:00", "A",
+ "LLLLL", "1970 09 01 0:00:00", "S",
+ "LLLLL", "1970 10 01 0:00:00", "O",
+ "LLLLL", "1970 11 01 0:00:00", "N",
+ "LLLLL", "1970 12 01 0:00:00", "D",
+
+ "EEEEE", "1970 01 04 0:00:00", "S",
+ "EEEEE", "1970 01 05 0:00:00", "M",
+ "EEEEE", "1970 01 06 0:00:00", "T",
+ "EEEEE", "1970 01 07 0:00:00", "W",
+ "EEEEE", "1970 01 01 0:00:00", "T",
+ "EEEEE", "1970 01 02 0:00:00", "F",
+ "EEEEE", "1970 01 03 0:00:00", "S",
+
+ "ccccc", "1970 01 04 0:00:00", "S",
+ "ccccc", "1970 01 05 0:00:00", "M",
+ "ccccc", "1970 01 06 0:00:00", "T",
+ "ccccc", "1970 01 07 0:00:00", "W",
+ "ccccc", "1970 01 01 0:00:00", "T",
+ "ccccc", "1970 01 02 0:00:00", "F",
+ "ccccc", "1970 01 03 0:00:00", "S",
+ };
+
+ const char *CS_DATA[] = {
+ "yyyy MM dd HH:mm:ss",
+
+ "yyyy LLLLL dd H:mm:ss", "2004 04 10 16:36:31", "2004 d 10 16:36:31",
+ "yyyy MMMMM dd H:mm:ss", "2004 04 10 16:36:31", "2004 d 10 16:36:31",
+
+ "MMMMM", "1970 01 01 0:00:00", "l",
+ "MMMMM", "1970 02 01 0:00:00", "\\u00FA",
+ "MMMMM", "1970 03 01 0:00:00", "b",
+ "MMMMM", "1970 04 01 0:00:00", "d",
+ "MMMMM", "1970 05 01 0:00:00", "k",
+ "MMMMM", "1970 06 01 0:00:00", "\\u010D",
+ "MMMMM", "1970 07 01 0:00:00", "\\u010D",
+ "MMMMM", "1970 08 01 0:00:00", "s",
+ "MMMMM", "1970 09 01 0:00:00", "z",
+ "MMMMM", "1970 10 01 0:00:00", "\\u0159",
+ "MMMMM", "1970 11 01 0:00:00", "l",
+ "MMMMM", "1970 12 01 0:00:00", "p",
+
+ "LLLLL", "1970 01 01 0:00:00", "l",
+ "LLLLL", "1970 02 01 0:00:00", "\\u00FA",
+ "LLLLL", "1970 03 01 0:00:00", "b",
+ "LLLLL", "1970 04 01 0:00:00", "d",
+ "LLLLL", "1970 05 01 0:00:00", "k",
+ "LLLLL", "1970 06 01 0:00:00", "\\u010D",
+ "LLLLL", "1970 07 01 0:00:00", "\\u010D",
+ "LLLLL", "1970 08 01 0:00:00", "s",
+ "LLLLL", "1970 09 01 0:00:00", "z",
+ "LLLLL", "1970 10 01 0:00:00", "\\u0159",
+ "LLLLL", "1970 11 01 0:00:00", "l",
+ "LLLLL", "1970 12 01 0:00:00", "p",
+
+ "EEEEE", "1970 01 04 0:00:00", "N",
+ "EEEEE", "1970 01 05 0:00:00", "P",
+ "EEEEE", "1970 01 06 0:00:00", "\\u00DA",
+ "EEEEE", "1970 01 07 0:00:00", "S",
+ "EEEEE", "1970 01 01 0:00:00", "\\u010C",
+ "EEEEE", "1970 01 02 0:00:00", "P",
+ "EEEEE", "1970 01 03 0:00:00", "S",
+
+ "ccccc", "1970 01 04 0:00:00", "N",
+ "ccccc", "1970 01 05 0:00:00", "P",
+ "ccccc", "1970 01 06 0:00:00", "\\u00DA",
+ "ccccc", "1970 01 07 0:00:00", "S",
+ "ccccc", "1970 01 01 0:00:00", "\\u010C",
+ "ccccc", "1970 01 02 0:00:00", "P",
+ "ccccc", "1970 01 03 0:00:00", "S",
+ };
+
+ expectFormat(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
+ expectFormat(CS_DATA, ARRAY_SIZE(CS_DATA), Locale("cs", "", ""));
+}
+
+void DateFormatTest::TestEras()
+{
+ const char *EN_DATA[] = {
+ "yyyy MM dd",
+
+ "MMMM dd yyyy G", "fp", "1951 07 17", "July 17 1951 AD", "1951 07 17",
+ "MMMM dd yyyy GG", "fp", "1951 07 17", "July 17 1951 AD", "1951 07 17",
+ "MMMM dd yyyy GGG", "fp", "1951 07 17", "July 17 1951 AD", "1951 07 17",
+ "MMMM dd yyyy GGGG", "fp", "1951 07 17", "July 17 1951 Anno Domini", "1951 07 17",
+
+ "MMMM dd yyyy G", "fp", "-438 07 17", "July 17 0439 BC", "-438 07 17",
+ "MMMM dd yyyy GG", "fp", "-438 07 17", "July 17 0439 BC", "-438 07 17",
+ "MMMM dd yyyy GGG", "fp", "-438 07 17", "July 17 0439 BC", "-438 07 17",
+ "MMMM dd yyyy GGGG", "fp", "-438 07 17", "July 17 0439 Before Christ", "-438 07 17",
+ };
+
+ expect(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
+}
+
+void DateFormatTest::TestQuarters()
+{
+ const char *EN_DATA[] = {
+ "yyyy MM dd",
+
+ "Q", "fp", "1970 01 01", "1", "1970 01 01",
+ "QQ", "fp", "1970 04 01", "02", "1970 04 01",
+ "QQQ", "fp", "1970 07 01", "Q3", "1970 07 01",
+ "QQQQ", "fp", "1970 10 01", "4th quarter", "1970 10 01",
+
+ "q", "fp", "1970 01 01", "1", "1970 01 01",
+ "qq", "fp", "1970 04 01", "02", "1970 04 01",
+ "qqq", "fp", "1970 07 01", "Q3", "1970 07 01",
+ "qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
+ };
+
+ expect(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
+}
+
+/**
+ * Test parsing. Input is an array that starts with the following
+ * header:
+ *
+ * [0] = pattern string to parse [i+2] with
+ *
+ * followed by test cases, each of which is 3 array elements:
+ *
+ * [i] = pattern, or NULL to reuse prior pattern
+ * [i+1] = input string
+ * [i+2] = expected parse result (parsed with pattern [0])
+ *
+ * If expect parse failure, then [i+2] should be NULL.
+ */
+void DateFormatTest::expectParse(const char** data, int32_t data_length,
+ const Locale& loc) {
+ const UDate FAIL = (UDate) -1;
+ const UnicodeString FAIL_STR("parse failure");
+ int32_t i = 0;
+
+ UErrorCode ec = U_ZERO_ERROR;
+ SimpleDateFormat fmt("", loc, ec);
+ SimpleDateFormat ref(data[i++], loc, ec);
+ SimpleDateFormat gotfmt("G yyyy MM dd HH:mm:ss z", loc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: SimpleDateFormat constructor");
+ return;
+ }
+
+ const char* currentPat = NULL;
+ while (i<data_length) {
+ const char* pattern = data[i++];
+ const char* input = data[i++];
+ const char* expected = data[i++];
+
+ ec = U_ZERO_ERROR;
+ if (pattern != NULL) {
+ fmt.applyPattern(pattern);
+ currentPat = pattern;
+ }
+ UDate got = fmt.parse(input, ec);
+ UnicodeString gotstr(FAIL_STR);
+ if (U_FAILURE(ec)) {
+ got = FAIL;
+ } else {
+ gotstr.remove();
+ gotfmt.format(got, gotstr);
+ }
+
+ UErrorCode ec2 = U_ZERO_ERROR;
+ UDate exp = FAIL;
+ UnicodeString expstr(FAIL_STR);
+ if (expected != NULL) {
+ expstr = expected;
+ exp = ref.parse(expstr, ec2);
+ if (U_FAILURE(ec2)) {
+ // This only happens if expected is in wrong format --
+ // should never happen once test is debugged.
+ errln("FAIL: Internal test error");
+ return;
+ }
+ }
+
+ if (got == exp) {
+ logln((UnicodeString)"Ok: " + input + " x " +
+ currentPat + " => " + gotstr);
+ } else {
+ errln((UnicodeString)"FAIL: " + input + " x " +
+ currentPat + " => " + gotstr + ", expected " +
+ expstr);
+ }
+ }
+}
+
+/**
+ * Test formatting and parsing. Input is an array that starts
+ * with the following header:
+ *
+ * [0] = pattern string to parse [i+2] with
+ *
+ * followed by test cases, each of which is 3 array elements:
+ *
+ * [i] = pattern, or null to reuse prior pattern
+ * [i+1] = control string, either "fp", "pf", or "F".
+ * [i+2..] = data strings
+ *
+ * The number of data strings depends on the control string.
+ * Examples:
+ * 1. "y/M/d H:mm:ss.SS", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.56", "2004 03 10 16:36:31.560",
+ * 'f': Format date [i+2] (as parsed using pattern [0]) and expect string [i+3].
+ * 'p': Parse string [i+3] and expect date [i+4].
+ *
+ * 2. "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567"
+ * 'F': Format date [i+2] and expect string [i+3],
+ * then parse string [i+3] and expect date [i+2].
+ *
+ * 3. "y/M/d H:mm:ss.SSSS", "pf", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5670",
+ * 'p': Parse string [i+2] and expect date [i+3].
+ * 'f': Format date [i+3] and expect string [i+4].
+ */
+void DateFormatTest::expect(const char** data, int32_t data_length,
+ const Locale& loc) {
+ int32_t i = 0;
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString str, str2;
+ SimpleDateFormat fmt("", loc, ec);
+ SimpleDateFormat ref(data[i++], loc, ec);
+ SimpleDateFormat univ("EE G yyyy MM dd HH:mm:ss.SSS z", loc, ec);
+ if (!assertSuccess("construct SimpleDateFormat", ec)) return;
+
+ UnicodeString currentPat;
+ while (i<data_length) {
+ const char* pattern = data[i++];
+ if (pattern != NULL) {
+ fmt.applyPattern(pattern);
+ currentPat = pattern;
+ }
+
+ const char* control = data[i++];
+
+ if (uprv_strcmp(control, "fp") == 0) {
+ // 'f'
+ const char* datestr = data[i++];
+ const char* string = data[i++];
+ UDate date = ref.parse(ctou(datestr), ec);
+ if (!assertSuccess("parse", ec)) return;
+ assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
+ ctou(string),
+ fmt.format(date, str.remove()));
+ // 'p'
+ datestr = data[i++];
+ date = ref.parse(ctou(datestr), ec);
+ if (!assertSuccess("parse", ec)) return;
+ UDate parsedate = fmt.parse(ctou(string), ec);
+ if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
+ assertEquals((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")",
+ univ.format(date, str.remove()),
+ univ.format(parsedate, str2.remove()));
+ }
+ }
+
+ else if (uprv_strcmp(control, "pf") == 0) {
+ // 'p'
+ const char* string = data[i++];
+ const char* datestr = data[i++];
+ UDate date = ref.parse(ctou(datestr), ec);
+ if (!assertSuccess("parse", ec)) return;
+ UDate parsedate = fmt.parse(ctou(string), ec);
+ if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
+ assertEquals((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")",
+ univ.format(date, str.remove()),
+ univ.format(parsedate, str2.remove()));
+ }
+ // 'f'
+ string = data[i++];
+ assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
+ ctou(string),
+ fmt.format(date, str.remove()));
+ }
+
+ else if (uprv_strcmp(control, "F") == 0) {
+ const char* datestr = data[i++];
+ const char* string = data[i++];
+ UDate date = ref.parse(ctou(datestr), ec);
+ if (!assertSuccess("parse", ec)) return;
+ assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
+ ctou(string),
+ fmt.format(date, str.remove()));
+
+ UDate parsedate = fmt.parse(string, ec);
+ if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
+ assertEquals((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")",
+ univ.format(date, str.remove()),
+ univ.format(parsedate, str2.remove()));
+ }
+ }
+
+ else {
+ errln((UnicodeString)"FAIL: Invalid control string " + control);
+ return;
+ }
+ }
+}
+
+/**
+ * Test formatting. Input is an array that starts
+ * with the following header:
+ *
+ * [0] = pattern string to parse [i+2] with
+ *
+ * followed by test cases, each of which is 3 array elements:
+ *
+ * [i] = pattern, or null to reuse prior pattern
+ * [i+1] = data string a
+ * [i+2] = data string b
+ *
+ * Examples:
+ * Format date [i+1] and expect string [i+2].
+ *
+ * "y/M/d H:mm:ss.SSSS", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567"
+ */
+void DateFormatTest::expectFormat(const char** data, int32_t data_length,
+ const Locale& loc) {
+ int32_t i = 0;
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString str, str2;
+ SimpleDateFormat fmt("", loc, ec);
+ SimpleDateFormat ref(data[i++], loc, ec);
+ SimpleDateFormat univ("EE G yyyy MM dd HH:mm:ss.SSS z", loc, ec);
+ if (!assertSuccess("construct SimpleDateFormat", ec)) return;
+
+ UnicodeString currentPat;
+
+ while (i<data_length) {
+ const char* pattern = data[i++];
+ if (pattern != NULL) {
+ fmt.applyPattern(pattern);
+ currentPat = pattern;
+ }
+
+ const char* datestr = data[i++];
+ const char* string = data[i++];
+ UDate date = ref.parse(ctou(datestr), ec);
+ if (!assertSuccess("parse", ec)) return;
+ assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
+ ctou(string),
+ fmt.format(date, str.remove()));
+ }
+}
+
+void DateFormatTest::TestGenericTime() {
+ // any zone pattern should parse any zone
+ const Locale en("en");
+ const char* ZDATA[] = {
+ "yyyy MM dd HH:mm zzz",
+ // round trip
+ "y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
+ "y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
+ "y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
+ "y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
+ // non-generic timezone string influences dst offset even if wrong for date/time
+ "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 PST",
+ "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 Pacific Time",
+ "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 PDT",
+ "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 Pacific Time",
+ // generic timezone generates dst offset appropriate for local time
+ "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
+ "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
+ "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
+ "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
+ // daylight savings time transition edge cases.
+ // time to parse does not really exist, PT interpreted as earlier time
+ "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
+ "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
+ "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PST",
+ "y/M/d H:mm v", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
+ "y/M/d H:mm v", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
+ "y/M/d H:mm v", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PT",
+ "y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
+ // time to parse is ambiguous, PT interpreted as later time
+ "y/M/d H:mm zzz", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PST",
+ "y/M/d H:mm v", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PT",
+ "y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
+
+ "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
+ "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
+ "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PDT",
+ "y/M/d H:mm v", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
+ "y/M/d H:mm v", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
+ "y/M/d H:mm v", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PT",
+ "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
+ };
+ const int32_t ZDATA_length = sizeof(ZDATA)/ sizeof(ZDATA[0]);
+ expect(ZDATA, ZDATA_length, en);
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ logln("cross format/parse tests");
+ UnicodeString basepat("yy/MM/dd H:mm ");
+ SimpleDateFormat formats[] = {
+ SimpleDateFormat(basepat + "vvv", en, status),
+ SimpleDateFormat(basepat + "vvvv", en, status),
+ SimpleDateFormat(basepat + "zzz", en, status),
+ SimpleDateFormat(basepat + "zzzz", en, status)
+ };
+ ASSERT_OK(status);
+ const int32_t formats_length = sizeof(formats)/sizeof(formats[0]);
+
+ UnicodeString test;
+ SimpleDateFormat univ("yyyy MM dd HH:mm zzz", en, status);
+ ASSERT_OK(status);
+ const UnicodeString times[] = {
+ "2004 01 02 03:04 PST",
+ "2004 07 08 09:10 PDT"
+ };
+ int32_t times_length = sizeof(times)/sizeof(times[0]);
+ for (int i = 0; i < times_length; ++i) {
+ UDate d = univ.parse(times[i], status);
+ logln(UnicodeString("\ntime: ") + d);
+ for (int j = 0; j < formats_length; ++j) {
+ test.remove();
+ formats[j].format(d, test);
+ logln("\ntest: '" + test + "'");
+ for (int k = 0; k < formats_length; ++k) {
+ UDate t = formats[k].parse(test, status);
+ if (U_SUCCESS(status)) {
+ if (d != t) {
+ errln((UnicodeString)"FAIL: format " + k +
+ " incorrectly parsed output of format " + j +
+ " (" + test + "), returned " +
+ dateToString(t) + " instead of " + dateToString(d));
+ } else {
+ logln((UnicodeString)"OK: format " + k + " parsed ok");
+ }
+ } else if (status == U_PARSE_ERROR) {
+ errln((UnicodeString)"FAIL: format " + k +
+ " could not parse output of format " + j +
+ " (" + test + ")");
+ }
+ }
+ }
+ }
+}
+
+void DateFormatTest::TestGenericTimeZoneOrder() {
+ // generic times should parse the same no matter what the placement of the time zone string
+ // should work for standard and daylight times
+
+ const char* XDATA[] = {
+ "yyyy MM dd HH:mm zzz",
+ // standard time, explicit daylight/standard
+ "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
+ "y/M/d zzz H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 PST 1:00",
+ "zzz y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "PST 2004/1/1 1:00",
+
+ // standard time, generic
+ "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
+ "y/M/d vvvv H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 Pacific Time 1:00",
+ "vvvv y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "Pacific Time 2004/1/1 1:00",
+
+ // dahylight time, explicit daylight/standard
+ "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
+ "y/M/d zzz H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PDT 1:00",
+ "zzz y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PDT 2004/7/1 1:00",
+
+ // daylight time, generic
+ "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
+ "y/M/d vvvv H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 Pacific Time 1:00",
+ "vvvv y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "Pacific Time 2004/7/1 1:00",
+ };
+ const int32_t XDATA_length = sizeof(XDATA)/sizeof(XDATA[0]);
+ Locale en("en");
+ expect(XDATA, XDATA_length, en);
+}
+
+void DateFormatTest::TestZTimeZoneParsing(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ const Locale en("en");
+ UnicodeString test;
+ //SimpleDateFormat univ("yyyy-MM-dd'T'HH:mm Z", en, status);
+ SimpleDateFormat univ("HH:mm Z", en, status);
+ const TimeZone *t = TimeZone::getGMT();
+ univ.setTimeZone(*t);
+
+ univ.setLenient(false);
+ ParsePosition pp(0);
+ ASSERT_OK(status);
+ struct {
+ UnicodeString input;
+ UnicodeString expected_result;
+ } tests[] = {
+ { "11:00 -0200", "13:00 +0000" },
+ { "11:00 +0200", "09:00 +0000" },
+ { "11:00 +0400", "07:00 +0000" },
+ { "11:00 +0530", "05:30 +0000" }
+ };
+
+ UnicodeString result;
+ int32_t tests_length = sizeof(tests)/sizeof(tests[0]);
+ for (int i = 0; i < tests_length; ++i) {
+ pp.setIndex(0);
+ UDate d = univ.parse(tests[i].input, pp);
+ if(pp.getIndex() != tests[i].input.length()){
+ errln("setZoneString() did not succeed. Consumed: %i instead of %i",
+ pp.getIndex(), tests[i].input.length());
+ return;
+ }
+ result.remove();
+ univ.format(d, result);
+ if(result != tests[i].expected_result) {
+ errln("Expected " + tests[i].expected_result
+ + " got " + result);
+ return;
+ }
+ logln("SUCCESS: Parsed " + tests[i].input
+ + " got " + result
+ + " expected " + tests[i].expected_result);
+ }
+}
+
+void DateFormatTest::TestHost(void)
+{
+#ifdef U_WINDOWS
+ Win32DateTimeTest::testLocales(this);
+#endif
+}
+
+// Relative Date Tests
+
+void DateFormatTest::TestRelative(int daysdelta,
+ const Locale& loc,
+ const char *expectChars) {
+ char banner[25];
+ sprintf(banner, "%d", daysdelta);
+ UnicodeString bannerStr(banner, "");
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ FieldPosition pos(0);
+ UnicodeString test;
+ Locale en("en");
+ DateFormat *fullrelative = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
+
+ if (fullrelative == NULL) {
+ errln("DateFormat::createDateInstance(DateFormat::kFullRelative, %s) returned NULL", loc.getName());
+ return;
+ }
+
+ DateFormat *full = DateFormat::createDateInstance(DateFormat::kFull , loc);
+
+ if (full == NULL) {
+ errln("DateFormat::createDateInstance(DateFormat::kFull, %s) returned NULL", loc.getName());
+ return;
+ }
+
+ DateFormat *en_full = DateFormat::createDateInstance(DateFormat::kFull, en);
+
+ if (en_full == NULL) {
+ errln("DateFormat::createDateInstance(DateFormat::kFull, en) returned NULL");
+ return;
+ }
+
+ DateFormat *en_fulltime = DateFormat::createDateTimeInstance(DateFormat::kFull,DateFormat::kFull,en);
+
+ if (en_fulltime == NULL) {
+ errln("DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, en) returned NULL");
+ return;
+ }
+
+ UnicodeString result;
+ UnicodeString normalResult;
+ UnicodeString expect;
+ UnicodeString parseResult;
+
+ Calendar *c = Calendar::createInstance(status);
+
+ // Today = Today
+ c->setTime(Calendar::getNow(), status);
+ if(daysdelta != 0) {
+ c->add(Calendar::DATE,daysdelta,status);
+ }
+ ASSERT_OK(status);
+
+ // calculate the expected string
+ if(expectChars != NULL) {
+ expect = expectChars;
+ } else {
+ full->format(*c, expect, pos); // expected = normal full
+ }
+
+ fullrelative ->format(*c, result, pos);
+ en_full ->format(*c, normalResult, pos);
+
+ if(result != expect) {
+ errln("FAIL: Relative Format ["+bannerStr+"] of "+normalResult+" failed, expected "+expect+" but got " + result);
+ } else {
+ logln("PASS: Relative Format ["+bannerStr+"] of "+normalResult+" got " + result);
+ }
+
+
+ //verify
+ UDate d = fullrelative->parse(result, status);
+ ASSERT_OK(status);
+
+ UnicodeString parseFormat; // parse rel->format full
+ en_full->format(d, parseFormat, status);
+
+ UnicodeString origFormat;
+ en_full->format(*c, origFormat, pos);
+
+ if(parseFormat!=origFormat) {
+ errln("FAIL: Relative Parse ["+bannerStr+"] of "+result+" failed, expected "+parseFormat+" but got "+origFormat);
+ } else {
+ logln("PASS: Relative Parse ["+bannerStr+"] of "+result+" passed, got "+parseFormat);
+ }
+
+ delete full;
+ delete fullrelative;
+ delete en_fulltime;
+ delete en_full;
+ delete c;
+}
+
+
+void DateFormatTest::TestRelative(void)
+{
+ Locale en("en");
+ TestRelative( 0, en, "Today");
+ TestRelative(-1, en, "Yesterday");
+ TestRelative( 1, en, "Tomorrow");
+ TestRelative( 2, en, NULL);
+ TestRelative( -2, en, NULL);
+ TestRelative( 3, en, NULL);
+ TestRelative( -3, en, NULL);
+ TestRelative( 300, en, NULL);
+ TestRelative( -300, en, NULL);
+}
+
+void DateFormatTest::TestRelativeClone(void)
+{
+ /*
+ Verify that a cloned formatter gives the same results
+ and is useable after the original has been deleted.
+ */
+ UErrorCode status = U_ZERO_ERROR;
+ Locale loc("en");
+ UDate now = Calendar::getNow();
+ DateFormat *full = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
+ if (full == NULL) {
+ errln("FAIL: Can't create Relative date instance");
+ return;
+ }
+ UnicodeString result1;
+ full->format(now, result1, status);
+ Format *fullClone = full->clone();
+ delete full;
+ full = NULL;
+
+ UnicodeString result2;
+ fullClone->format(now, result2, status);
+ ASSERT_OK(status);
+ if (result1 != result2) {
+ errln("FAIL: Clone returned different result from non-clone.");
+ }
+ delete fullClone;
+}
+
+void DateFormatTest::TestHostClone(void)
+{
+ /*
+ Verify that a cloned formatter gives the same results
+ and is useable after the original has been deleted.
+ */
+ // This is mainly important on Windows.
+ UErrorCode status = U_ZERO_ERROR;
+ Locale loc("en_US@compat=host");
+ UDate now = Calendar::getNow();
+ DateFormat *full = DateFormat::createDateInstance(DateFormat::kFull, loc);
+ if (full == NULL) {
+ errln("FAIL: Can't create Relative date instance");
+ return;
+ }
+ UnicodeString result1;
+ full->format(now, result1, status);
+ Format *fullClone = full->clone();
+ delete full;
+ full = NULL;
+
+ UnicodeString result2;
+ fullClone->format(now, result2, status);
+ ASSERT_OK(status);
+ if (result1 != result2) {
+ errln("FAIL: Clone returned different result from non-clone.");
+ }
+ delete fullClone;
+}
+
+void DateFormatTest::TestTimeZoneDisplayName()
+{
+ // This test data was ported from ICU4J. Don't know why the 6th column in there because it's not being
+ // used currently.
+ const char *fallbackTests[][6] = {
+ { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
+ { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
+ { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "PST", "America/Los_Angeles" },
+ { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "V", "PST", "America/Los_Angeles" },
+ { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Pacific Standard Time", "America/Los_Angeles" },
+ { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
+ { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
+ { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "PDT", "America/Los_Angeles" },
+ { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "V", "PDT", "America/Los_Angeles" },
+ { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Pacific Daylight Time", "America/Los_Angeles" },
+ { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "PT", "America/Los_Angeles" },
+ { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Pacific Time", "America/Los_Angeles" },
+ { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "United States (Los Angeles)", "America/Los_Angeles" },
+ { "en_GB", "America/Los_Angeles", "2004-01-15T12:00:00Z", "z", "PST", "America/Los_Angeles" },
+ { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "Z", "-0700", "-7:00" },
+ { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
+ { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "z", "MST", "America/Phoenix" },
+ { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "V", "MST", "America/Phoenix" },
+ { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
+ { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
+ { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
+ { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "z", "MST", "America/Phoenix" },
+ { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "V", "MST", "America/Phoenix" },
+ { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
+ { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "v", "MST", "America/Phoenix" },
+ { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "vvvv", "Mountain Standard Time", "America/Phoenix" },
+ { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "VVVV", "United States (Phoenix)", "America/Phoenix" },
+
+ { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "V", "ART", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Time", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "V", "ART", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Time", "-3:00" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Argentina (Buenos Aires)", "America/Buenos_Aires" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Time", "America/Buenos_Aires" },
+ { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Argentina (Buenos Aires)", "America/Buenos_Aires" },
+
+ { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "V", "ART", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Time", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "V", "ART", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Time", "-3:00" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Argentina (Buenos Aires)", "America/Buenos_Aires" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Time", "America/Buenos_Aires" },
+ { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Argentina (Buenos Aires)", "America/Buenos_Aires" },
+
+ { "en", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
+ { "en", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
+ { "en", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-05:00", "-5:00" },
+ { "en", "America/Havana", "2004-01-15T00:00:00Z", "V", "CST (Cuba)", "-5:00" },
+ { "en", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Cuba Standard Time", "-5:00" },
+ { "en", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
+ { "en", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
+ { "en", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-04:00", "-4:00" },
+ { "en", "America/Havana", "2004-07-15T00:00:00Z", "V", "CDT (Cuba)", "-4:00" },
+ { "en", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Cuba Daylight Time", "-4:00" },
+ { "en", "America/Havana", "2004-07-15T00:00:00Z", "v", "Cuba Time", "America/Havana" },
+ { "en", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Cuba Time", "America/Havana" },
+ { "en", "America/Havana", "2004-07-15T00:00:00Z", "VVVV", "Cuba Time", "America/Havana" },
+
+ { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
+ { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+ { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "V", "AEDT", "+11:00" },
+ { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "V", "AEST", "+10:00" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Australia (Sydney)", "Australia/Sydney" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
+ { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "VVVV", "Australia (Sydney)", "Australia/Sydney" },
+
+ { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
+ { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+ { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "V", "AEDT", "+11:00" },
+ { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "V", "AEST", "+10:00" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Australia (Sydney)", "Australia/Sydney" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
+ { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "VVVV", "Australia (Sydney)", "Australia/Sydney" },
+
+ { "en", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
+ { "en", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+00:00", "+0:00" },
+ { "en", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
+ { "en", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
+ { "en", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Greenwich Mean Time", "+0:00" },
+ { "en", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
+ { "en", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
+ { "en", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "Europe/London" },
+ { "en", "Europe/London", "2004-07-15T00:00:00Z", "V", "BST", "Europe/London" },
+ { "en", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "British Summer Time", "Europe/London" },
+ // icu en.txt has exemplar city for this time zone
+ { "en", "Europe/London", "2004-07-15T00:00:00Z", "v", "United Kingdom Time", "Europe/London" },
+ { "en", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "United Kingdom Time", "Europe/London" },
+ { "en", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "United Kingdom Time", "Europe/London" },
+
+ { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-03:00", "-3:00" },
+ { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
+
+ // JB#5150
+ { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
+ { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+05:30", "+5:30" },
+ { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "V", "IST", "+5:30" },
+ { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
+ { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
+ { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+05:30", "+05:30" },
+ { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "V", "IST", "+05:30" },
+ { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
+ { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "India Time", "Asia/Calcutta" },
+ { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "India Standard Time", "Asia/Calcutta" },
+
+ // ==========
+
+ { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
+ { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
+ { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-08:00", "-8:00" },
+ { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "GMT-08:00", "-8:00" },
+ { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
+ { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
+ { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-07:00", "-7:00" },
+ { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "GMT-07:00", "-7:00" },
+ { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Vereinigte Staaten (Los Angeles)", "America/Los_Angeles" },
+ { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Vereinigte Staaten (Los Angeles)", "America/Los_Angeles" },
+
+ { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Argentinien (Buenos Aires)", "America/Buenos_Aires" },
+ { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinien (Buenos Aires)", "America/Buenos_Aires" },
+
+ { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Argentinien (Buenos Aires)", "America/Buenos_Aires" },
+ { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinien (Buenos Aires)", "America/Buenos_Aires" },
+
+ { "de", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
+ { "de", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
+ { "de", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-05:00", "-5:00" },
+ { "de", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-05:00", "-5:00" },
+ { "de", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
+ { "de", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
+ { "de", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-04:00", "-4:00" },
+ { "de", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-04:00", "-4:00" },
+ { "de", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba", "America/Havana" },
+ { "de", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kuba", "America/Havana" },
+ // added to test proper fallback of country name
+ { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba", "America/Havana" },
+ { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kuba", "America/Havana" },
+
+ { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
+ { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+ { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
+ { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
+ { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+ { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
+ { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Australien (Sydney)", "Australia/Sydney" },
+ { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Australien (Sydney)", "Australia/Sydney" },
+
+ { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
+ { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+ { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
+ { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
+ { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+ { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
+ { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Australien (Sydney)", "Australia/Sydney" },
+ { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Australien (Sydney)", "Australia/Sydney" },
+
+ { "de", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
+ { "de", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+00:00", "+0:00" },
+ { "de", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+00:00", "+0:00" },
+ { "de", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT+00:00", "+0:00" },
+ { "de", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
+ { "de", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
+ { "de", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "+1:00" },
+ { "de", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+01:00", "+1:00" },
+ { "de", "Europe/London", "2004-07-15T00:00:00Z", "v", "Vereinigtes K\\u00f6nigreich", "Europe/London" },
+ { "de", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "Vereinigtes K\\u00f6nigreich", "Europe/London" },
+
+ { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-03:00", "-3:00" },
+ { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
+
+ // JB#5150
+ { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
+ { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+05:30", "+5:30" },
+ { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
+ { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
+ { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+05:30", "+05:30" },
+ { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
+ { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "Indien", "Asia/Calcutta" },
+ { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "Indien", "Asia/Calcutta" },
+
+ // ==========
+
+ { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
+ { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0800", "-8:00" },
+ { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-0800", "America/Los_Angeles" },
+ { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u592a\\u5e73\\u6d0b\\u6807\\u51c6\\u65f6\\u95f4", "America/Los_Angeles" },
+ { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
+ { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0700", "-7:00" },
+ { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-0700", "America/Los_Angeles" },
+ { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u592a\\u5e73\\u6d0b\\u590f\\u4ee4\\u65f6\\u95f4", "America/Los_Angeles" },
+ // icu zh.txt has exemplar city for this time zone
+ { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u7f8e\\u56fd (\\u6d1b\\u6749\\u77f6)", "America/Los_Angeles" },
+ { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u7f8e\\u56fd (\\u6d1b\\u6749\\u77f6)", "America/Los_Angeles" },
+
+ { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ // icu zh.txt does not have info for this time zone
+ { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u963f\\u6839\\u5ef7 (\\u5e03\\u5b9c\\u8bfa\\u65af\\u827e\\u5229\\u65af)", "America/Buenos_Aires" },
+ { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7 (\\u5e03\\u5b9c\\u8bfa\\u65af\\u827e\\u5229\\u65af)", "America/Buenos_Aires" },
+
+ { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u963f\\u6839\\u5ef7 (\\u5e03\\u5b9c\\u8bfa\\u65af\\u827e\\u5229\\u65af)", "America/Buenos_Aires" },
+ { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7 (\\u5e03\\u5b9c\\u8bfa\\u65af\\u827e\\u5229\\u65af)", "America/Buenos_Aires" },
+
+ { "zh", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
+ { "zh", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0500", "-5:00" },
+ { "zh", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-0500", "-5:00" },
+ { "zh", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-0500", "-5:00" },
+ { "zh", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
+ { "zh", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0400", "-4:00" },
+ { "zh", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-0400", "-4:00" },
+ { "zh", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-0400", "-4:00" },
+ { "zh", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u53e4\\u5df4", "America/Havana" },
+ { "zh", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u53e4\\u5df4", "America/Havana" },
+
+ { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+1100", "+11:00" },
+ { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+1100", "+11:00" },
+ { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
+ { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+1000", "+10:00" },
+ { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+1000", "+10:00" },
+ { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+1000", "+10:00" },
+ // icu zh.txt does not have info for this time zone
+ { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u6fb3\\u5927\\u5229\\u4e9a (\\u6089\\u5c3c)", "Australia/Sydney" },
+ { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a (\\u6089\\u5c3c)", "Australia/Sydney" },
+
+ { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+1100", "+11:00" },
+ { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+1100", "+11:00" },
+ { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
+ { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+1000", "+10:00" },
+ { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+1000", "+10:00" },
+ { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+1000", "+10:00" },
+ { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u6fb3\\u5927\\u5229\\u4e9a (\\u6089\\u5c3c)", "Australia/Sydney" },
+ { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a (\\u6089\\u5c3c)", "Australia/Sydney" },
+
+ { "zh", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
+ { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+0000", "+0:00" },
+ { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+0000", "+0:00" },
+ { "zh", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
+ { "zh", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u683C\\u6797\\u5C3C\\u6CBB\\u6807\\u51C6\\u65F6\\u95F4", "+0:00" },
+ { "zh", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
+ { "zh", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+0100", "+1:00" },
+ { "zh", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+0100", "+1:00" },
+ { "zh", "Europe/London", "2004-07-15T00:00:00Z", "V", "BST", "+1:00" },
+ { "zh", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+0100", "+1:00" },
+ { "zh", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u82f1\\u56fd", "Europe/London" },
+ { "zh", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u82f1\\u56fd", "Europe/London" },
+ { "zh", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\\u82f1\\u56fd", "Europe/London" },
+
+ { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-0300", "-3:00" },
+ { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-0300", "-3:00" },
+
+ // JB#5150
+ { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+0530", "+5:30" },
+ { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+0530", "+5:30" },
+ { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "GMT+0530", "+5:30" },
+ { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+0530", "+5:30" },
+ { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+0530", "+05:30" },
+ { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "GMT+0530", "+5:30" },
+ { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u5370\\u5ea6", "Asia/Calcutta" },
+ { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u5370\\u5EA6", "Asia/Calcutta" },
+
+ // ==========
+
+ { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
+ { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u096e:\\u0966\\u0966", "-8:00" },
+ { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-\\u0966\\u096e:\\u0966\\u0966", "-8:00" },
+ { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u096e:\\u0966\\u0966", "-8:00" },
+ { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
+ { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u096d:\\u0966\\u0966", "-7:00" },
+ { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-\\u0966\\u096d:\\u0966\\u0966", "-7:00" },
+ { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u096d:\\u0966\\u0966", "-7:00" },
+ { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u0938\\u0902\\u092f\\u0941\\u0915\\u094d\\u0924 \\u0930\\u093e\\u091c\\u094d\\u092f \\u0905\\u092e\\u0930\\u093f\\u0915\\u093e (Los Angeles)", "America/Los_Angeles" },
+ { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u0938\\u0902\\u092f\\u0941\\u0915\\u094d\\u0924 \\u0930\\u093e\\u091c\\u094d\\u092f \\u0905\\u092e\\u0930\\u093f\\u0915\\u093e (Los Angeles)", "America/Los_Angeles" },
+
+ { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0905\\u0930\\u094d\\u091c\\u0947\\u0928\\u094d\\u091f\\u0940\\u0928\\u093e (Buenos Aires)", "America/Buenos_Aires" },
+ { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0905\\u0930\\u094d\\u091c\\u0947\\u0928\\u094d\\u091f\\u0940\\u0928\\u093e (Buenos Aires)", "America/Buenos_Aires" },
+
+ { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0905\\u0930\\u094d\\u091c\\u0947\\u0928\\u094d\\u091f\\u0940\\u0928\\u093e (Buenos Aires)", "America/Buenos_Aires" },
+ { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0905\\u0930\\u094d\\u091c\\u0947\\u0928\\u094d\\u091f\\u0940\\u0928\\u093e (Buenos Aires)", "America/Buenos_Aires" },
+
+ { "hi", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
+ { "hi", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u096b:\\u0966\\u0966", "-5:00" },
+ { "hi", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-\\u0966\\u096b:\\u0966\\u0966", "-5:00" },
+ { "hi", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u096b:\\u0966\\u0966", "-5:00" },
+ { "hi", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
+ { "hi", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u096a:\\u0966\\u0966", "-4:00" },
+ { "hi", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-\\u0966\\u096a:\\u0966\\u0966", "-4:00" },
+ { "hi", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u096a:\\u0966\\u0966", "-4:00" },
+ { "hi", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e", "America/Havana" },
+ { "hi", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e", "America/Havana" },
+
+ { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+\\u0967\\u0967:\\u0966\\u0966", "+11:00" },
+ { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+\\u0967\\u0967:\\u0966\\u0966", "+11:00" },
+ { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+\\u0967\\u0967:\\u0966\\u0966", "+11:00" },
+ { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+\\u0967\\u0966:\\u0966\\u0966", "+10:00" },
+ { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+\\u0967\\u0966:\\u0966\\u0966", "+10:00" },
+ { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+\\u0967\\u0966:\\u0966\\u0966", "+10:00" },
+ { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0911\\u0938\\u094d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e (Sydney)", "Australia/Sydney" },
+ { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u0911\\u0938\\u094d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e (Sydney)", "Australia/Sydney" },
+
+ { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+\\u0967\\u0967:\\u0966\\u0966", "+11:00" },
+ { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+\\u0967\\u0967:\\u0966\\u0966", "+11:00" },
+ { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+\\u0967\\u0967:\\u0966\\u0966", "+11:00" },
+ { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+\\u0967\\u0966:\\u0966\\u0966", "+10:00" },
+ { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+\\u0967\\u0966:\\u0966\\u0966", "+10:00" },
+ { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+\\u0967\\u0966:\\u0966\\u0966", "+10:00" },
+ { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0911\\u0938\\u094d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e (Sydney)", "Australia/Sydney" },
+ { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u0911\\u0938\\u094d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e (Sydney)", "Australia/Sydney" },
+
+ { "hi", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
+ { "hi", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+\\u0966\\u0966:\\u0966\\u0966", "+0:00" },
+ { "hi", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+\\u0966\\u0966:\\u0966\\u0966", "+0:00" },
+ { "hi", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT+\\u0966\\u0966:\\u0966\\u0966", "+0:00" },
+ { "hi", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
+ { "hi", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+\\u0966\\u0967:\\u0966\\u0966", "+1:00" },
+ { "hi", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+\\u0966\\u0967:\\u0966\\u0966", "+1:00" },
+ { "hi", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+\\u0966\\u0967:\\u0966\\u0966", "+1:00" },
+ { "hi", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u092C\\u094D\\u0930\\u093F\\u0924\\u0928", "Europe/London" },
+ { "hi", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u092C\\u094D\\u0930\\u093F\\u0924\\u0928", "Europe/London" },
+
+ { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+ { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-\\u0966\\u0969:\\u0966\\u0966", "-3:00" },
+
+ { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+\\u0966\\u096B:\\u0969\\u0966", "+5:30" },
+ { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "IST", "+5:30" },
+ { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u0938\\u092E\\u092F", "+5:30" },
+ { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+\\u0966\\u096B:\\u0969\\u0966", "+5:30" },
+ { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "IST", "+05:30" },
+ { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u0938\\u092E\\u092F", "+5:30" },
+ { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "IST", "Asia/Calcutta" },
+ { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u0938\\u092E\\u092F", "Asia/Calcutta" },
+
+ // ==========
+
+ { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
+ { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0800", "-8:00" },
+ { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-0800", "America/Los_Angeles" },
+ { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "V", "PST", "America/Los_Angeles" },
+ { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u0422\\u0438\\u0445\\u043E\\u043E\\u043A\\u0435\\u0430\\u043D\\u0441\\u043A\\u0430 \\u0447\\u0430\\u0441\\u043E\\u0432\\u0430 \\u0437\\u043E\\u043D\\u0430", "America/Los_Angeles" },
+ { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
+ { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0700", "-7:00" },
+ { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-0700", "America/Los_Angeles" },
+ { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "V", "PDT", "America/Los_Angeles" },
+ { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u0422\\u0438\\u0445\\u043E\\u043E\\u043A\\u0435\\u0430\\u043D\\u0441\\u043A\\u0430 \\u043B\\u044F\\u0442\\u043D\\u0430 \\u0447\\u0430\\u0441\\u043E\\u0432\\u0430 \\u0437\\u043E\\u043D\\u0430", "America/Los_Angeles" },
+ // icu bg.txt has exemplar city for this time zone
+ { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u0421\\u0410\\u0429 (\\u041b\\u043e\\u0441 \\u0410\\u043d\\u0436\\u0435\\u043b\\u0438\\u0441)", "America/Los_Angeles" },
+ { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u0421\\u0410\\u0429 (\\u041b\\u043e\\u0441 \\u0410\\u043d\\u0436\\u0435\\u043b\\u0438\\u0441)", "America/Los_Angeles" },
+ { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\\u0421\\u0410\\u0429 (\\u041b\\u043e\\u0441 \\u0410\\u043d\\u0436\\u0435\\u043b\\u0438\\u0441)", "America/Los_Angeles" },
+
+ { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0410\\u0440\\u0436\\u0435\\u043d\\u0442\\u0438\\u043d\\u0430 (\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441)", "America/Buenos_Aires" },
+ { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0440\\u0436\\u0435\\u043d\\u0442\\u0438\\u043d\\u0430 (\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441)", "America/Buenos_Aires" },
+
+ { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ // icu bg.txt does not have info for this time zone
+ { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0410\\u0440\\u0436\\u0435\\u043d\\u0442\\u0438\\u043d\\u0430 (\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441)", "America/Buenos_Aires" },
+ { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0440\\u0436\\u0435\\u043d\\u0442\\u0438\\u043d\\u0430 (\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441)", "America/Buenos_Aires" },
+
+ { "bg", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
+ { "bg", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0500", "-5:00" },
+ { "bg", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-0500", "-5:00" },
+ { "bg", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-0500", "-5:00" },
+ { "bg", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
+ { "bg", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0400", "-4:00" },
+ { "bg", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-0400", "-4:00" },
+ { "bg", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-0400", "-4:00" },
+ { "bg", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u041a\\u0443\\u0431\\u0430", "America/Havana" },
+ { "bg", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u041a\\u0443\\u0431\\u0430", "America/Havana" },
+
+ { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+1100", "+11:00" },
+ { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+1100", "+11:00" },
+ { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+1100", "+11:00" },
+ { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+1000", "+10:00" },
+ { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+1000", "+10:00" },
+ { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+1000", "+10:00" },
+ { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0438\\u044f (\\u0421\\u0438\\u0434\\u043D\\u0438)", "Australia/Sydney" },
+ { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0438\\u044f (\\u0421\\u0438\\u0434\\u043D\\u0438)", "Australia/Sydney" },
+
+ { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+1100", "+11:00" },
+ { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+1100", "+11:00" },
+ { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+1100", "+11:00" },
+ { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+1000", "+10:00" },
+ { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+1000", "+10:00" },
+ { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+1000", "+10:00" },
+ { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0438\\u044f (\\u0421\\u0438\\u0434\\u043D\\u0438)", "Australia/Sydney" },
+ { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0438\\u044f (\\u0421\\u0438\\u0434\\u043D\\u0438)", "Australia/Sydney" },
+
+ { "bg", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
+ { "bg", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+0000", "+0:00" },
+ { "bg", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+0000", "+0:00" },
+ { "bg", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u0427\\u0430\\u0441\\u043E\\u0432\\u0430 \\u0437\\u043E\\u043D\\u0430 \\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
+ { "bg", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
+ { "bg", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+0100", "+1:00" },
+ { "bg", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+0100", "+1:00" },
+ { "bg", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+0100", "+1:00" },
+ { "bg", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u041e\\u0431\\u0435\\u0434\\u0438\\u043d\\u0435\\u043d\\u043e \\u043a\\u0440\\u0430\\u043b\\u0441\\u0442\\u0432\\u043e", "Europe/London" },
+ { "bg", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u041e\\u0431\\u0435\\u0434\\u0438\\u043d\\u0435\\u043d\\u043e \\u043a\\u0440\\u0430\\u043b\\u0441\\u0442\\u0432\\u043e", "Europe/London" },
+
+ { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-0300", "-3:00" },
+ { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-0300", "-3:00" },
+
+ // JB#5150
+ { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+0530", "+5:30" },
+ { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+0530", "+5:30" },
+ { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "GMT+0530", "+5:30" },
+ { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+0530", "+5:30" },
+ { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+0530", "+05:30" },
+ { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "GMT+0530", "+5:30" },
+ { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u0418\\u043D\\u0434\\u0438\\u044F", "Asia/Calcutta" },
+ { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u0418\\u043D\\u0434\\u0438\\u044F", "Asia/Calcutta" },
+
+ // ==========
+
+ { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
+ { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0800", "-8:00" },
+ { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-0800", "America/Los_Angeles" },
+ { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "V", "PST", "America/Los_Angeles" },
+ { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u592a\\u5e73\\u6d0b\\u6a19\\u6e96\\u6642", "America/Los_Angeles" },
+ { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
+ { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0700", "-7:00" },
+ { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-0700", "America/Los_Angeles" },
+ { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "V", "PDT", "America/Los_Angeles" },
+ { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u592a\\u5e73\\u6d0b\\u590f\\u6642\\u9593", "America/Los_Angeles" },
+ // icu ja.txt has exemplar city for this time zone
+ { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u30A2\\u30E1\\u30EA\\u30AB\\u5408\\u8846\\u56FD (\\u30ed\\u30b5\\u30f3\\u30bc\\u30eb\\u30b9)", "America/Los_Angeles" },
+ { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30E1\\u30EA\\u30AB\\u5408\\u8846\\u56FD (\\u30ed\\u30b5\\u30f3\\u30bc\\u30eb\\u30b9)", "America/Los_Angeles" },
+ { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\\u30A2\\u30E1\\u30EA\\u30AB\\u5408\\u8846\\u56FD (\\u30ed\\u30b5\\u30f3\\u30bc\\u30eb\\u30b9)", "America/Los_Angeles" },
+
+ { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ // icu ja.txt does not have info for this time zone
+ { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30a2\\u30eb\\u30bc\\u30f3\\u30c1\\u30f3 (\\u30A2\\u30E1\\u30EA\\u30AB/\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9)", "America/Buenos_Aires" },
+ { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u30a2\\u30eb\\u30bc\\u30f3\\u30c1\\u30f3 (\\u30A2\\u30E1\\u30EA\\u30AB/\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9)", "America/Buenos_Aires" },
+
+ { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ // icu ja.txt does not have info for this time zone
+ { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30a2\\u30eb\\u30bc\\u30f3\\u30c1\\u30f3 (\\u30A2\\u30E1\\u30EA\\u30AB/\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9)", "America/Buenos_Aires" },
+ { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u30a2\\u30eb\\u30bc\\u30f3\\u30c1\\u30f3 (\\u30A2\\u30E1\\u30EA\\u30AB/\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9)", "America/Buenos_Aires" },
+
+ { "ja", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
+ { "ja", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0500", "-5:00" },
+ { "ja", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-0500", "-5:00" },
+ { "ja", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-0500", "-5:00" },
+ { "ja", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
+ { "ja", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0400", "-4:00" },
+ { "ja", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-0400", "-4:00" },
+ { "ja", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-0400", "-4:00" },
+ { "ja", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
+ { "ja", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
+
+ { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+1100", "+11:00" },
+ { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+1100", "+11:00" },
+ { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+1100", "+11:00" },
+ { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+1000", "+10:00" },
+ { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+1000", "+10:00" },
+ { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+1000", "+10:00" },
+ // icu ja.txt does not have info for this time zone
+ { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u30aa\\u30fc\\u30b9\\u30c8\\u30e9\\u30ea\\u30a2 (\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2/\\u30B7\\u30C9\\u30CB\\u30FC)", "Australia/Sydney" },
+ { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u30aa\\u30fc\\u30b9\\u30c8\\u30e9\\u30ea\\u30a2 (\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2/\\u30B7\\u30C9\\u30CB\\u30FC)", "Australia/Sydney" },
+
+ { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+1100", "+11:00" },
+ { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+1100", "+11:00" },
+ { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+1100", "+11:00" },
+ { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+1000", "+10:00" },
+ { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+1000", "+10:00" },
+ { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+1000", "+10:00" },
+ { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u30aa\\u30fc\\u30b9\\u30c8\\u30e9\\u30ea\\u30a2 (\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2/\\u30B7\\u30C9\\u30CB\\u30FC)", "Australia/Sydney" },
+ { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u30aa\\u30fc\\u30b9\\u30c8\\u30e9\\u30ea\\u30a2 (\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2/\\u30B7\\u30C9\\u30CB\\u30FC)", "Australia/Sydney" },
+
+ { "ja", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
+ { "ja", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+0000", "+0:00" },
+ { "ja", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+0000", "+0:00" },
+ { "ja", "Europe/London", "2004-01-15T00:00:00Z", "V", "GMT", "+0:00" },
+ { "ja", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u30B0\\u30EA\\u30CB\\u30C3\\u30B8\\u6A19\\u6E96\\u6642", "+0:00" },
+ { "ja", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
+ { "ja", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+0100", "+1:00" },
+ { "ja", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+0100", "+1:00" },
+ { "ja", "Europe/London", "2004-07-15T00:00:00Z", "V", "GMT+0100", "+1:00" },
+ { "ja", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+0100", "+1:00" },
+ { "ja", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
+ { "ja", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
+ { "ja", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
+
+ { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-0300", "-3:00" },
+ { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-0300", "-3:00" },
+ { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-0300", "-3:00" },
+ { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-0300", "-3:00" },
+ { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-0300", "-3:00" },
+
+ // JB#5150
+ { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+0530", "+5:30" },
+ { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+0530", "+5:30" },
+ { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "GMT+0530", "+5:30" },
+ { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+0530", "+5:30" },
+ { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+0530", "+05:30" },
+ { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "GMT+0530", "+5:30" },
+ { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u30A4\\u30F3\\u30C9\\u6642\\u9593", "Asia/Calcutta" },
+ { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u30A4\\u30F3\\u30C9\\u6642\\u9593", "Asia/Calcutta" },
+
+ // ==========
+
+ { "as", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
+ { "as", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
+ { "as", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-08:00", "-8:00" },
+ { "as", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "GMT-08:00", "-8:00" },
+ { "as", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
+ { "as", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
+ { "as", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-07:00", "-7:00" },
+ { "as", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "GMT-07:00", "-7:00" },
+ { "as", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "US (Los Angeles)", "America/Los_Angeles" },
+ { "as", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "US (Los Angeles)", "America/Los_Angeles" },
+
+ { "as", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "as", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "as", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "as", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "as", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "as", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "as", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "as", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "as", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "AR (Buenos Aires)", "America/Buenos_Aires" },
+ { "as", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "AR (Buenos Aires)", "America/Buenos_Aires" },
+
+ { "as", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "as", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "as", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "as", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "as", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "as", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "as", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "as", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "as", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "AR (Buenos Aires)", "America/Buenos_Aires" },
+ { "as", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "AR (Buenos Aires)", "America/Buenos_Aires" },
+
+ { "as", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
+ { "as", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
+ { "as", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-05:00", "-5:00" },
+ { "as", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-05:00", "-5:00" },
+ { "as", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
+ { "as", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
+ { "as", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-04:00", "-4:00" },
+ { "as", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-04:00", "-4:00" },
+ { "as", "America/Havana", "2004-07-15T00:00:00Z", "v", "CU", "America/Havana" },
+ { "as", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "CU", "America/Havana" },
+
+ { "as", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "as", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
+ { "as", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+ { "as", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
+ { "as", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "as", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
+ { "as", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+ { "as", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
+ { "as", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "AU (Sydney)", "Australia/Sydney" },
+ { "as", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "AU (Sydney)", "Australia/Sydney" },
+
+ { "as", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
+ { "as", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
+ { "as", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11:00", "+11:00" },
+ { "as", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
+ { "as", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
+ { "as", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
+ { "as", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10:00", "+10:00" },
+ { "as", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
+ { "as", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "AU (Sydney)", "Australia/Sydney" },
+ { "as", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "AU (Sydney)", "Australia/Sydney" },
+
+ { "as", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
+ { "as", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+00:00", "+0:00" },
+ { "as", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT+00:00", "+0:00" },
+ { "as", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT+00:00", "+0:00" },
+ { "as", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
+ { "as", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
+ { "as", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+01:00", "+1:00" },
+ { "as", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "GMT+01:00", "+1:00" },
+ { "as", "Europe/London", "2004-07-15T00:00:00Z", "v", "GB", "Europe/London" },
+ { "as", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "GB", "Europe/London" },
+
+ { "as", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "as", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "as", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "as", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "as", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
+ { "as", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
+ { "as", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-03:00", "-3:00" },
+ { "as", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
+ { "as", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-03:00", "-3:00" },
+ { "as", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
+
+ // JB#5150
+ { "as", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "as", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
+ { "as", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "\\u09AD\\u09BE. \\u09B8.", "+5:30" },
+ { "as", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u09AD\\u09BE\\u09F0\\u09A4\\u09C0\\u09AF\\u09BC \\u09B8\\u09AE\\u09AF\\u09BC", "+5:30" },
+ { "as", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
+ { "as", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
+ { "as", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "\\u09AD\\u09BE. \\u09B8.", "+05:30" },
+ { "as", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u09AD\\u09BE\\u09F0\\u09A4\\u09C0\\u09AF\\u09BC \\u09B8\\u09AE\\u09AF\\u09BC", "+5:30" },
+ { "as", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u09AD\\u09BE. \\u09B8.", "Asia/Calcutta" },
+ { "as", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u09AD\\u09BE\\u09F0\\u09A4\\u09C0\\u09AF\\u09BC \\u09B8\\u09AE\\u09AF\\u09BC", "Asia/Calcutta" },
+ { "", "", "", "", "", "" },
+ };
+
+ if (isICUVersionAtLeast(ICU_39))
+ {
+ UErrorCode status;
+ Calendar *cal = GregorianCalendar::createInstance(status);
+ for (int i = 0; fallbackTests[i][0][0]; i++) {
+ UnicodeString info[5];
+ for ( int j = 0 ; j < 5 ; j++ ) {
+ UnicodeString value(fallbackTests[i][j],"");
+ value = value.unescape();
+ info[j].setTo(value);
+ }
+ logln(info[0] + ";" + info[1] + ";" + info[2] + ";" + info[3]);
+
+ TimeZone *tz = TimeZone::createTimeZone(info[1]);
+
+ if ( info[2] == UNICODE_STRING_SIMPLE("2004-07-15T00:00:00Z")) {
+ cal->set(2004,6,15,0,0,0);
+ } else {
+ cal->set(2004,0,15,0,0,0);
+ }
+
+ SimpleDateFormat *fmt = new SimpleDateFormat(info[3], Locale(fallbackTests[i][0]),status);
+ cal->setTimeZone(*tz);
+ UnicodeString result;
+ FieldPosition pos(0);
+ fmt->format(*cal,result,pos);
+ if (result != info[4]) {
+ errln(info[0] + ";" + info[1] + ";" + info[2] + ";" + info[3] + " expected: '" +
+ info[4] + "' but got: '" + result + "'");
+ }
+ }
+ } else {
+ logln("Warning: Skipping TestTimeZoneDisplayName. TODO: Fix in ICU 4.0");
+ }
+}
+
+/*
+void DateFormatTest::TestRelativeError(void)
+{
+ UErrorCode status;
+ Locale en("en");
+
+ DateFormat *en_reltime_reldate = DateFormat::createDateTimeInstance(DateFormat::kFullRelative,DateFormat::kFullRelative,en);
+ if(en_reltime_reldate == NULL) {
+ logln("PASS: rel date/rel time failed");
+ } else {
+ errln("FAIL: rel date/rel time created, should have failed.");
+ delete en_reltime_reldate;
+ }
+}
+
+void DateFormatTest::TestRelativeOther(void)
+{
+ logln("Nothing in this test. When we get more data from CLDR, put in some tests of -2, +2, etc. ");
+}
+*/
+
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtfmttst.h b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmttst.h
new file mode 100644
index 00000000000..091c459786e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtfmttst.h
@@ -0,0 +1,217 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _DATEFORMATTEST_
+#define _DATEFORMATTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "caltztst.h"
+
+/**
+ * Performs many different tests for DataeFormat and SimpleDateFormat
+ **/
+class DateFormatTest: public CalendarTimeZoneTest {
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+ /**
+ * "Test written by Wally Wedel and emailed to me."
+ * Test handling of timezone offsets
+ **/
+ virtual void TestWallyWedel(void);
+ /**
+ * Test operator==
+ */
+ virtual void TestEquals(void);
+ /**
+ * Test the parsing of 2-digit years.
+ */
+ virtual void TestTwoDigitYearDSTParse(void);
+
+public: // package
+ // internal utility routine (genrates escape sequences for characters)
+ static UnicodeString& escape(UnicodeString& s);
+
+public:
+ /**
+ * Verify that returned field position indices are correct.
+ */
+ void TestFieldPosition(void);
+
+ void TestGeneral();
+
+public: // package
+ // internal utility function
+ static void getFieldText(DateFormat* df, int32_t field, UDate date, UnicodeString& str);
+
+public:
+ /**
+ * Verify that strings which contain incomplete specifications are parsed
+ * correctly. In some instances, this means not being parsed at all, and
+ * returning an appropriate error.
+ */
+ virtual void TestPartialParse994(void);
+
+public: // package
+ // internal test subroutine, used by TestPartialParse994
+ virtual void tryPat994(SimpleDateFormat* format, const char* pat, const char* str, UDate expected);
+
+public:
+ /**
+ * Verify the behavior of patterns in which digits for different fields run together
+ * without intervening separators.
+ */
+ virtual void TestRunTogetherPattern985(void);
+ /**
+ * Verify the behavior of patterns in which digits for different fields run together
+ * without intervening separators.
+ */
+ virtual void TestRunTogetherPattern917(void);
+
+public: // package
+ // internal test subroutine, used by TestRunTogetherPattern917
+ virtual void testIt917(SimpleDateFormat* fmt, UnicodeString& str, UDate expected);
+
+public:
+ /**
+ * Verify the handling of Czech June and July, which have the unique attribute that
+ * one is a proper prefix substring of the other.
+ */
+ virtual void TestCzechMonths459(void);
+ /**
+ * Test the handling of 'D' in patterns.
+ */
+ virtual void TestLetterDPattern212(void);
+ /**
+ * Test the day of year pattern.
+ */
+ virtual void TestDayOfYearPattern195(void);
+
+public: // package
+ // interl test subroutine, used by TestDayOfYearPattern195
+ virtual void tryPattern(SimpleDateFormat& sdf, UDate d, const char* pattern, UDate expected);
+
+public:
+ /**
+ * Test the handling of single quotes in patterns.
+ */
+ virtual void TestQuotePattern161(void);
+ /**
+ * Verify the correct behavior when handling invalid input strings.
+ */
+ virtual void TestBadInput135(void);
+
+public:
+ /**
+ * Verify the correct behavior when parsing an array of inputs against an
+ * array of patterns, with known results. The results are encoded after
+ * the input strings in each row.
+ */
+ virtual void TestBadInput135a(void);
+ /**
+ * Test the parsing of two-digit years.
+ */
+ virtual void TestTwoDigitYear(void);
+
+public: // package
+ // internal test subroutine, used by TestTwoDigitYear
+ virtual void parse2DigitYear(DateFormat& fmt, const char* str, UDate expected);
+
+public:
+ /**
+ * Test the formatting of time zones.
+ */
+ virtual void TestDateFormatZone061(void);
+ /**
+ * Further test the formatting of time zones.
+ */
+ virtual void TestDateFormatZone146(void);
+
+ void TestTimeZoneStringsAPI(void);
+
+public: // package
+ /**
+ * Test the formatting of dates in different locales.
+ */
+ virtual void TestLocaleDateFormat(void);
+
+ virtual void TestDateFormatCalendar(void);
+
+ virtual void TestSpaceParsing(void);
+
+ void TestExactCountFormat(void);
+
+ void TestWhiteSpaceParsing(void);
+
+ void TestInvalidPattern(void);
+
+ void TestGreekMay(void);
+
+ void TestGenericTime(void);
+
+ void TestGenericTimeZoneOrder(void);
+
+public:
+ /**
+ * Test host-specific formatting.
+ */
+ void TestHost(void);
+
+public:
+ /**
+ * Test patterns added in CLDR 1.4
+ */
+ void TestEras(void);
+
+ void TestNarrowNames(void);
+
+ void TestStandAloneDays(void);
+
+ void TestStandAloneMonths(void);
+
+ void TestQuarters(void);
+
+ void TestZTimeZoneParsing(void);
+
+ void TestRelativeClone(void);
+
+ void TestHostClone(void);
+
+public:
+ /***
+ * Test Relative Dates
+ */
+ void TestRelative(void);
+ void TestTimeZoneDisplayName(void);
+/* void TestRelativeError(void);
+ void TestRelativeOther(void);
+*/
+
+ private:
+ void TestRelative(int daysdelta,
+ const Locale& loc,
+ const char *expectChars);
+
+ private:
+ void expectParse(const char** data, int32_t data_length,
+ const Locale& locale);
+
+ void expect(const char** data, int32_t data_length,
+ const Locale& loc);
+
+ void expectFormat(const char **data, int32_t data_length,
+ const Locale &locale);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DATEFORMATTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtptngts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/dtptngts.cpp
new file mode 100644
index 00000000000..11dc9e601b7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtptngts.cpp
@@ -0,0 +1,442 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "dtptngts.h"
+
+#include "unicode/calendar.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/dtptngen.h"
+#include "loctest.h"
+
+
+// This is an API test, not a unit test. It doesn't test very many cases, and doesn't
+// try to test the full functionality. It just calls each function in the class and
+// verifies that it works on a basic level.
+
+void IntlTestDateTimePatternGeneratorAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite DateTimePatternGeneratorAPI");
+ switch (index) {
+ TESTCASE(0, testAPI);
+ default: name = ""; break;
+ }
+}
+
+#define MAX_LOCALE 4
+
+/**
+ * Test various generic API methods of DateTimePatternGenerator for API coverage.
+ */
+void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/)
+{
+ UnicodeString patternData[] = {
+ UnicodeString("yM"),
+ UnicodeString("yMMM"),
+ UnicodeString("yMd"),
+ UnicodeString("yMMMd"),
+ UnicodeString("Md"),
+ UnicodeString("MMMd"),
+ UnicodeString("yQQQ"),
+ UnicodeString("hhmm"),
+ UnicodeString("HHmm"),
+ UnicodeString("mmss"),
+ UnicodeString(),
+ };
+
+ const char* testLocale[MAX_LOCALE][3] = {
+ {"en", "US", ""},
+ {"zh", "Hans", "CN"},
+ {"de", "DE", ""},
+ {"fi", "", ""},
+ };
+
+ UnicodeString patternResults[] = {
+ UnicodeString("1/1999"), // en_US
+ UnicodeString("Jan 1999"),
+ UnicodeString("1/13/1999"),
+ UnicodeString("Jan/13/1999"),
+ UnicodeString("1/13"),
+ UnicodeString("Jan 13"),
+ UnicodeString("Q1 1999"),
+ UnicodeString("11:58 PM"),
+ UnicodeString("23:58"),
+ UnicodeString("58:59"),
+ UnicodeString("1999-1"), // zh_Hans_CN
+ UnicodeString("1999 1"),
+ CharsToUnicodeString("1999\\u5E741\\u670813\\u65E5"),
+ CharsToUnicodeString("1999\\u5E741\\u670813\\u65E5"),
+ UnicodeString("1-13"),
+ UnicodeString("1 13"),
+ CharsToUnicodeString("1999 Q1"),
+ CharsToUnicodeString("\\u4E0B\\u534811:58"),
+ CharsToUnicodeString("23:58"),
+ UnicodeString("58:59"),
+ UnicodeString("1.1999"), // de_DE
+ UnicodeString("Jan 1999"),
+ UnicodeString("13.1.1999"),
+ UnicodeString("13. Jan 1999"),
+ UnicodeString("13.1."),
+ UnicodeString("13. Jan"),
+ UnicodeString("Q1 1999"),
+ UnicodeString("23:58"),
+ UnicodeString("23:58"),
+ UnicodeString("58:59"),
+ UnicodeString("1/1999"), // fi
+ UnicodeString("tammi 1999"),
+ UnicodeString("13.1.1999"),
+ UnicodeString("13. tammita 1999"),
+ UnicodeString("13.1."),
+ UnicodeString("13. tammita"),
+ UnicodeString("1. nelj./1999"),
+ UnicodeString("23.58"),
+ UnicodeString("23.58"),
+ UnicodeString("58.59"),
+ UnicodeString(),
+ };
+
+ // results for getSkeletons() and getPatternForSkeleton()
+ const UnicodeString testSkeletonsResults[] = {
+ UnicodeString("HH:mm"),
+ UnicodeString("MMMMd"),
+ UnicodeString("MMMMMd"),
+ };
+
+ const UnicodeString testBaseSkeletonsResults[] = {
+ UnicodeString("Hm"),
+ UnicodeString("MMMd"),
+ UnicodeString("MMMd"),
+ };
+
+ UnicodeString newDecimal(" "); // space
+ UnicodeString newAppendItemName("hrs.");
+ UnicodeString newAppendItemFormat("{1} {0}");
+ UnicodeString newDateTimeFormat("{1} {0}");
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString conflictingPattern;
+ UDateTimePatternConflict conflictingStatus;
+
+ // ======= Test CreateInstance with default locale
+ logln("Testing DateTimePatternGenerator createInstance from default locale");
+
+ DateTimePatternGenerator *instFromDefaultLocale=DateTimePatternGenerator::createInstance(status);
+ if (U_FAILURE(status)) {
+ dataerrln("ERROR: Could not create DateTimePatternGenerator (default) - exitting");
+ return;
+ }
+ else {
+ delete instFromDefaultLocale;
+ }
+
+ // ======= Test CreateInstance with given locale
+ logln("Testing DateTimePatternGenerator createInstance from French locale");
+ status = U_ZERO_ERROR;
+ DateTimePatternGenerator *instFromLocale=DateTimePatternGenerator::createInstance(Locale::getFrench(), status);
+ if (U_FAILURE(status)) {
+ dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getFrench()) - exitting");
+ return;
+ }
+
+ // ======= Test clone DateTimePatternGenerator
+ logln("Testing DateTimePatternGenerator::clone()");
+ status = U_ZERO_ERROR;
+
+
+ UnicodeString decimalSymbol = instFromLocale->getDecimal();
+ UnicodeString newDecimalSymbol = UnicodeString("*");
+ decimalSymbol = instFromLocale->getDecimal();
+ instFromLocale->setDecimal(newDecimalSymbol);
+ DateTimePatternGenerator *cloneDTPatternGen=instFromLocale->clone();
+ decimalSymbol = cloneDTPatternGen->getDecimal();
+ if (decimalSymbol != newDecimalSymbol) {
+ errln("ERROR: inconsistency is found in cloned object.");
+ }
+ if ( !(*cloneDTPatternGen == *instFromLocale) ) {
+ errln("ERROR: inconsistency is found in cloned object.");
+ }
+
+ if ( *cloneDTPatternGen != *instFromLocale ) {
+ errln("ERROR: inconsistency is found in cloned object.");
+ }
+
+ delete instFromLocale;
+ delete cloneDTPatternGen;
+
+ // ======= Test simple use cases
+ logln("Testing simple use cases");
+ status = U_ZERO_ERROR;
+ Locale deLocale=Locale::getGermany();
+ UDate sampleDate=LocaleTest::date(99, 9, 13, 23, 58, 59);
+ DateTimePatternGenerator *gen = DateTimePatternGenerator::createInstance(deLocale, status);
+ if (U_FAILURE(status)) {
+ dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getGermany()) - exitting");
+ return;
+ }
+ UnicodeString findPattern = gen->getBestPattern(UnicodeString("MMMddHmm"), status);
+ SimpleDateFormat *format = new SimpleDateFormat(findPattern, deLocale, status);
+ if (U_FAILURE(status)) {
+ dataerrln("ERROR: Could not create SimpleDateFormat (Locale::getGermany())");
+ delete gen;
+ return;
+ }
+ TimeZone *zone = TimeZone::createTimeZone(UnicodeString("ECT"));
+ if (zone==NULL) {
+ dataerrln("ERROR: Could not create TimeZone ECT");
+ delete gen;
+ delete format;
+ return;
+ }
+ format->setTimeZone(*zone);
+ UnicodeString dateReturned, expectedResult;
+ dateReturned.remove();
+ dateReturned = format->format(sampleDate, dateReturned, status);
+ expectedResult=UnicodeString("8:58 14. Okt");
+ if ( dateReturned != expectedResult ) {
+ errln("ERROR: Simple test in getBestPattern with Locale::getGermany()).");
+ }
+ // add new pattern
+ status = U_ZERO_ERROR;
+ conflictingStatus = gen->addPattern(UnicodeString("d'. von' MMMM"), true, conflictingPattern, status);
+ if (U_FAILURE(status)) {
+ errln("ERROR: Could not addPattern - d\'. von\' MMMM");
+ }
+ status = U_ZERO_ERROR;
+ UnicodeString testPattern=gen->getBestPattern(UnicodeString("MMMMdd"), status);
+ testPattern=gen->getBestPattern(UnicodeString("MMMddHmm"), status);
+ format->applyPattern(gen->getBestPattern(UnicodeString("MMMMddHmm"), status));
+ dateReturned.remove();
+ dateReturned = format->format(sampleDate, dateReturned, status);
+ expectedResult=UnicodeString("8:58 14. von Oktober");
+ if ( dateReturned != expectedResult ) {
+ errln("ERROR: Simple test addPattern failed!: d\'. von\' MMMM ");
+ }
+ delete format;
+
+ // get a pattern and modify it
+ format = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull,
+ deLocale);
+ format->setTimeZone(*zone);
+ UnicodeString pattern;
+ pattern = format->toPattern(pattern);
+ dateReturned.remove();
+ dateReturned = format->format(sampleDate, dateReturned, status);
+ expectedResult=UnicodeString("Donnerstag, 14. Oktober 1999 08:58:59 Frankreich");
+ if ( dateReturned != expectedResult ) {
+ errln("ERROR: Simple test uses full date format.");
+ errln(UnicodeString(" Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult);
+ }
+
+ // modify it to change the zone.
+ UnicodeString newPattern = gen->replaceFieldTypes(pattern, UnicodeString("vvvv"), status);
+ format->applyPattern(newPattern);
+ dateReturned.remove();
+ dateReturned = format->format(sampleDate, dateReturned, status);
+ expectedResult=UnicodeString("Donnerstag, 14. Oktober 1999 08:58:59 Frankreich");
+ if ( dateReturned != expectedResult ) {
+ errln("ERROR: Simple test modify the timezone!");
+ errln(UnicodeString(" Got: ")+ dateReturned + UnicodeString(" Expected: ") + expectedResult);
+ }
+
+ // setDeciaml(), getDeciaml()
+ gen->setDecimal(newDecimal);
+ if (newDecimal != gen->getDecimal()) {
+ errln("ERROR: unexpected result from setDecimal() and getDecimal()!.\n");
+ }
+
+ // setAppenItemName() , getAppendItemName()
+ gen->setAppendItemName(UDATPG_HOUR_FIELD, newAppendItemName);
+ if (newAppendItemName != gen->getAppendItemName(UDATPG_HOUR_FIELD)) {
+ errln("ERROR: unexpected result from setAppendItemName() and getAppendItemName()!.\n");
+ }
+
+ // setAppenItemFormat() , getAppendItemFormat()
+ gen->setAppendItemFormat(UDATPG_HOUR_FIELD, newAppendItemFormat);
+ if (newAppendItemFormat != gen->getAppendItemFormat(UDATPG_HOUR_FIELD)) {
+ errln("ERROR: unexpected result from setAppendItemFormat() and getAppendItemFormat()!.\n");
+ }
+
+ // setDateTimeFormat() , getDateTimeFormat()
+ gen->setDateTimeFormat(newDateTimeFormat);
+ if (newDateTimeFormat != gen->getDateTimeFormat()) {
+ errln("ERROR: unexpected result from setDateTimeFormat() and getDateTimeFormat()!.\n");
+ }
+
+ // ======== Test getSkeleton and getBaseSkeleton
+ status = U_ZERO_ERROR;
+ pattern = UnicodeString("dd-MMM");
+ UnicodeString expectedSkeleton = UnicodeString("MMMdd");
+ UnicodeString expectedBaseSkeleton = UnicodeString("MMMd");
+ UnicodeString retSkeleton = gen->getSkeleton(pattern, status);
+ if(U_FAILURE(status) || retSkeleton != expectedSkeleton ) {
+ errln("ERROR: Unexpected result from getSkeleton().\n");
+ errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected: ") + expectedSkeleton );
+ }
+ retSkeleton = gen->getBaseSkeleton(pattern, status);
+ if(U_FAILURE(status) || retSkeleton != expectedBaseSkeleton) {
+ errln("ERROR: Unexpected result from getBaseSkeleton().\n");
+ errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected:")+ expectedBaseSkeleton);
+ }
+
+ pattern = UnicodeString("dd/MMMM/yy");
+ expectedSkeleton = UnicodeString("yyMMMMdd");
+ expectedBaseSkeleton = UnicodeString("yMMMd");
+ retSkeleton = gen->getSkeleton(pattern, status);
+ if(U_FAILURE(status) || retSkeleton != expectedSkeleton ) {
+ errln("ERROR: Unexpected result from getSkeleton().\n");
+ errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected: ") + expectedSkeleton );
+ }
+ retSkeleton = gen->getBaseSkeleton(pattern, status);
+ if(U_FAILURE(status) || retSkeleton != expectedBaseSkeleton) {
+ errln("ERROR: Unexpected result from getBaseSkeleton().\n");
+ errln(UnicodeString(" Got: ") + retSkeleton + UnicodeString(" Expected:")+ expectedBaseSkeleton);
+ }
+ delete format;
+ delete zone;
+ delete gen;
+
+ // ======= Test various skeletons.
+ logln("Testing DateTimePatternGenerator with various skeleton");
+
+ status = U_ZERO_ERROR;
+ int32_t localeIndex=0;
+ int32_t resultIndex=0;
+ UnicodeString resultDate;
+ UDate testDate= LocaleTest::date(99, 0, 13, 23, 58, 59);
+ while (localeIndex < MAX_LOCALE )
+ {
+ int32_t dataIndex=0;
+ UnicodeString bestPattern;
+
+ Locale loc(testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2], "");
+ logln("\n\n Locale: %s_%s_%s", testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2]);
+ DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status);
+ if(U_FAILURE(status)) {
+ dataerrln("ERROR: Could not create DateTimePatternGenerator with locale index:%d . - exitting\n", localeIndex);
+ return;
+ }
+ while (patternData[dataIndex].length() > 0) {
+ log(patternData[dataIndex]);
+ bestPattern = patGen->getBestPattern(patternData[dataIndex++], status);
+ logln(UnicodeString(" -> ") + bestPattern);
+
+ SimpleDateFormat sdf(bestPattern, loc, status);
+ resultDate.remove();
+ resultDate = sdf.format(testDate, resultDate);
+ if ( resultDate != patternResults[resultIndex] ) {
+ errln(UnicodeString("\nERROR: Test various skeletons[") + (dataIndex-1)
+ + UnicodeString("]. Got: ") + resultDate + UnicodeString(" Expected: ") + patternResults[resultIndex] );
+ }
+
+ resultIndex++;
+ }
+ delete patGen;
+ localeIndex++;
+ }
+
+
+
+ // ======= Test random skeleton
+ DateTimePatternGenerator *randDTGen= DateTimePatternGenerator::createInstance(status);
+ if (U_FAILURE(status)) {
+ dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getFrench()) - exitting");
+ return;
+ }
+ UChar newChar;
+ int32_t i;
+ for (i=0; i<10; ++i) {
+ UnicodeString randomSkeleton;
+ int32_t len = rand() % 20;
+ for (int32_t j=0; j<len; ++j ) {
+ while ((newChar = (UChar)(rand()%0x7f))>=(UChar)0x20) {
+ randomSkeleton += newChar;
+ }
+ }
+ UnicodeString bestPattern = randDTGen->getBestPattern(randomSkeleton, status);
+ }
+ delete randDTGen;
+
+ // UnicodeString randomString=Unicode
+ // ======= Test getStaticClassID()
+
+ logln("Testing getStaticClassID()");
+ status = U_ZERO_ERROR;
+ DateTimePatternGenerator *test= DateTimePatternGenerator::createInstance(status);
+
+ if(test->getDynamicClassID() != DateTimePatternGenerator::getStaticClassID()) {
+ errln("ERROR: getDynamicClassID() didn't return the expected value");
+ }
+ delete test;
+
+ // ====== Test createEmptyInstance()
+
+ logln("Testing createEmptyInstance()");
+ status = U_ZERO_ERROR;
+
+ test = DateTimePatternGenerator::createEmptyInstance(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Fail to create an empty instance ! - exitting.\n");
+ delete test;
+ return;
+ }
+
+ conflictingStatus = test->addPattern(UnicodeString("MMMMd"), true, conflictingPattern, status);
+ status = U_ZERO_ERROR;
+ testPattern=test->getBestPattern(UnicodeString("MMMMdd"), status);
+ conflictingStatus = test->addPattern(UnicodeString("HH:mm"), true, conflictingPattern, status);
+ conflictingStatus = test->addPattern(UnicodeString("MMMMMd"), true, conflictingPattern, status); //duplicate pattern
+ StringEnumeration *output=NULL;
+ output = test->getRedundants(status);
+ expectedResult=UnicodeString("MMMMd");
+ if (output != NULL) {
+ output->reset(status);
+ const UnicodeString *dupPattern=output->snext(status);
+ if ( (dupPattern==NULL) || (*dupPattern != expectedResult) ) {
+ errln("ERROR: Fail in getRedundants !\n");
+ }
+ }
+
+ // ======== Test getSkeletons and getBaseSkeletons
+ StringEnumeration* ptrSkeletonEnum = test->getSkeletons(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Fail to get skeletons !\n");
+ }
+ UnicodeString returnPattern, *ptrSkeleton;
+ ptrSkeletonEnum->reset(status);
+ int32_t count=ptrSkeletonEnum->count(status);
+ for (i=0; i<count; ++i) {
+ ptrSkeleton = (UnicodeString *)ptrSkeletonEnum->snext(status);
+ returnPattern = test->getPatternForSkeleton(*ptrSkeleton);
+ if ( returnPattern != testSkeletonsResults[i] ) {
+ errln(UnicodeString("ERROR: Unexpected result from getSkeletons and getPatternForSkeleton\nGot: ") + returnPattern
+ + UnicodeString("\nExpected: ") + testSkeletonsResults[i]
+ + UnicodeString("\n"));
+ }
+ }
+ StringEnumeration* ptrBaseSkeletonEnum = test->getBaseSkeletons(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Fail to get base skeletons !\n");
+ }
+ count=ptrBaseSkeletonEnum->count(status);
+ for (i=0; i<count; ++i) {
+ ptrSkeleton = (UnicodeString *)ptrBaseSkeletonEnum->snext(status);
+ if ( *ptrSkeleton != testBaseSkeletonsResults[i] ) {
+ errln("ERROR: Unexpected result from getBaseSkeletons() !\n");
+ }
+ }
+
+ delete output;
+ delete ptrSkeletonEnum;
+ delete ptrBaseSkeletonEnum;
+ delete test;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/dtptngts.h b/Build/source/libs/icu/icu-xetex/test/intltest/dtptngts.h
new file mode 100644
index 00000000000..6834c7d5b4a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/dtptngts.h
@@ -0,0 +1,31 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _INTLTESTDATETIMEPATTERNGENERATORAPI
+#define _INTLTESTDATETIMEPATTERNGENERATORAPI
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+/**
+ * Test basic functionality of various API functions
+ **/
+class IntlTestDateTimePatternGeneratorAPI : public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+private:
+ /**
+ * Performs tests on many API functions, see detailed comments in source code
+ **/
+ void testAPI(/* char* par */);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/encoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/encoll.cpp
new file mode 100644
index 00000000000..abaeb561573
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/encoll.cpp
@@ -0,0 +1,334 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/unistr.h"
+#include "unicode/sortkey.h"
+#include "encoll.h"
+
+CollationEnglishTest::CollationEnglishTest()
+: myCollation(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation = Collator::createInstance(Locale::getEnglish(), status);
+}
+
+CollationEnglishTest::~CollationEnglishTest()
+{
+ delete myCollation;
+}
+
+static const UChar testSourceCases[][CollationEnglishTest::MAX_TOKEN_LEN] = {
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x002D /* '-' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x0020 /* ' ' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x002D /* '-' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0048 /* 'H' */, (UChar)0x0065 /* 'e' */, (UChar)0x006C /* 'l' */, (UChar)0x006C /* 'l' */, (UChar)0x006F /* 'o' */, 0},
+ {(UChar)0x0041 /* 'A' */, (UChar)0x0042 /* 'B' */, (UChar)0x0043 /* 'C' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x002D /* '-' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x002D /* '-' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00EA, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, (UChar)0x0065 /* 'e' */, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00E9, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, 0x00E9, 0},
+ {0x00C4, (UChar)0x0042 /* 'B' */, 0x0308, (UChar)0x0043 /* 'C' */, 0x0308, 0},
+ {(UChar)0x0061 /* 'a' */, 0x0308, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00E9, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, (UChar)0x0065 /* 'e' */, (UChar)0x0072 /* 'r' */, 0},
+ {(UChar)0x0072 /* 'r' */, (UChar)0x006F /* 'o' */, (UChar)0x006C /* 'l' */, (UChar)0x0065 /* 'e' */, (UChar)0x0073 /* 's' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0041 /* 'A' */, 0},
+ {(UChar)0x0041 /* 'A' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, 0},
+ {(UChar)0x0074 /* 't' */, (UChar)0x0063 /* 'c' */, (UChar)0x006F /* 'o' */, (UChar)0x006D /* 'm' */, (UChar)0x0070 /* 'p' */, (UChar)0x0061 /* 'a' */, (UChar)0x0072 /* 'r' */, (UChar)0x0065 /* 'e' */, (UChar)0x0070 /* 'p' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0069 /* 'i' */, (UChar)0x006E /* 'n' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0023 /* '#' */, (UChar)0x0062 /* 'b' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0023 /* '#' */, (UChar)0x0062 /* 'b' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0041 /* 'A' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {0x00E6, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {0x00E4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x0048 /* 'H' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, 0x0308, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0074 /* 't' */, (UChar)0x0068 /* 'h' */, (UChar)0x0069 /* 'i' */, 0x0302, (UChar)0x0073 /* 's' */, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00EA, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, (UChar)0x0065 /* 'e' */},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, 0x00E6, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, 0x00E6, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00E9, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, 0x00E9, 0} // 49
+};
+
+static const UChar testTargetCases[][CollationEnglishTest::MAX_TOKEN_LEN] = {
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x002D /* '-' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, 0},
+ {(UChar)0x0068 /* 'h' */, (UChar)0x0065 /* 'e' */, (UChar)0x006C /* 'l' */, (UChar)0x006C /* 'l' */, (UChar)0x006F /* 'o' */, 0},
+ {(UChar)0x0041 /* 'A' */, (UChar)0x0042 /* 'B' */, (UChar)0x0043 /* 'C' */, 0},
+ {(UChar)0x0041 /* 'A' */, (UChar)0x0042 /* 'B' */, (UChar)0x0043 /* 'C' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, (UChar)0x0073 /* 's' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, (UChar)0x0073 /* 's' */, 0},
+ {(UChar)0x0062 /* 'b' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0063 /* 'c' */, (UChar)0x006B /* 'k' */, (UChar)0x0062 /* 'b' */, (UChar)0x0069 /* 'i' */, (UChar)0x0072 /* 'r' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00E9, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, 0x00E9, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00E9, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, (UChar)0x0065 /* 'e' */, (UChar)0x0072 /* 'r' */, 0},
+ {0x00C4, (UChar)0x0042 /* 'B' */, 0x0308, (UChar)0x0043 /* 'C' */, 0x0308, 0},
+ {(UChar)0x0041 /* 'A' */, 0x0308, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00E9, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, (UChar)0x0065 /* 'e' */, 0},
+ {(UChar)0x0072 /* 'r' */, (UChar)0x006F /* 'o' */, 0x0302, (UChar)0x006C /* 'l' */, (UChar)0x0065 /* 'e' */, 0},
+ {(UChar)0x0041 /* 'A' */, 0x00E1, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0041 /* 'A' */, 0x00E1, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0054 /* 'T' */, (UChar)0x0043 /* 'C' */, (UChar)0x006F /* 'o' */, (UChar)0x006D /* 'm' */, (UChar)0x0070 /* 'p' */, (UChar)0x0061 /* 'a' */, (UChar)0x0072 /* 'r' */, (UChar)0x0065 /* 'e' */, (UChar)0x0050 /* 'P' */, (UChar)0x006C /* 'l' */, (UChar)0x0061 /* 'a' */, (UChar)0x0069 /* 'i' */, (UChar)0x006E /* 'n' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0042 /* 'B' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0023 /* '#' */, (UChar)0x0042 /* 'B' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0026 /* '&' */, (UChar)0x0062 /* 'b' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0023 /* '#' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {0x00C4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {0x00E4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {0x00C4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {0x00C4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, (UChar)0x0064 /* 'd' */, (UChar)0x0061 /* 'a' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0023 /* '#' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x003D /* '=' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0064 /* 'd' */, 0},
+ {0x00E4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0043 /* 'C' */, (UChar)0x0048 /* 'H' */, (UChar)0x0063 /* 'c' */, 0},
+ {0x00E4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0074 /* 't' */, (UChar)0x0068 /* 'h' */, 0x00EE, (UChar)0x0073 /* 's' */, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00E9, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, 0x00E9, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0042 /* 'B' */, (UChar)0x0043 /* 'C' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0062 /* 'b' */, (UChar)0x0064 /* 'd' */, 0},
+ {0x00E4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, 0x00C6, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0042 /* 'B' */, (UChar)0x0064 /* 'd' */, 0},
+ {0x00E4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, 0x00C6, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0042 /* 'B' */, (UChar)0x0064 /* 'd' */, 0},
+ {0x00E4, (UChar)0x0062 /* 'b' */, (UChar)0x0063 /* 'c' */, 0},
+ {(UChar)0x0070 /* 'p' */, 0x00EA, (UChar)0x0063 /* 'c' */, (UChar)0x0068 /* 'h' */, (UChar)0x0065 /* 'e' */, 0} // 49
+};
+
+static const Collator::EComparisonResult results[] = {
+ Collator::LESS,
+ Collator::LESS, /*Collator::GREATER,*/
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::GREATER,
+ Collator::EQUAL,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS, /*Collator::GREATER,*/ /* 10 */
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::EQUAL,
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::GREATER,
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS, /* 20 */
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::GREATER,
+ Collator::GREATER,
+ /* Test Tertiary > 26 */
+ Collator::LESS,
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::LESS, /* 30 */
+ Collator::GREATER,
+ Collator::EQUAL,
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS,
+ /* test identical > 36 */
+ Collator::EQUAL,
+ Collator::EQUAL,
+ /* test primary > 38 */
+ Collator::EQUAL,
+ Collator::EQUAL, /* 40 */
+ Collator::LESS,
+ Collator::EQUAL,
+ Collator::EQUAL,
+ /* test secondary > 43 */
+ Collator::LESS,
+ Collator::LESS,
+ Collator::EQUAL,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS // 49
+};
+
+static const UChar testBugs[][CollationEnglishTest::MAX_TOKEN_LEN] = {
+ {0x61, 0},
+ {0x41, 0},
+ {0x65, 0},
+ {0x45, 0},
+ {0x00e9, 0},
+ {0x00e8, 0},
+ {0x00ea, 0},
+ {0x00eb, 0},
+ {0x65, 0x61, 0},
+ {0x78, 0}
+};
+
+// 0x0300 is grave, 0x0301 is acute
+// the order of elements in this array must be different than the order in CollationFrenchTest
+static const UChar testAcute[][CollationEnglishTest::MAX_TOKEN_LEN] = {
+ {0x65, 0x65, 0},
+ {0x65, 0x65, 0x0301, 0},
+ {0x65, 0x65, 0x0301, 0x0300, 0},
+ {0x65, 0x65, 0x0300, 0},
+ {0x65, 0x65, 0x0300, 0x0301, 0},
+ {0x65, 0x0301, 0x65, 0},
+ {0x65, 0x0301, 0x65, 0x0301, 0},
+ {0x65, 0x0301, 0x65, 0x0301, 0x0300, 0},
+ {0x65, 0x0301, 0x65, 0x0300, 0},
+ {0x65, 0x0301, 0x65, 0x0300, 0x0301, 0},
+ {0x65, 0x0301, 0x0300, 0x65, 0},
+ {0x65, 0x0301, 0x0300, 0x65, 0x0301, 0},
+ {0x65, 0x0301, 0x0300, 0x65, 0x0301, 0x0300, 0},
+ {0x65, 0x0301, 0x0300, 0x65, 0x0300, 0},
+ {0x65, 0x0301, 0x0300, 0x65, 0x0300, 0x0301, 0},
+ {0x65, 0x0300, 0x65, 0},
+ {0x65, 0x0300, 0x65, 0x0301, 0},
+ {0x65, 0x0300, 0x65, 0x0301, 0x0300, 0},
+ {0x65, 0x0300, 0x65, 0x0300, 0},
+ {0x65, 0x0300, 0x65, 0x0300, 0x0301, 0},
+ {0x65, 0x0300, 0x0301, 0x65, 0},
+ {0x65, 0x0300, 0x0301, 0x65, 0x0301, 0},
+ {0x65, 0x0300, 0x0301, 0x65, 0x0301, 0x0300, 0},
+ {0x65, 0x0300, 0x0301, 0x65, 0x0300, 0},
+ {0x65, 0x0300, 0x0301, 0x65, 0x0300, 0x0301, 0}
+};
+
+static const UChar testMore[][CollationEnglishTest::MAX_TOKEN_LEN] = {
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0065 /* 'e' */, 0},
+ { 0x00E6, 0},
+ { 0x00C6, 0},
+ {(UChar)0x0061 /* 'a' */, (UChar)0x0066 /* 'f' */, 0},
+ {(UChar)0x006F /* 'o' */, (UChar)0x0065 /* 'e' */, 0},
+ { 0x0153, 0},
+ { 0x0152, 0},
+ {(UChar)0x006F /* 'o' */, (UChar)0x0066 /* 'f' */, 0},
+};
+
+void CollationEnglishTest::TestTertiary(/* char* par */)
+{
+ int32_t i = 0;
+ myCollation->setStrength(Collator::TERTIARY);
+ for (i = 0; i < 38 ; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+
+ int32_t j = 0;
+ for (i = 0; i < 10; i++)
+ {
+ for (j = i+1; j < 10; j++)
+ {
+ doTest(myCollation, testBugs[i], testBugs[j], Collator::LESS);
+ }
+ }
+
+ //test more interesting cases
+ Collator::EComparisonResult expected;
+ const int32_t testMoreSize = (int32_t)(sizeof(testMore) / sizeof(testMore[0]));
+ for (i = 0; i < testMoreSize; i++)
+ {
+ for (j = 0; j < testMoreSize; j++)
+ {
+ if (i < j)
+ expected = Collator::LESS;
+ else if (i == j)
+ expected = Collator::EQUAL;
+ else // (i > j)
+ expected = Collator::GREATER;
+ doTest(myCollation, testMore[i], testMore[j], expected );
+ }
+ }
+
+}
+
+void CollationEnglishTest::TestPrimary(/* char* par */)
+{
+ int32_t i;
+ myCollation->setStrength(Collator::PRIMARY);
+ for (i = 38; i < 43 ; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+
+void CollationEnglishTest::TestSecondary(/* char* par */)
+{
+ int32_t i;
+ myCollation->setStrength(Collator::SECONDARY);
+ for (i = 43; i < 49 ; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+
+ //test acute and grave ordering (compare to french collation)
+ int32_t j;
+ Collator::EComparisonResult expected;
+ const int32_t testAcuteSize = (int32_t)(sizeof(testAcute) / sizeof(testAcute[0]));
+ for (i = 0; i < testAcuteSize; i++)
+ {
+ for (j = 0; j < testAcuteSize; j++)
+ {
+ if (i < j)
+ expected = Collator::LESS;
+ else if (i == j)
+ expected = Collator::EQUAL;
+ else // (i > j)
+ expected = Collator::GREATER;
+ doTest(myCollation, testAcute[i], testAcute[j], expected );
+ }
+ }
+}
+
+void CollationEnglishTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CollationEnglishTest: ");
+ if(myCollation) {
+ switch (index) {
+ case 0: name = "TestPrimary"; if (exec) TestPrimary(/* par */); break;
+ case 1: name = "TestSecondary"; if (exec) TestSecondary(/* par */); break;
+ case 2: name = "TestTertiary"; if (exec) TestTertiary(/* par */); break;
+ default: name = ""; break;
+ }
+ } else {
+ errln("Collator couldn't be instantiated!");
+ name = "";
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/encoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/encoll.h
new file mode 100644
index 00000000000..06beb89dd29
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/encoll.h
@@ -0,0 +1,48 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * CollationEnglishTest is a third level test class. This tests the locale
+ * specific primary, secondary and tertiary rules. For example, the ignorable
+ * character '-' in string "black-bird". The en_US locale uses the default
+ * collation rules as its sorting sequence.
+ */
+
+#ifndef _ENCOLL
+#define _ENCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class CollationEnglishTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationEnglishTest();
+ virtual ~CollationEnglishTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // performs test with strength PRIMARY
+ void TestPrimary(/* char* par */);
+
+ // perform test with strength SECONDARY
+ void TestSecondary(/* char* par */);
+
+ // perform test with strength TERTIARY
+ void TestTertiary(/* char* par */);
+
+private:
+ Collator *myCollation;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/escoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/escoll.cpp
new file mode 100644
index 00000000000..152453bdaf0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/escoll.cpp
@@ -0,0 +1,116 @@
+
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#ifndef _COLL
+#include "unicode/coll.h"
+#endif
+
+#ifndef _TBLCOLL
+#include "unicode/tblcoll.h"
+#endif
+
+#ifndef _UNISTR
+#include "unicode/unistr.h"
+#endif
+
+#ifndef _SORTKEY
+#include "unicode/sortkey.h"
+#endif
+
+#ifndef _ESCOLL
+#include "escoll.h"
+#endif
+
+#include "sfwdchit.h"
+
+CollationSpanishTest::CollationSpanishTest()
+: myCollation(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation = Collator::createInstance(Locale("es", "ES", ""),status);
+}
+
+CollationSpanishTest::~CollationSpanishTest()
+{
+ delete myCollation;
+}
+
+const UChar CollationSpanishTest::testSourceCases[][CollationSpanishTest::MAX_TOKEN_LEN] = {
+ {0x61, 0x6c, 0x69, 0x61, 0x73, 0},
+ {0x45, 0x6c, 0x6c, 0x69, 0x6f, 0x74, 0},
+ {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0},
+ {0x61, 0x63, 0x48, 0x63, 0},
+ {0x61, 0x63, 0x63, 0},
+ {0x61, 0x6c, 0x69, 0x61, 0x73, 0},
+ {0x61, 0x63, 0x48, 0x63, 0},
+ {0x61, 0x63, 0x63, 0},
+ {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0},
+};
+
+const UChar CollationSpanishTest::testTargetCases[][CollationSpanishTest::MAX_TOKEN_LEN] = {
+ {0x61, 0x6c, 0x6c, 0x69, 0x61, 0x73, 0},
+ {0x45, 0x6d, 0x69, 0x6f, 0x74, 0},
+ {0x68, 0x65, 0x6c, 0x6c, 0x4f, 0},
+ {0x61, 0x43, 0x48, 0x63, 0},
+ {0x61, 0x43, 0x48, 0x63, 0},
+ {0x61, 0x6c, 0x6c, 0x69, 0x61, 0x73, 0},
+ {0x61, 0x43, 0x48, 0x63, 0},
+ {0x61, 0x43, 0x48, 0x63, 0},
+ {0x68, 0x65, 0x6c, 0x6c, 0x4f, 0},
+};
+
+const Collator::EComparisonResult CollationSpanishTest::results[] = {
+ Collator::LESS,
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::LESS,
+ // test primary > 5
+ Collator::LESS,
+ Collator::EQUAL,
+ Collator::LESS,
+ Collator::EQUAL
+};
+
+void CollationSpanishTest::TestTertiary(/* char* par */)
+{
+ int32_t i = 0;
+ myCollation->setStrength(Collator::TERTIARY);
+ for (i = 0; i < 5 ; i++) {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+void CollationSpanishTest::TestPrimary(/* char* par */)
+{
+ int32_t i;
+ myCollation->setStrength(Collator::PRIMARY);
+ for (i = 5; i < 9; i++) {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+
+void CollationSpanishTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par */)
+{
+ if (exec) logln("TestSuite CollationSpanishTest: ");
+
+ if((!myCollation) && exec) {
+ errln(__FILE__ " cannot test - failed to create collator.");
+ name = "some test";
+ return;
+ }
+ switch (index) {
+ case 0: name = "TestPrimary"; if (exec) TestPrimary(/* par */); break;
+ case 1: name = "TestTertiary"; if (exec) TestTertiary(/* par */); break;
+ default: name = ""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/escoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/escoll.h
new file mode 100644
index 00000000000..917e30af156
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/escoll.h
@@ -0,0 +1,49 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * CollationSpanishTest is a third level test class. This tests the locale
+ * specific primary and tertiary rules. This Spanish sort uses the traditional
+ * sorting sequence. The Spanish modern sorting sequence does not sort
+ * ch and ll as unique characters.
+ */
+
+#ifndef _ESCOLL
+#define _ESCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class CollationSpanishTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationSpanishTest();
+ virtual ~CollationSpanishTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // performs tests with strength PRIMARY
+ void TestPrimary(/* char* par */);
+
+ // prforms test with strength TERTIARY
+ void TestTertiary(/* char* par */);
+
+private:
+ static const UChar testSourceCases[][MAX_TOKEN_LEN];
+ static const UChar testTargetCases[][MAX_TOKEN_LEN];
+ static const Collator::EComparisonResult results[];
+
+ Collator *myCollation;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ficoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/ficoll.cpp
new file mode 100644
index 00000000000..b67f6348e57
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ficoll.cpp
@@ -0,0 +1,102 @@
+/********************************************************************
+ * Copyright (c) 1997-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#ifndef _COLL
+#include "unicode/coll.h"
+#endif
+
+#ifndef _TBLCOLL
+#include "unicode/tblcoll.h"
+#endif
+
+#ifndef _UNISTR
+#include "unicode/unistr.h"
+#endif
+
+#ifndef _SORTKEY
+#include "unicode/sortkey.h"
+#endif
+
+#ifndef _FICOLL
+#include "ficoll.h"
+#endif
+
+#include "sfwdchit.h"
+
+CollationFinnishTest::CollationFinnishTest()
+: myCollation(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation = Collator::createInstance(Locale("fi", "FI", "", "collation=standard"),status);
+}
+
+CollationFinnishTest::~CollationFinnishTest()
+{
+ delete myCollation;
+}
+
+const UChar CollationFinnishTest::testSourceCases[][CollationFinnishTest::MAX_TOKEN_LEN] = {
+ {0x77, 0x61, 0x74, 0},
+ {0x76, 0x61, 0x74, 0},
+ {0x61, 0x00FC, 0x62, 0x65, 0x63, 0x6b, 0},
+ {0x4c, 0x00E5, 0x76, 0x69, 0},
+ {0x77, 0x61, 0x74, 0}
+};
+
+const UChar CollationFinnishTest::testTargetCases[][CollationFinnishTest::MAX_TOKEN_LEN] = {
+ {0x76, 0x61, 0x74, 0},
+ {0x77, 0x61, 0x79, 0},
+ {0x61, 0x78, 0x62, 0x65, 0x63, 0x6b, 0},
+ {0x4c, 0x00E4, 0x77, 0x65, 0},
+ {0x76, 0x61, 0x74, 0}
+};
+
+const Collator::EComparisonResult CollationFinnishTest::results[] = {
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::LESS,
+ // test primary > 4
+ Collator::EQUAL,
+};
+
+void CollationFinnishTest::TestTertiary(/* char* par */)
+{
+ int32_t i = 0;
+ myCollation->setStrength(Collator::TERTIARY);
+ for (i = 0; i < 4 ; i++) {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+void CollationFinnishTest::TestPrimary(/* char* par */)
+{
+ int32_t i;
+ myCollation->setStrength(Collator::PRIMARY);
+ for (i = 4; i < 5; i++) {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+
+void CollationFinnishTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CollationFinnishTest: ");
+
+ if((!myCollation) && exec) {
+ errln(__FILE__ " cannot test - failed to create collator.");
+ name = "some test";
+ return;
+ }
+ switch (index) {
+ case 0: name = "TestPrimary"; if (exec) TestPrimary(/* par */); break;
+ case 1: name = "TestTertiary"; if (exec) TestTertiary(/* par */); break;
+ default: name = ""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ficoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/ficoll.h
new file mode 100644
index 00000000000..8c185f4eef7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ficoll.h
@@ -0,0 +1,48 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * CollationFinnishTest is a third level test class. This tests the locale
+ * specific primary and tertiary rules. For example, a-ring sorts after z
+ * and w and v are equivalent.
+ */
+
+#ifndef _FICOLL
+#define _FICOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class CollationFinnishTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationFinnishTest();
+ virtual ~CollationFinnishTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // perform tests with strength PRIMARY
+ void TestPrimary(/* char* par */);
+
+ // perform test with strength TERTIARY
+ void TestTertiary(/* char* par */);
+
+private:
+ static const UChar testSourceCases[][MAX_TOKEN_LEN];
+ static const UChar testTargetCases[][MAX_TOKEN_LEN];
+ static const Collator::EComparisonResult results[];
+
+ Collator *myCollation;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/fldset.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/fldset.cpp
new file mode 100644
index 00000000000..aa3aa284796
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/fldset.cpp
@@ -0,0 +1,351 @@
+/*
+************************************************************************
+* Copyright (c) 2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+************************************************************************
+*/
+
+#include "fldset.h"
+#include "intltest.h"
+
+#if !UCONFIG_NO_FORMATTING
+#include "unicode/regex.h"
+
+
+FieldsSet::FieldsSet() {
+ // NOTREACHED
+}
+
+FieldsSet::FieldsSet(int32_t fieldCount) {
+ construct((UDebugEnumType)-1, fieldCount);
+}
+
+FieldsSet::FieldsSet(UDebugEnumType field) {
+ construct(field, udbg_enumCount(field));
+}
+
+FieldsSet::~FieldsSet() {
+
+}
+
+int32_t FieldsSet::fieldCount() const {
+ return fFieldCount;
+}
+
+void FieldsSet::construct(UDebugEnumType field, int32_t fieldCount) {
+ fEnum = field;
+ if(fieldCount > U_FIELDS_SET_MAX) {
+ fieldCount = U_FIELDS_SET_MAX;
+ }
+ fFieldCount = fieldCount;
+ clear();
+}
+
+UnicodeString FieldsSet::diffFrom(const FieldsSet& other, UErrorCode& status) const {
+ UnicodeString str;
+ if(!isSameType(other)) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return UnicodeString("U_ILLEGAL_ARGUMENT_ERROR: FieldsSet of a different type!");
+ }
+ for (int i=0; i<fieldCount(); i++) {
+ if (isSet((UCalendarDateFields)i)) {
+ int32_t myVal = get(i);
+ int32_t theirVal = other.get(i);
+
+ if(fEnum != -1) {
+ const UnicodeString& fieldName = udbg_enumString(
+ fEnum, i);
+
+ str = str + fieldName + UnicodeString("=")+myVal+UnicodeString(" not ")+theirVal+UnicodeString(", ");
+ } else {
+ str = str + UnicodeString("some field") + "=" + myVal+" not " + theirVal+", ";
+ }
+ }
+ }
+ return str;
+}
+
+static UnicodeString *split(const UnicodeString &src, UChar ch, int32_t &splits)
+{
+ int32_t offset = -1;
+
+ splits = 1;
+ while((offset = src.indexOf(ch, offset + 1)) >= 0) {
+ splits += 1;
+ }
+
+ UnicodeString *result = new UnicodeString[splits];
+
+ int32_t start = 0;
+ int32_t split = 0;
+ int32_t end;
+
+ while((end = src.indexOf(ch, start)) >= 0) {
+ src.extractBetween(start, end, result[split++]);
+ start = end + 1;
+ }
+
+ src.extractBetween(start, src.length(), result[split]);
+
+ return result;
+}
+
+int32_t FieldsSet::parseFrom(const UnicodeString& str, const
+ FieldsSet* inheritFrom, UErrorCode& status) {
+
+ int goodFields = 0;
+
+ if(U_FAILURE(status)) {
+ return -1;
+ }
+
+ int32_t destCount = 0;
+ UnicodeString *dest = split(str, 0x002C /* ',' */, destCount);
+
+ for(int i = 0; i < destCount; i += 1) {
+ int32_t dc = 0;
+ UnicodeString *kv = split(dest[i], 0x003D /* '=' */, dc);
+
+ if(dc != 2) {
+ it_errln(UnicodeString("dc == ") + dc + UnicodeString("?"));
+ }
+
+ int32_t field = handleParseName(inheritFrom, kv[0], kv[1], status);
+
+ if(U_FAILURE(status)) {
+ char ch[256];
+ const UChar *u = kv[0].getBuffer();
+ int32_t len = kv[0].length();
+ u_UCharsToChars(u, ch, len);
+ ch[len] = 0; /* include terminating \0 */
+ it_errln(UnicodeString("Parse Failed: Field ") + UnicodeString(ch) + UnicodeString(", err ") + UnicodeString(u_errorName(status)));
+ return -1;
+ }
+
+ if(field != -1) {
+ handleParseValue(inheritFrom, field, kv[1], status);
+
+ if(U_FAILURE(status)) {
+ char ch[256];
+ const UChar *u = kv[1].getBuffer();
+ int32_t len = kv[1].length();
+ u_UCharsToChars(u, ch, len);
+ ch[len] = 0; /* include terminating \0 */
+ it_errln(UnicodeString("Parse Failed: Value ") + UnicodeString(ch) + UnicodeString(", err ") + UnicodeString(u_errorName(status)));
+ return -1;
+ }
+
+ goodFields += 1;
+ }
+
+ delete[] kv;
+ }
+
+ delete[] dest;
+
+ return goodFields;
+}
+
+UBool FieldsSet::isSameType(const FieldsSet& other) const {
+ return((&other==this)||
+ ((other.fFieldCount==fFieldCount) && (other.fEnum==fEnum)));
+}
+
+void FieldsSet::clear() {
+ for (int i=0; i<fieldCount(); i++) {
+ fValue[i]=-1;
+ fIsSet[i]=FALSE;
+ }
+}
+
+void FieldsSet::clear(int32_t field) {
+ if (field<0|| field>=fieldCount()) {
+ return;
+ }
+ fValue[field] = -1;
+ fIsSet[field] = FALSE;
+}
+void FieldsSet::set(int32_t field, int32_t amount) {
+ if (field<0|| field>=fieldCount()) {
+ return;
+ }
+ fValue[field] = amount;
+ fIsSet[field] = TRUE;
+}
+
+UBool FieldsSet::isSet(int32_t field) const {
+ if (field<0|| field>=fieldCount()) {
+ return FALSE;
+ }
+ return fIsSet[field];
+}
+int32_t FieldsSet::get(int32_t field) const {
+ if (field<0|| field>=fieldCount()) {
+ return -1;
+ }
+ return fValue[field];
+}
+
+
+int32_t FieldsSet::handleParseName(const FieldsSet* /* inheritFrom */, const UnicodeString& name, const UnicodeString& /* substr*/ , UErrorCode& status) {
+ if(fEnum > -1) {
+ return udbg_enumByString(fEnum, name);
+ } else {
+ status = U_UNSUPPORTED_ERROR;
+ return -1;
+ }
+}
+
+void FieldsSet::parseValueDefault(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
+ int32_t value = -1;
+ if(substr.length()==0) { // inherit requested
+ // inherit
+ if((inheritFrom == NULL) || !inheritFrom->isSet((UCalendarDateFields)field)) {
+ // couldn't inherit from field
+ it_errln(UnicodeString("Parse Failed: Couldn't inherit field ") + field + UnicodeString(" [") + UnicodeString(udbg_enumName(fEnum, field)) + UnicodeString("]"));
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ value = inheritFrom->get((UCalendarDateFields)field);
+ } else {
+ value = udbg_stoi(substr);
+ }
+ set(field, value);
+}
+
+void FieldsSet::parseValueEnum(UDebugEnumType type, const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
+ int32_t value = udbg_enumByString(type, substr);
+ if(value>=0) {
+ set(field, value);
+ } else {
+ // fallback
+ parseValueDefault(inheritFrom,field,substr,status);
+ }
+}
+
+void FieldsSet::handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
+ parseValueDefault(inheritFrom, field, substr, status);
+}
+
+/// CAL FIELDS
+
+
+CalendarFieldsSet::CalendarFieldsSet() :
+FieldsSet(UDBG_UCalendarDateFields) {
+ // base class will call clear.
+}
+
+CalendarFieldsSet::~CalendarFieldsSet() {
+}
+
+void CalendarFieldsSet::handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
+ if(field==UCAL_MONTH) {
+ parseValueEnum(UDBG_UCalendarMonths, inheritFrom, field, substr, status);
+ // will fallback to default.
+ } else {
+ parseValueDefault(inheritFrom, field, substr, status);
+ }
+}
+
+/**
+ * set the specified fields on this calendar. Doesn't clear first. Returns any errors the caller
+ */
+void CalendarFieldsSet::setOnCalendar(Calendar *cal, UErrorCode& /*status*/) const {
+ for (int i=0; i<UDAT_FIELD_COUNT; i++) {
+ if (isSet((UCalendarDateFields)i)) {
+ int32_t value = get((UCalendarDateFields)i);
+ //fprintf(stderr, "Setting: %s#%d=%d\n",udbg_enumName(UDBG_UCalendarDateFields,i),i,value);
+ cal->set((UCalendarDateFields)i, value);
+ }
+ }
+}
+
+/**
+ * return true if the calendar matches in these fields
+ */
+UBool CalendarFieldsSet::matches(Calendar *cal, CalendarFieldsSet &diffSet,
+ UErrorCode& status) const {
+ UBool match = TRUE;
+ if (U_FAILURE(status))
+ return FALSE;
+ for (int i=0; i<UDAT_FIELD_COUNT; i++) {
+ if (isSet((UCalendarDateFields)i)) {
+ int32_t calVal = cal->get((UCalendarDateFields)i, status);
+ if (U_FAILURE(status))
+ return FALSE;
+ if (calVal != get((UCalendarDateFields)i)) {
+ match = FALSE;
+ diffSet.set((UCalendarDateFields)i, calVal);
+ //fprintf(stderr, "match failed: %s#%d=%d != %d\n",udbg_enumName(UDBG_UCalendarDateFields,i),i,cal->get((UCalendarDateFields)i,status), get((UCalendarDateFields)i));;
+ }
+ }
+ }
+ return match;
+}
+
+
+enum {
+ DTS_DATE = 0,
+ DTS_TIME,
+ DTS_COUNT
+};
+
+/**
+ * DateTimeSet
+ * */
+DateTimeStyleSet::DateTimeStyleSet() :
+ FieldsSet(DTS_COUNT) {
+
+}
+
+DateTimeStyleSet::~DateTimeStyleSet() {
+
+}
+
+UDateFormatStyle DateTimeStyleSet::getDateStyle() const {
+ if(!isSet(DTS_DATE)) {
+ return UDAT_NONE;
+ } else {
+ return (UDateFormatStyle)get(DTS_DATE);
+ }
+}
+
+
+UDateFormatStyle DateTimeStyleSet::getTimeStyle() const {
+ if(!isSet(DTS_TIME)) {
+ return UDAT_NONE;
+ } else {
+ return (UDateFormatStyle)get(DTS_TIME);
+ }
+}
+
+void DateTimeStyleSet::handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status) {
+// int32_t value = udbg_enumByString(UDBG_UDateFormatStyle, substr);
+// fprintf(stderr, " HPV: %d -> %d\n", field, value);
+ UnicodeString kRELATIVE_("RELATIVE_");
+ if(substr.startsWith(kRELATIVE_)) {
+ UnicodeString relativeas(substr,kRELATIVE_.length());
+ parseValueEnum(UDBG_UDateFormatStyle, inheritFrom, field, relativeas, status);
+ // fix relative value
+ if(isSet(field) && U_SUCCESS(status)) {
+ set(field, get(field) | UDAT_RELATIVE);
+ }
+ } else {
+ parseValueEnum(UDBG_UDateFormatStyle, inheritFrom, field, substr, status);
+ }
+}
+
+int32_t DateTimeStyleSet::handleParseName(const FieldsSet* /* inheritFrom */, const UnicodeString& name, const UnicodeString& /* substr */, UErrorCode& status) {
+ UnicodeString kDATE("DATE"); // TODO: static
+ UnicodeString kTIME("TIME"); // TODO: static
+ if(name == kDATE ) {
+ return DTS_DATE;
+ } else if(name == kTIME) {
+ return DTS_TIME;
+ } else {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+}
+
+#endif /*!UCONFIG_NO_FORMAT*/
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/fldset.h b/Build/source/libs/icu/icu-xetex/test/intltest/fldset.h
new file mode 100644
index 00000000000..d471b026c19
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/fldset.h
@@ -0,0 +1,186 @@
+/*
+************************************************************************
+* Copyright (c) 2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+************************************************************************
+*/
+#ifndef FLDSET_H_
+#define FLDSET_H_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+#include "unicode/calendar.h"
+#include "unicode/ucal.h"
+#include "unicode/udat.h"
+#include "unicode/udbgutil.h"
+#include "unicode/dbgutil.h"
+#include "unicode/unistr.h"
+
+#define U_FIELDS_SET_MAX 64
+
+class FieldsSet {
+ protected:
+ /**
+ * subclass interface
+ * @param whichEnum which enumaration value goes with this set. Will be used to calculate str values and also enum size.
+ */
+ FieldsSet(UDebugEnumType whichEnum);
+
+ /**
+ * subclass interface - no enum tie-in
+ * @param fieldCount how many fields this can hold.
+ */
+ FieldsSet(int32_t fieldsCount);
+
+ public:
+ /**
+ * @param other "expected" set to match against
+ * @param status - will return invalid argument if sets are not the same size
+ * @return a formatted string listing which fields are set in
+ * this, with the comparison made agaainst those fields in other.
+ */
+ UnicodeString diffFrom(const FieldsSet& other, UErrorCode &status) const;
+
+ public:
+ /**
+ * @param str string to parse
+ * @param status formatted string for status
+ */
+ int32_t parseFrom(const UnicodeString& str, UErrorCode& status) { return parseFrom(str,NULL,status); }
+
+ public:
+ int32_t parseFrom(const UnicodeString& str, const FieldsSet& inheritFrom, UErrorCode& status) { return parseFrom(str, &inheritFrom, status); }
+
+ int32_t parseFrom(const UnicodeString& str, const
+ FieldsSet* inheritFrom, UErrorCode& status);
+
+ protected:
+ /**
+ * Callback interface for subclass.
+ * This function is called when parsing a field name, such as "MONTH" in "MONTH=4".
+ * Base implementation is to lookup the enum value using udbg_* utilities, or else as an integer if
+ * enum is not available.
+ *
+ * If there is a special directive, the implementer can catch it here and return -1 after special processing completes.
+ *
+ * @param inheritFrom the set inheriting from - may be null.
+ * @param name the field name (key side)
+ * @param substr the string in question (value side)
+ * @param status error status - set to error for failure.
+ * @return field number, or negative if field should be skipped.
+ */
+ virtual int32_t handleParseName(const FieldsSet* inheritFrom, const UnicodeString& name, const UnicodeString& substr, UErrorCode& status);
+
+ /**
+ * Callback interface for subclass.
+ * Base implementation is to call parseValueDefault(...)
+ * @param inheritFrom the set inheriting from - may be null.
+ * @param field which field is being parsed
+ * @param substr the string in question (value side)
+ * @param status error status - set to error for failure.
+ * @see parseValueDefault
+ */
+ virtual void handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
+
+ /**
+ * the default implementation for handleParseValue.
+ * Base implementation is to parse a decimal integer value, or inherit from inheritFrom if the string is 0-length.
+ * Implementations of this function should call set(field,...) on successful parse.
+ * @see handleParseValue
+ */
+ void parseValueDefault(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
+
+
+ /**
+ * convenience implementation for handleParseValue
+ * attempt to load a value from an enum value using udbg_enumByString()
+ * if fails, will call parseValueDefault()
+ * @see handleParseValue
+ */
+ void parseValueEnum(UDebugEnumType type, const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
+
+ private:
+ FieldsSet();
+
+ void construct(UDebugEnumType whichEnum, int32_t fieldCount);
+
+ public:
+ virtual ~FieldsSet();
+
+ void clear();
+ void clear(int32_t field);
+ void set(int32_t field, int32_t amount);
+ UBool isSet(int32_t field) const;
+ int32_t get(int32_t field) const;
+
+ UBool isSameType(const FieldsSet& other) const;
+ int32_t fieldCount() const;
+
+
+ protected:
+ int32_t fValue[U_FIELDS_SET_MAX];
+ UBool fIsSet[U_FIELDS_SET_MAX];
+ protected:
+ int32_t fFieldCount;
+ UDebugEnumType fEnum;
+};
+
+/** ------- Calendar Fields Set -------- **/
+class CalendarFieldsSet : public FieldsSet {
+ public:
+ CalendarFieldsSet();
+ virtual ~CalendarFieldsSet();
+
+// void clear(UCalendarDateFields field) { clear((int32_t)field); }
+// void set(UCalendarDateFields field, int32_t amount) { set ((int32_t)field, amount); }
+
+// UBool isSet(UCalendarDateFields field) const { return isSet((int32_t)field); }
+// int32_t get(UCalendarDateFields field) const { return get((int32_t)field); }
+
+ /**
+ * @param matches fillin to hold any fields different. Will have the calendar's value set on them.
+ * @return true if the calendar matches in these fields.
+ */
+ UBool matches(Calendar *cal, CalendarFieldsSet &diffSet,
+ UErrorCode& status) const;
+
+ /**
+ * set the specified fields on this calendar. Doesn't clear first. Returns any errors the cale
+ */
+ void setOnCalendar(Calendar *cal, UErrorCode& status) const;
+
+
+ protected:
+ void handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
+};
+
+/**
+ * This class simply implements a set of date and time styles
+ * such as DATE=SHORT or TIME=SHORT,DATE=LONG
+ */
+class DateTimeStyleSet : public FieldsSet {
+ public:
+ DateTimeStyleSet();
+ virtual ~DateTimeStyleSet();
+
+
+ /**
+ * @return the date style, or UDAT_NONE if not set
+ */
+ UDateFormatStyle getDateStyle() const;
+
+ /**
+ * @return the time style, or UDAT_NONE if not set
+ */
+ UDateFormatStyle getTimeStyle() const;
+
+
+ protected:
+ void handleParseValue(const FieldsSet* inheritFrom, int32_t field, const UnicodeString& substr, UErrorCode& status);
+ int32_t handleParseName(const FieldsSet* inheritFrom, const UnicodeString& name, const UnicodeString& substr, UErrorCode& status);
+};
+
+
+#endif /*!UCONFIG_NO_FORMAT*/
+#endif /*FLDSET_H_*/
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/frcoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/frcoll.cpp
new file mode 100644
index 00000000000..fd8702c6112
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/frcoll.cpp
@@ -0,0 +1,217 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/***********************************************************************
+* Modification history
+* Date Name Description
+* 02/14/2001 synwee Added attributes in TestTertiary and
+* TestSecondary
+***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/unistr.h"
+#include "unicode/sortkey.h"
+#include "frcoll.h"
+
+#include "sfwdchit.h"
+
+CollationFrenchTest::CollationFrenchTest()
+: myCollation(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation = Collator::createInstance(Locale::getFrance(), status);
+ if(!myCollation || U_FAILURE(status)) {
+ errln(__FILE__ "failed to create! err " + UnicodeString(u_errorName(status)));
+ /* if it wasn't already: */
+ delete myCollation;
+ myCollation = NULL;
+ }
+}
+
+CollationFrenchTest::~CollationFrenchTest()
+{
+ delete myCollation;
+}
+
+const UChar CollationFrenchTest::testSourceCases[][CollationFrenchTest::MAX_TOKEN_LEN] =
+{
+ {0x0061/*'a'*/, 0x0062/*'b'*/, 0x0063/*'c'*/, 0x0000},
+ {0x0043/*'C'*/, 0x004f/*'O'*/, 0x0054/*'T'*/, 0x0045/*'E'*/, 0x0000},
+ {0x0063/*'c'*/, 0x006f/*'o'*/, 0x002d/*'-'*/, 0x006f/*'o'*/, 0x0070/*'p'*/, 0x0000},
+ {0x0070/*'p'*/, 0x00EA, 0x0063/*'c'*/, 0x0068/*'h'*/, 0x0065/*'e'*/, 0x0000},
+ {0x0070/*'p'*/, 0x00EA, 0x0063/*'c'*/, 0x0068/*'h'*/, 0x0065/*'e'*/, 0x0072/*'r'*/, 0x0000},
+ {0x0070/*'p'*/, 0x00E9, 0x0063/*'c'*/, 0x0068/*'h'*/, 0x0065/*'e'*/, 0x0072/*'r'*/, 0x0000},
+ {0x0070/*'p'*/, 0x00E9, 0x0063/*'c'*/, 0x0068/*'h'*/, 0x0065/*'e'*/, 0x0072/*'r'*/, 0x0000},
+ {0x0048/*'H'*/, 0x0065/*'e'*/, 0x006c/*'l'*/, 0x006c/*'l'*/, 0x006f/*'o'*/, 0x0000},
+ {0x01f1, 0x0000},
+ {0xfb00, 0x0000},
+ {0x01fa, 0x0000},
+ {0x0101, 0x0000}
+};
+
+const UChar CollationFrenchTest::testTargetCases[][CollationFrenchTest::MAX_TOKEN_LEN] =
+{
+ {0x0041/*'A'*/, 0x0042/*'B'*/, 0x0043/*'C'*/, 0x0000},
+ {0x0063/*'c'*/, 0x00f4, 0x0074/*'t'*/, 0x0065/*'e'*/, 0x0000},
+ {0x0043/*'C'*/, 0x004f/*'O'*/, 0x004f/*'O'*/, 0x0050/*'P'*/, 0x0000},
+ {0x0070/*'p'*/, 0x00E9, 0x0063/*'c'*/, 0x0068/*'h'*/, 0x00E9, 0x0000},
+ {0x0070/*'p'*/, 0x00E9, 0x0063/*'c'*/, 0x0068/*'h'*/, 0x00E9, 0x0000},
+ {0x0070/*'p'*/, 0x00EA, 0x0063/*'c'*/, 0x0068/*'h'*/, 0x0065/*'e'*/, 0x0000},
+ {0x0070/*'p'*/, 0x00EA, 0x0063/*'c'*/, 0x0068/*'h'*/, 0x0065/*'e'*/, 0x0072/*'r'*/, 0x0000},
+ {0x0068/*'h'*/, 0x0065/*'e'*/, 0x006c/*'l'*/, 0x006c/*'l'*/, 0x004f/*'O'*/, 0x0000},
+ {0x01ee, 0x0000},
+ {0x25ca, 0x0000},
+ {0x00e0, 0x0000},
+ {0x01df, 0x0000}
+};
+
+const Collator::EComparisonResult CollationFrenchTest::results[] =
+{
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS, /*Collator::GREATER,*/
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::LESS, /*Collator::GREATER,*/
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::LESS
+};
+
+// 0x0300 is grave, 0x0301 is acute
+// the order of elements in this array must be different than the order in CollationEnglishTest
+const UChar CollationFrenchTest::testAcute[][CollationFrenchTest::MAX_TOKEN_LEN] =
+{
+/*00*/ {0x0065/*'e'*/, 0x0065/*'e'*/, 0x0000},
+/*01*/ {0x0065/*'e'*/, 0x0301, 0x0065/*'e'*/, 0x0000},
+/*02*/ {0x0065/*'e'*/, 0x0300, 0x0301, 0x0065/*'e'*/, 0x0000},
+/*03*/ {0x0065/*'e'*/, 0x0300, 0x0065/*'e'*/, 0x0000},
+/*04*/ {0x0065/*'e'*/, 0x0301, 0x0300, 0x0065/*'e'*/, 0x0000},
+/*05*/ {0x0065/*'e'*/, 0x0065/*'e'*/, 0x0301, 0x0000},
+/*06*/ {0x0065/*'e'*/, 0x0301, 0x0065/*'e'*/, 0x0301, 0x0000},
+/*07*/ {0x0065/*'e'*/, 0x0300, 0x0301, 0x0065/*'e'*/, 0x0301, 0x0000},
+/*08*/ {0x0065/*'e'*/, 0x0300, 0x0065/*'e'*/, 0x0301, 0x0000},
+/*09*/ {0x0065/*'e'*/, 0x0301, 0x0300, 0x0065/*'e'*/, 0x0301, 0x0000},
+/*0a*/ {0x0065/*'e'*/, 0x0065/*'e'*/, 0x0300, 0x0301, 0x0000},
+/*0b*/ {0x0065/*'e'*/, 0x0301, 0x0065/*'e'*/, 0x0300, 0x0301, 0x0000},
+/*0c*/ {0x0065/*'e'*/, 0x0300, 0x0301, 0x0065/*'e'*/, 0x0300, 0x0301, 0x0000},
+/*0d*/ {0x0065/*'e'*/, 0x0300, 0x0065/*'e'*/, 0x0300, 0x0301, 0x0000},
+/*0e*/ {0x0065/*'e'*/, 0x0301, 0x0300, 0x0065/*'e'*/, 0x0300, 0x0301, 0x0000},
+/*0f*/ {0x0065/*'e'*/, 0x0065/*'e'*/, 0x0300, 0x0000},
+/*10*/ {0x0065/*'e'*/, 0x0301, 0x0065/*'e'*/, 0x0300, 0x0000},
+/*11*/ {0x0065/*'e'*/, 0x0300, 0x0301, 0x0065/*'e'*/, 0x0300, 0x0000},
+/*12*/ {0x0065/*'e'*/, 0x0300, 0x0065/*'e'*/, 0x0300, 0x0000},
+/*13*/ {0x0065/*'e'*/, 0x0301, 0x0300, 0x0065/*'e'*/, 0x0300, 0x0000},
+/*14*/ {0x0065/*'e'*/, 0x0065/*'e'*/, 0x0301, 0x0300, 0x0000},
+/*15*/ {0x0065/*'e'*/, 0x0301, 0x0065/*'e'*/, 0x0301, 0x0300, 0x0000},
+/*16*/ {0x0065/*'e'*/, 0x0300, 0x0301, 0x0065/*'e'*/, 0x0301, 0x0300, 0x0000},
+/*17*/ {0x0065/*'e'*/, 0x0300, 0x0065/*'e'*/, 0x0301, 0x0300, 0x0000},
+/*18*/ {0x0065/*'e'*/, 0x0301, 0x0300, 0x0065/*'e'*/, 0x0301, 0x0300, 0x0000}
+};
+
+const UChar CollationFrenchTest::testBugs[][CollationFrenchTest::MAX_TOKEN_LEN] =
+{
+ {0x0061/*'a'*/, 0x000},
+ {0x0041/*'A'*/, 0x000},
+ {0x0065/*'e'*/, 0x000},
+ {0x0045/*'E'*/, 0x000},
+ {0x00e9, 0x000},
+ {0x00e8, 0x000},
+ {0x00ea, 0x000},
+ {0x00eb, 0x000},
+ {0x0065/*'e'*/, 0x0061/*'a'*/, 0x000},
+ {0x0078/*'x'*/, 0x000}
+};
+
+void CollationFrenchTest::TestTertiary(/* char* par */)
+{
+ int32_t i = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation->setStrength(Collator::TERTIARY);
+ myCollation->setAttribute(UCOL_FRENCH_COLLATION, UCOL_ON, status);
+ myCollation->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status);
+ if (U_FAILURE(status)) {
+ errln("Error setting attribute in French collator");
+ }
+ else
+ {
+ for (i = 0; i < 12 ; i++)
+ {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+ }
+}
+
+void CollationFrenchTest::TestSecondary(/* char* par */)
+{
+ //test acute and grave ordering
+ int32_t i = 0;
+ int32_t j;
+ Collator::EComparisonResult expected;
+ UErrorCode status = U_ZERO_ERROR;
+ //myCollation->setAttribute(UCOL_FRENCH_COLLATION, UCOL_ON, status);
+ myCollation->setStrength(Collator::SECONDARY);
+ if (U_FAILURE(status))
+ errln("Error setting attribute in French collator");
+ else
+ {
+ const int32_t testAcuteSize = (int32_t)(sizeof(testAcute) / sizeof(testAcute[0]));
+ for (i = 0; i < testAcuteSize; i++)
+ {
+ for (j = 0; j < testAcuteSize; j++)
+ {
+ if (i < j)
+ expected = Collator::LESS;
+ else if (i == j)
+ expected = Collator::EQUAL;
+ else // (i > j)
+ expected = Collator::GREATER;
+ doTest(myCollation, testAcute[i], testAcute[j], expected );
+ }
+ }
+ }
+}
+
+void CollationFrenchTest::TestExtra(/* char* par */)
+{
+ int32_t i, j;
+ myCollation->setStrength(Collator::TERTIARY);
+ for (i = 0; i < 9 ; i++)
+ {
+ for (j = i + 1; j < 10; j += 1)
+ {
+ doTest(myCollation, testBugs[i], testBugs[j], Collator::LESS);
+ }
+ }
+}
+
+void CollationFrenchTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CollationFrenchTest: ");
+
+ if((!myCollation) && exec) {
+ errln(__FILE__ " cannot test - failed to create collator.");
+ name = "some test";
+ return;
+ }
+
+ switch (index) {
+ case 0: name = "TestSecondary"; if (exec) TestSecondary(/* par */); break;
+ case 1: name = "TestTertiary"; if (exec) TestTertiary(/* par */); break;
+ case 2: name = "TestExtra"; if (exec) TestExtra(/* par */); break;
+ default: name = ""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/frcoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/frcoll.h
new file mode 100644
index 00000000000..a8dfea12c35
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/frcoll.h
@@ -0,0 +1,52 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * CollationFrenchTest is a third level test class. This tests the locale
+ * specific tertiary rules. For example, the French secondary sorting on
+ * accented characters.
+ */
+#ifndef _FRCOLL
+#define _FRCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class CollationFrenchTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationFrenchTest();
+ virtual ~CollationFrenchTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // perform tests with strength SECONDARY
+ void TestSecondary(/* char* par */);
+
+ // perform tests with strength TERTIARY
+ void TestTertiary(/* char* par */);
+
+ // perform extra tests
+ void TestExtra(/* char* par */);
+
+private:
+ static const UChar testSourceCases[][MAX_TOKEN_LEN];
+ static const UChar testTargetCases[][MAX_TOKEN_LEN];
+ static const UChar testBugs[][MAX_TOKEN_LEN];
+ static const Collator::EComparisonResult results[];
+ static const UChar testAcute[][MAX_TOKEN_LEN];
+
+ Collator *myCollation;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/g7coll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/g7coll.cpp
new file mode 100644
index 00000000000..cb8f5f8563c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/g7coll.cpp
@@ -0,0 +1,302 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/unistr.h"
+#include "unicode/sortkey.h"
+#include "g7coll.h"
+#include "sfwdchit.h"
+
+
+static const UChar testCases[][G7CollationTest::MAX_TOKEN_LEN] = {
+ { 0x0062 /*'b'*/, 0x006c /*'l'*/, 0x0061 /*'a'*/, 0x0062 /*'c'*/, 0x006b /*'k'*/,
+ 0x0062 /*'b'*/, 0x0069 /*'i'*/, 0x0072 /*'r'*/, 0x0064 /*'d'*/, 0x0073 /*'s'*/, 0x0000}, /* 9 */
+ { 0x0050 /*'P'*/, 0x0061 /*'a'*/, 0x0074/*'t'*/, 0x0000}, /* 1 */
+ { 0x0070 /*'p'*/, 0x00E9, 0x0063 /*'c'*/, 0x0068 /*'h'*/, 0x00E9, 0x0000}, /* 2 */
+ { 0x0070 /*'p'*/, 0x00EA, 0x0063 /*'c'*/, 0x0068 /*'h'*/, 0x0065 /*'e'*/, 0x0000}, /* 3 */
+ { 0x0070 /*'p'*/, 0x00E9, 0x0063 /*'c'*/, 0x0068 /*'h'*/, 0x0065 /*'e'*/, 0x0072 /*'r'*/, 0x0000}, /* 4 */
+ { 0x0070 /*'p'*/, 0x00EA, 0x0063 /*'c'*/, 0x0068 /*'h'*/, 0x0065 /*'e'*/, 0x0072 /*'r'*/, 0x0000}, /* 5 */
+ { 0x0054 /*'T'*/, 0x006f /*'o'*/, 0x0064 /*'d'*/, 0x0000}, /* 6 */
+ { 0x0054 /*'T'*/, 0x00F6, 0x006e /*'n'*/, 0x0065 /*'e'*/, 0x0000}, /* 7 */
+ { 0x0054 /*'T'*/, 0x006f /*'o'*/, 0x0066 /*'f'*/, 0x0075 /*'u'*/, 0x0000}, /* 8 */
+ { 0x0062 /*'b'*/, 0x006c /*'l'*/, 0x0061 /*'a'*/, 0x0062 /*'c'*/, 0x006b /*'k'*/,
+ 0x0062 /*'b'*/, 0x0069 /*'i'*/, 0x0072 /*'r'*/, 0x0064 /*'d'*/, 0x0000}, /* 12 */
+ { 0x0054 /*'T'*/, 0x006f /*'o'*/, 0x006e /*'n'*/, 0x0000}, /* 10 */
+ { 0x0050 /*'P'*/, 0x0041 /*'A'*/, 0x0054 /*'T'*/, 0x0000}, /* 11 */
+ { 0x0062 /*'b'*/, 0x006c /*'l'*/, 0x0061 /*'a'*/, 0x0062 /*'c'*/, 0x006b /*'k'*/,
+ 0x002d /*'-'*/, 0x0062 /*'b'*/, 0x0069 /*'i'*/, 0x0072 /*'r'*/, 0x0064 /*'d'*/, 0x0000}, /* 13 */
+ { 0x0062 /*'b'*/, 0x006c /*'l'*/, 0x0061 /*'a'*/, 0x0062 /*'c'*/, 0x006b /*'k'*/,
+ 0x002d /*'-'*/, 0x0062 /*'b'*/, 0x0069 /*'i'*/, 0x0072 /*'r'*/, 0x0064 /*'d'*/, 0x0073/*'s'*/, 0x0000}, /* 0 */
+ {0x0070 /*'p'*/, 0x0061 /*'a'*/, 0x0074 /*'t'*/, 0x0000}, /* 14 */
+ /* Additional tests */
+ { 0x0063 /*'c'*/, 0x007a /*'z'*/, 0x0061 /*'a'*/, 0x0072 /*'r'*/, 0x0000 }, /* 15 */
+ { 0x0063 /*'c'*/, 0x0068 /*'h'*/, 0x0075 /*'u'*/, 0x0072 /*'r'*/, 0x006f /*'o'*/, 0x0000 }, /* 16 */
+ { 0x0063 /*'c'*/, 0x0061 /*'a'*/, 0x0074 /*'t'*/, 0x000 }, /* 17 */
+ { 0x0064 /*'d'*/, 0x0061 /*'a'*/, 0x0072 /*'r'*/, 0x006e /*'n'*/, 0x0000 }, /* 18 */
+ { 0x003f /*'?'*/, 0x0000 }, /* 19 */
+ { 0x0071 /*'q'*/, 0x0075 /*'u'*/, 0x0069 /*'i'*/, 0x0063 /*'c'*/, 0x006b /*'k'*/, 0x0000 }, /* 20 */
+ { 0x0023 /*'#'*/, 0x0000 }, /* 21 */
+ { 0x0026 /*'&'*/, 0x0000 }, /* 22 */
+ { 0x0061 /*'a'*/, 0x002d /*'-'*/, 0x0072 /*'r'*/, 0x0064 /*'d'*/, 0x0076 /*'v'*/, 0x0061 /*'a'*/,
+ 0x0072/*'r'*/, 0x006b/*'k'*/, 0x0000}, /* 24 */
+ { 0x0061 /*'a'*/, 0x0061 /*'a'*/, 0x0072 /*'r'*/, 0x0064 /*'d'*/, 0x0076 /*'v'*/, 0x0061 /*'a'*/,
+ 0x0072/*'r'*/, 0x006b/*'k'*/, 0x0000}, /* 23 */
+ { 0x0061 /*'a'*/, 0x0062 /*'b'*/, 0x0062 /*'b'*/, 0x006f /*'o'*/, 0x0074 /*'t'*/, 0x0000}, /* 25 */
+ { 0x0063 /*'c'*/, 0x006f /*'o'*/, 0x002d /*'-'*/, 0x0070 /*'p'*/, 0x0000}, /* 27 */
+ { 0x0063 /*'c'*/, 0x006f /*'o'*/, 0x0070 /*'p'*/, 0x0000}, /* 28 */
+ { 0x0063 /*'c'*/, 0x006f /*'o'*/, 0x006f /*'o'*/, 0x0070 /*'p'*/, 0x0000}, /* 26 */
+ { 0x007a /*'z'*/, 0x0065 /*'e'*/, 0x0062 /*'b'*/, 0x0072 /*'r'*/, 0x0061 /*'a'*/, 0x0000} /* 29 */
+};
+
+static const int32_t results[G7CollationTest::TESTLOCALES][G7CollationTest::TOTALTESTSET] = {
+ { 12, 13, 9, 0, 14, 1, 11, 2, 3, 4, 5, 6, 8, 10, 7, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, /* en_US */
+ { 12, 13, 9, 0, 14, 1, 11, 2, 3, 4, 5, 6, 8, 10, 7, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, /* en_GB */
+ { 12, 13, 9, 0, 14, 1, 11, 2, 3, 4, 5, 6, 8, 10, 7, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, /* en_CA */
+ { 12, 13, 9, 0, 14, 1, 11, 3, 2, 4, 5, 6, 8, 10, 7, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, /* fr_FR */
+ { 12, 13, 9, 0, 14, 1, 11, 3, 2, 4, 5, 6, 8, 10, 7, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, /* fr_CA */
+ { 12, 13, 9, 0, 14, 1, 11, 2, 3, 4, 5, 6, 8, 10, 7, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, /* de_DE */
+ { 12, 13, 9, 0, 14, 1, 11, 2, 3, 4, 5, 6, 8, 10, 7, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, /* it_IT */
+ { 12, 13, 9, 0, 14, 1, 11, 2, 3, 4, 5, 6, 8, 10, 7, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 }, /* ja_JP */
+ /* new table collation with rules "& Z < p, P" loop to FIXEDTESTSET */
+ { 12, 13, 9, 0, 6, 8, 10, 7, 14, 1, 11, 2, 3, 4, 5, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 },
+ /* new table collation with rules "& C < ch , cH, Ch, CH " loop to TOTALTESTSET */
+ { 19, 22, 21, 23, 24, 25, 12, 13, 9, 0, 17, 26, 28, 27, 15, 16, 18, 14, 1, 11, 2, 3, 4, 5, 20, 6, 8, 10, 7, 29 },
+ /* new table collation with rules "& Question-mark ; ? & Hash-mark ; # & Ampersand ; '&' " loop to TOTALTESTSET */
+ { 23, 24, 25, 22, 12, 13, 9, 0, 17, 16, 26, 28, 27, 15, 18, 21, 14, 1, 11, 2, 3, 4, 5, 19, 20, 6, 8, 10, 7, 29 },
+ /* analogous to Japanese rules " & aa ; a- & ee ; e- & ii ; i- & oo ; o- & uu ; u- " */ /* loop to TOTALTESTSET */
+ { 19, 22, 21, 24, 23, 25, 12, 13, 9, 0, 17, 16, 28, 26, 27, 15, 18, 14, 1, 11, 2, 3, 4, 5, 20, 6, 8, 10, 7, 29 }
+};
+
+G7CollationTest::~G7CollationTest() {}
+
+void G7CollationTest::TestG7Locales(/* char* par */)
+{
+ int32_t i;
+ const Locale locales[8] = {
+ Locale("en", "US", ""),
+ Locale("en", "GB", ""),
+ Locale("en", "CA", ""),
+ Locale("fr", "FR", ""),
+ Locale("fr", "CA", ""),
+ Locale("de", "DE", ""),
+ Locale("it", "IT", ""),
+ Locale("ja", "JP", "")
+ };
+
+
+ for (i = 0; i < 8; i++)
+ {
+ Collator *myCollation= 0;
+ UnicodeString dispName;
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator* tblColl1 = 0;
+
+ myCollation = Collator::createInstance(locales[i], status);
+ if(U_FAILURE(status)) {
+ delete myCollation;
+ errln("Couldn't instantiate collator. Error: %s", u_errorName(status));
+ return;
+ }
+ myCollation->setStrength(Collator::QUATERNARY);
+ myCollation->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status);
+ if (U_FAILURE(status))
+ {
+ UnicodeString msg;
+
+ msg += "Locale ";
+ msg += locales[i].getDisplayName(dispName);
+ msg += "creation failed.";
+
+ errln(msg);
+ continue;
+ }
+
+// const UnicodeString& defRules = ((RuleBasedCollator*)myCollation)->getRules();
+ status = U_ZERO_ERROR;
+ tblColl1 = new RuleBasedCollator(((RuleBasedCollator*)myCollation)->getRules(), status);
+ if (U_FAILURE(status))
+ {
+ UnicodeString msg, name;
+
+ msg += "Recreate ";
+ msg += locales[i].getDisplayName(name);
+ msg += "collation failed.";
+
+ errln(msg);
+ continue;
+ }
+
+ UnicodeString msg;
+
+ msg += "Locale ";
+ msg += locales[i].getDisplayName(dispName);
+ msg += "tests start :";
+ logln(msg);
+
+ int32_t j, n;
+ for (j = 0; j < FIXEDTESTSET; j++)
+ {
+ for (n = j+1; n < FIXEDTESTSET; n++)
+ {
+ doTest(tblColl1, testCases[results[i][j]], testCases[results[i][n]], Collator::LESS);
+ }
+ }
+
+ delete myCollation;
+ delete tblColl1;
+ }
+}
+
+void G7CollationTest::TestDemo1(/* char* par */)
+{
+ logln("Demo Test 1 : Create a new table collation with rules \"& Z < p, P\"");
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *col = Collator::createInstance("en_US", status);
+ if(U_FAILURE(status)) {
+ delete col;
+ errln("Couldn't instantiate collator. Error: %s", u_errorName(status));
+ return;
+ }
+ const UnicodeString baseRules = ((RuleBasedCollator*)col)->getRules();
+ UnicodeString newRules(" & Z < p, P");
+ newRules.insert(0, baseRules);
+ RuleBasedCollator *myCollation = new RuleBasedCollator(newRules, status);
+
+ if (U_FAILURE(status))
+ {
+ errln( "Demo Test 1 Table Collation object creation failed.");
+ return;
+ }
+
+ int32_t j, n;
+ for (j = 0; j < FIXEDTESTSET; j++)
+ {
+ for (n = j+1; n < FIXEDTESTSET; n++)
+ {
+ doTest(myCollation, testCases[results[8][j]], testCases[results[8][n]], Collator::LESS);
+ }
+ }
+
+ delete myCollation;
+ delete col;
+}
+
+void G7CollationTest::TestDemo2(/* char* par */)
+{
+ logln("Demo Test 2 : Create a new table collation with rules \"& C < ch , cH, Ch, CH\"");
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *col = Collator::createInstance("en_US", status);
+ if(U_FAILURE(status)) {
+ delete col;
+ errln("Couldn't instantiate collator. Error: %s", u_errorName(status));
+ return;
+ }
+ const UnicodeString baseRules = ((RuleBasedCollator*)col)->getRules();
+ UnicodeString newRules("& C < ch , cH, Ch, CH");
+ newRules.insert(0, baseRules);
+ RuleBasedCollator *myCollation = new RuleBasedCollator(newRules, status);
+
+ if (U_FAILURE(status))
+ {
+ errln("Demo Test 2 Table Collation object creation failed.");
+ return;
+ }
+
+ int32_t j, n;
+ for (j = 0; j < TOTALTESTSET; j++)
+ {
+ for (n = j+1; n < TOTALTESTSET; n++)
+ {
+ doTest(myCollation, testCases[results[9][j]], testCases[results[9][n]], Collator::LESS);
+ }
+ }
+
+ delete myCollation;
+ delete col;
+}
+
+void G7CollationTest::TestDemo3(/* char* par */)
+{
+ logln("Demo Test 3 : Create a new table collation with rules \"& Question'-'mark ; '?' & Hash'-'mark ; '#' & Ampersand ; '&'\"");
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *col = Collator::createInstance("en_US", status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't instantiate collator. Error: %s", u_errorName(status));
+ delete col;
+ return;
+ }
+ const UnicodeString baseRules = ((RuleBasedCollator*)col)->getRules();
+ UnicodeString newRules = "& Question'-'mark ; '?' & Hash'-'mark ; '#' & Ampersand ; '&'";
+ newRules.insert(0, baseRules);
+ RuleBasedCollator *myCollation = new RuleBasedCollator(newRules, status);
+
+ if (U_FAILURE(status))
+ {
+ errln("Demo Test 3 Table Collation object creation failed.");
+ return;
+ }
+
+ int32_t j, n;
+ for (j = 0; j < TOTALTESTSET; j++)
+ {
+ for (n = j+1; n < TOTALTESTSET; n++)
+ {
+ doTest(myCollation, testCases[results[10][j]], testCases[results[10][n]], Collator::LESS);
+ }
+ }
+
+ delete myCollation;
+ delete col;
+}
+
+void G7CollationTest::TestDemo4(/* char* par */)
+{
+ logln("Demo Test 4 : Create a new table collation with rules \" & aa ; a'-' & ee ; e'-' & ii ; i'-' & oo ; o'-' & uu ; u'-' \"");
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *col = Collator::createInstance("en_US", status);
+ if(U_FAILURE(status)) {
+ delete col;
+ errln("Couldn't instantiate collator. Error: %s", u_errorName(status));
+ return;
+ }
+
+ const UnicodeString baseRules = ((RuleBasedCollator*)col)->getRules();
+ UnicodeString newRules = " & aa ; a'-' & ee ; e'-' & ii ; i'-' & oo ; o'-' & uu ; u'-' ";
+ newRules.insert(0, baseRules);
+ RuleBasedCollator *myCollation = new RuleBasedCollator(newRules, status);
+
+ int32_t j, n;
+ for (j = 0; j < TOTALTESTSET; j++)
+ {
+ for (n = j+1; n < TOTALTESTSET; n++)
+ {
+ doTest(myCollation, testCases[results[11][j]], testCases[results[11][n]], Collator::LESS);
+ }
+ }
+
+ delete myCollation;
+ delete col;
+}
+
+void G7CollationTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite G7CollationTest: ");
+ switch (index) {
+ case 0: name = "TestG7Locales"; if (exec) TestG7Locales(/* par */); break;
+ case 1: name = "TestDemo1"; if (exec) TestDemo1(/* par */); break;
+ case 2: name = "TestDemo2"; if (exec) TestDemo2(/* par */); break;
+ case 3: name = "TestDemo3"; if (exec) TestDemo3(/* par */); break;
+ case 4: name = "TestDemo4"; if (exec) TestDemo4(/* par */); break;
+ default: name = ""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/g7coll.h b/Build/source/libs/icu/icu-xetex/test/intltest/g7coll.h
new file mode 100644
index 00000000000..cd3d0a13c11
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/g7coll.h
@@ -0,0 +1,77 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * G7CollationTest is a third level test class. This test performs the examples
+ * mentioned on the IBM Java international demos web site.
+ * Sample Rules: & Z < p , P
+ * Effect : Making P sort after Z.
+ *
+ * Sample Rules: & c < ch , cH, Ch, CH
+ * Effect : As well as adding sequences of characters that act as a single character (this is
+ * known as contraction), you can also add characters that act like a sequence of
+ * characters (this is known as expansion).
+ *
+ * Sample Rules: & Question'-'mark ; '?' & Hash'-'mark ; '#' & Ampersand ; '&'
+ * Effect : Expansion and contraction can actually be combined.
+ *
+ * Sample Rules: & aa ; a'-' & ee ; e'-' & ii ; i'-' & oo ; o'-' & uu ; u'-'
+ * Effect : sorted sequence as the following,
+ * aardvark
+ * a-rdvark
+ * abbot
+ * coop
+ * co-p
+ * cop
+ */
+
+#ifndef _G7COLL
+#define _G7COLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/tblcoll.h"
+#include "tscoll.h"
+
+class G7CollationTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ enum ETotal_Locales { TESTLOCALES = 12 };
+ enum ETotal_Fixed { FIXEDTESTSET = 15 };
+ enum ETotal_Test { TOTALTESTSET = 30 };
+
+ G7CollationTest() {}
+ virtual ~G7CollationTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+
+ // perform test for G7 locales
+ void TestG7Locales(/* char* par */);
+
+ // perform test with added rules " & Z < p, P"
+ void TestDemo1(/* char* par */);
+
+ // perorm test with added rules "& C < ch , cH, Ch, CH"
+ void TestDemo2(/* char* par */);
+
+ // perform test with added rules
+ // "& Question'-'mark ; '?' & Hash'-'mark ; '#' & Ampersand ; '&'"
+ void TestDemo3(/* char* par */);
+
+ // perform test with added rules
+ // " & aa ; a'-' & ee ; e'-' & ii ; i'-' & oo ; o'-' & uu ; u'-' "
+ void TestDemo4(/* char* par */);
+
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/icusvtst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/icusvtst.cpp
new file mode 100644
index 00000000000..b3aff063ae1
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/icusvtst.cpp
@@ -0,0 +1,1511 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ *
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE
+
+#include "icusvtst.h"
+#include "servloc.h"
+#include <stdio.h>
+
+
+class MyListener : public EventListener {
+};
+
+class WrongListener : public EventListener {
+};
+
+class ICUNSubclass : public ICUNotifier {
+ public:
+ UBool acceptsListener(const EventListener& /*l*/) const {
+ return TRUE;
+ // return l instanceof MyListener;
+ }
+
+ virtual void notifyListener(EventListener& /*l*/) const {
+ }
+};
+
+// This factory does nothing
+class LKFSubclass0 : public LocaleKeyFactory {
+public:
+ LKFSubclass0()
+ : LocaleKeyFactory(VISIBLE, "LKFSubclass0")
+ {
+ }
+};
+
+class LKFSubclass : public LocaleKeyFactory {
+ Hashtable table;
+
+ public:
+ LKFSubclass(UBool visible)
+ : LocaleKeyFactory(visible ? VISIBLE : INVISIBLE, "LKFSubclass")
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ table.put("en_US", this, status);
+ }
+
+ protected:
+ virtual const Hashtable* getSupportedIDs(UErrorCode &/*status*/) const {
+ return &table;
+ }
+};
+
+class Integer : public UObject {
+ public:
+ const int32_t _val;
+
+ Integer(int32_t val) : _val(val) {
+ }
+
+ Integer(const Integer& rhs) : UObject(rhs), _val(rhs._val) {
+ }
+ virtual ~Integer() {
+ }
+
+ public:
+ /**
+ * UObject boilerplate.
+ */
+ static UClassID getStaticClassID() {
+ return (UClassID)&fgClassID;
+ }
+
+ virtual UClassID getDynamicClassID() const {
+ return getStaticClassID();
+ }
+
+ virtual UBool operator==(const UObject& other) const
+ {
+ return other.getDynamicClassID() == getStaticClassID() &&
+ _val == ((Integer&)other)._val;
+ }
+
+ public:
+ virtual UnicodeString& debug(UnicodeString& result) const {
+ debugClass(result);
+ result.append(" val: ");
+ result.append(_val);
+ return result;
+ }
+
+ virtual UnicodeString& debugClass(UnicodeString& result) const {
+ return result.append("Integer");
+ }
+
+ private:
+ static const char fgClassID;
+};
+
+const char Integer::fgClassID = '\0';
+
+// use locale keys
+class TestIntegerService : public ICUService {
+ public:
+ ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
+ return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
+ }
+
+ virtual ICUServiceFactory* createSimpleFactory(UObject* obj, const UnicodeString& id, UBool visible, UErrorCode& status)
+ {
+ if (U_SUCCESS(status) && obj && obj->getDynamicClassID() == Integer::getStaticClassID()) {
+ return new SimpleFactory((Integer*)obj, id, visible);
+ }
+ return NULL;
+ }
+
+ virtual UObject* cloneInstance(UObject* instance) const {
+ return instance ? new Integer(*(Integer*)instance) : NULL;
+ }
+};
+
+
+ICUServiceTest::ICUServiceTest() {
+}
+
+ICUServiceTest::~ICUServiceTest() {
+}
+
+void
+ICUServiceTest::runIndexedTest(int32_t index, UBool exec, const char* &name,
+char* /*par*/)
+{
+ switch (index) {
+ TESTCASE(0,testAPI_One);
+ TESTCASE(1,testAPI_Two);
+ TESTCASE(2,testRBF);
+ TESTCASE(3,testNotification);
+ TESTCASE(4,testLocale);
+ TESTCASE(5,testWrapFactory);
+ TESTCASE(6,testCoverage);
+ default: name = ""; break;
+ }
+}
+
+UnicodeString append(UnicodeString& result, const UObject* obj)
+{
+ char buffer[128];
+ if (obj == NULL) {
+ result.append("NULL");
+ } else {
+ UClassID id = obj->getDynamicClassID();
+ if (id == UnicodeString::getStaticClassID()) {
+ result.append(*(UnicodeString*)obj);
+ } else if (id == Locale::getStaticClassID()) {
+ result.append(((Locale*)obj)->getName());
+ } else if (id == Integer::getStaticClassID()) {
+ sprintf(buffer, "%d", (int)((Integer*)obj)->_val);
+ result.append(buffer);
+ } else {
+ sprintf(buffer, "%p", (const void*)obj);
+ result.append(buffer);
+ }
+ }
+ return result;
+}
+
+UnicodeString&
+ICUServiceTest::lrmsg(UnicodeString& result, const UnicodeString& message, const UObject* lhs, const UObject* rhs) const
+{
+ result.append(message);
+ result.append(" lhs: ");
+ append(result, lhs);
+ result.append(", rhs: ");
+ append(result, rhs);
+ return result;
+}
+
+void
+ICUServiceTest::confirmBoolean(const UnicodeString& message, UBool val)
+{
+ if (val) {
+ logln(message);
+ } else {
+ errln(message);
+ }
+}
+
+#if 0
+void
+ICUServiceTest::confirmEqual(const UnicodeString& message, const UObject* lhs, const UObject* rhs)
+{
+ UBool equ = (lhs == NULL)
+ ? (rhs == NULL)
+ : (rhs != NULL && lhs->operator==(*rhs));
+
+ UnicodeString temp;
+ lrmsg(temp, message, lhs, rhs);
+
+ if (equ) {
+ logln(temp);
+ } else {
+ errln(temp);
+ }
+}
+#else
+void
+ICUServiceTest::confirmEqual(const UnicodeString& message, const Integer* lhs, const Integer* rhs)
+{
+ UBool equ = (lhs == NULL)
+ ? (rhs == NULL)
+ : (rhs != NULL && lhs->operator==(*rhs));
+
+ UnicodeString temp;
+ lrmsg(temp, message, lhs, rhs);
+
+ if (equ) {
+ logln(temp);
+ } else {
+ errln(temp);
+ }
+}
+
+void
+ICUServiceTest::confirmEqual(const UnicodeString& message, const UnicodeString* lhs, const UnicodeString* rhs)
+{
+ UBool equ = (lhs == NULL)
+ ? (rhs == NULL)
+ : (rhs != NULL && lhs->operator==(*rhs));
+
+ UnicodeString temp;
+ lrmsg(temp, message, lhs, rhs);
+
+ if (equ) {
+ logln(temp);
+ } else {
+ errln(temp);
+ }
+}
+
+void
+ICUServiceTest::confirmEqual(const UnicodeString& message, const Locale* lhs, const Locale* rhs)
+{
+ UBool equ = (lhs == NULL)
+ ? (rhs == NULL)
+ : (rhs != NULL && lhs->operator==(*rhs));
+
+ UnicodeString temp;
+ lrmsg(temp, message, lhs, rhs);
+
+ if (equ) {
+ logln(temp);
+ } else {
+ errln(temp);
+ }
+}
+#endif
+
+// use these for now
+void
+ICUServiceTest::confirmStringsEqual(const UnicodeString& message, const UnicodeString& lhs, const UnicodeString& rhs)
+{
+ UBool equ = lhs == rhs;
+
+ UnicodeString temp = message;
+ temp.append(" lhs: ");
+ temp.append(lhs);
+ temp.append(" rhs: ");
+ temp.append(rhs);
+
+ if (equ) {
+ logln(temp);
+ } else {
+ errln(temp);
+ }
+}
+
+
+void
+ICUServiceTest::confirmIdentical(const UnicodeString& message, const UObject* lhs, const UObject *rhs)
+{
+ UnicodeString temp;
+ lrmsg(temp, message, lhs, rhs);
+ if (lhs == rhs) {
+ logln(temp);
+ } else {
+ errln(temp);
+ }
+}
+
+void
+ICUServiceTest::confirmIdentical(const UnicodeString& message, int32_t lhs, int32_t rhs)
+{
+ if (lhs == rhs) {
+ logln(message + " lhs: " + lhs + " rhs: " + rhs);
+ } else {
+ errln(message + " lhs: " + lhs + " rhs: " + rhs);
+ }
+}
+
+void
+ICUServiceTest::msgstr(const UnicodeString& message, UObject* obj, UBool err)
+{
+ if (obj) {
+ UnicodeString* str = (UnicodeString*)obj;
+ logln(message + *str);
+ delete str;
+ } else if (err) {
+ errln("Error " + message + "string is NULL");
+ }
+}
+
+void
+ICUServiceTest::testAPI_One()
+{
+ // create a service using locale keys,
+ TestIntegerService service;
+
+ // register an object with one locale,
+ // search for an object with a more specific locale
+ // should return the original object
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* singleton0 = new Integer(0);
+ service.registerInstance(singleton0, "en_US", status);
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("en_US_FOO", status);
+ confirmEqual("1) en_US_FOO -> en_US", result, singleton0);
+ delete result;
+ }
+
+ // register a new object with the more specific locale
+ // search for an object with that locale
+ // should return the new object
+ Integer* singleton1 = new Integer(1);
+ service.registerInstance(singleton1, "en_US_FOO", status);
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("en_US_FOO", status);
+ confirmEqual("2) en_US_FOO -> en_US_FOO", result, singleton1);
+ delete result;
+ }
+
+ // search for an object that falls back to the first registered locale
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("en_US_BAR", status);
+ confirmEqual("3) en_US_BAR -> en_US", result, singleton0);
+ delete result;
+ }
+
+ // get a list of the factories, should be two
+ {
+ confirmIdentical("4) factory size", service.countFactories(), 2);
+ }
+
+ // register a new object with yet another locale
+ Integer* singleton2 = new Integer(2);
+ service.registerInstance(singleton2, "en", status);
+ {
+ confirmIdentical("5) factory size", service.countFactories(), 3);
+ }
+
+ // search for an object with the new locale
+ // stack of factories is now en, en_US_FOO, en_US
+ // search for en_US should still find en_US object
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("en_US_BAR", status);
+ confirmEqual("6) en_US_BAR -> en_US", result, singleton0);
+ delete result;
+ }
+
+ // register a new object with an old id, should hide earlier factory using this id, but leave it there
+ Integer* singleton3 = new Integer(3);
+ URegistryKey s3key = service.registerInstance(singleton3, "en_US", status);
+ {
+ confirmIdentical("9) factory size", service.countFactories(), 4);
+ }
+
+ // should get data from that new factory
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("en_US_BAR", status);
+ confirmEqual("10) en_US_BAR -> (3)", result, singleton3);
+ delete result;
+ }
+
+ // remove new factory
+ // should have fewer factories again
+ // singleton3 dead!
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ service.unregister(s3key, status);
+ confirmIdentical("11) factory size", service.countFactories(), 3);
+ }
+
+ // should get original data again after remove factory
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("en_US_BAR", status);
+ confirmEqual("12) en_US_BAR -> (3)", result, singleton0);
+ delete result;
+ }
+
+ // shouldn't find unregistered ids
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("foo", status);
+ confirmIdentical("13) foo -> null", result, NULL);
+ delete result;
+ }
+
+ // should find non-canonical strings
+ {
+ UnicodeString resultID;
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("EN_us_fOo", &resultID, status);
+ confirmEqual("14a) find-non-canonical", result, singleton1);
+ confirmStringsEqual("14b) find non-canonical", resultID, "en_US_FOO");
+ delete result;
+ }
+
+ // should be able to register non-canonical strings and get them canonicalized
+ Integer* singleton4 = new Integer(4);
+ service.registerInstance(singleton4, "eN_ca_dUde", status);
+ {
+ UnicodeString resultID;
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("En_Ca_DuDe", &resultID, status);
+ confirmEqual("15a) find-non-canonical", result, singleton4);
+ confirmStringsEqual("15b) register non-canonical", resultID, "en_CA_DUDE");
+ delete result;
+ }
+
+ // should be able to register invisible factories, these will not
+ // be visible by default, but if you know the secret password you
+ // can still access these services...
+ Integer* singleton5 = new Integer(5);
+ service.registerInstance(singleton5, "en_US_BAR", FALSE, status);
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Integer* result = (Integer*)service.get("en_US_BAR", status);
+ confirmEqual("17) get invisible", result, singleton5);
+ delete result;
+ }
+
+ // should not be able to locate invisible services
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ service.getVisibleIDs(ids, status);
+ UnicodeString target = "en_US_BAR";
+ confirmBoolean("18) find invisible", !ids.contains(&target));
+ }
+
+ // clear factory and caches
+ service.reset();
+ confirmBoolean("19) is default", service.isDefault());
+}
+
+/*
+ ******************************************************************
+ */
+class TestStringSimpleKeyService : public ICUService {
+public:
+
+ virtual ICUServiceFactory* createSimpleFactory(UObject* obj, const UnicodeString& id, UBool visible, UErrorCode& status)
+ {
+ // We could put this type check into ICUService itself, but we'd still
+ // have to implement cloneInstance. Otherwise we could just tell the service
+ // what the object type is when we create it, and the default implementation
+ // could handle everything for us. Phooey.
+ if (obj && obj->getDynamicClassID() == UnicodeString::getStaticClassID()) {
+ return ICUService::createSimpleFactory(obj, id, visible, status);
+ }
+ return NULL;
+ }
+
+ virtual UObject* cloneInstance(UObject* instance) const {
+ return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
+ }
+};
+
+class TestStringService : public ICUService {
+ public:
+ ICUServiceKey* createKey(const UnicodeString* id, UErrorCode& status) const {
+ return LocaleKey::createWithCanonicalFallback(id, NULL, status); // no fallback locale
+ }
+
+ virtual ICUServiceFactory* createSimpleFactory(UObject* obj, const UnicodeString& id, UBool visible, UErrorCode& /* status */)
+ {
+ if (obj && obj->getDynamicClassID() == UnicodeString::getStaticClassID()) {
+ return new SimpleFactory((UnicodeString*)obj, id, visible);
+ }
+ return NULL;
+ }
+
+ virtual UObject* cloneInstance(UObject* instance) const {
+ return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
+ }
+};
+
+// this creates a string for any id, but doesn't report anything
+class AnonymousStringFactory : public ICUServiceFactory
+{
+ public:
+ virtual UObject* create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& /* status */) const {
+ return new UnicodeString(key.getID());
+ }
+
+ virtual void updateVisibleIDs(Hashtable& /*result*/, UErrorCode& /*status*/) const {
+ // do nothing
+ }
+
+ virtual UnicodeString& getDisplayName(const UnicodeString& /*id*/, const Locale& /*locale*/, UnicodeString& result) const {
+ // do nothing
+ return result;
+ }
+
+ static UClassID getStaticClassID() {
+ return (UClassID)&fgClassID;
+ }
+
+ virtual UClassID getDynamicClassID() const {
+ return getStaticClassID();
+ }
+
+ private:
+ static const char fgClassID;
+};
+
+const char AnonymousStringFactory::fgClassID = '\0';
+
+class TestMultipleKeyStringFactory : public ICUServiceFactory {
+ UErrorCode _status;
+ UVector _ids;
+ UnicodeString _factoryID;
+
+ public:
+ TestMultipleKeyStringFactory(const UnicodeString ids[], int32_t count, const UnicodeString& factoryID)
+ : _status(U_ZERO_ERROR)
+ , _ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, count, _status)
+ , _factoryID(factoryID + ": ")
+ {
+ for (int i = 0; i < count; ++i) {
+ _ids.addElement(new UnicodeString(ids[i]), _status);
+ }
+ }
+
+ ~TestMultipleKeyStringFactory() {
+ }
+
+ UObject* create(const ICUServiceKey& key, const ICUService* /* service */, UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ UnicodeString temp;
+ key.currentID(temp);
+ if (U_SUCCESS(_status)) {
+ if (_ids.contains(&temp)) {
+ return new UnicodeString(_factoryID + temp);
+ }
+ } else {
+ status = _status;
+ }
+ return NULL;
+ }
+
+ void updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
+ if (U_SUCCESS(_status)) {
+ for (int32_t i = 0; i < _ids.size(); ++i) {
+ result.put(*(UnicodeString*)_ids[i], (void*)this, status);
+ }
+ }
+ }
+
+ UnicodeString& getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const {
+ if (U_SUCCESS(_status) && _ids.contains((void*)&id)) {
+ char buffer[128];
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len = id.extract(buffer, sizeof(buffer), NULL, status);
+ if (U_SUCCESS(status)) {
+ if (len == sizeof(buffer)) {
+ --len;
+ }
+ buffer[len] = 0;
+ Locale loc = Locale::createFromName(buffer);
+ loc.getDisplayName(locale, result);
+ return result;
+ }
+ }
+ result.setToBogus(); // shouldn't happen
+ return result;
+ }
+
+ static UClassID getStaticClassID() {
+ return (UClassID)&fgClassID;
+ }
+
+ virtual UClassID getDynamicClassID() const {
+ return getStaticClassID();
+ }
+
+ private:
+ static const char fgClassID;
+};
+
+const char TestMultipleKeyStringFactory::fgClassID = '\0';
+
+void
+ICUServiceTest::testAPI_Two()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ TestStringService service;
+ service.registerFactory(new AnonymousStringFactory(), status);
+
+ // anonymous factory will still handle the id
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ const UnicodeString en_US = "en_US";
+ UnicodeString* result = (UnicodeString*)service.get(en_US, status);
+ confirmEqual("21) locale", result, &en_US);
+ delete result;
+ }
+
+ // still normalizes id
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ const UnicodeString en_US_BAR = "en_US_BAR";
+ UnicodeString resultID;
+ UnicodeString* result = (UnicodeString*)service.get("EN_us_bar", &resultID, status);
+ confirmEqual("22) locale", &resultID, &en_US_BAR);
+ delete result;
+ }
+
+ // we can override for particular ids
+ UnicodeString* singleton0 = new UnicodeString("Zero");
+ service.registerInstance(singleton0, "en_US_BAR", status);
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* result = (UnicodeString*)service.get("en_US_BAR", status);
+ confirmEqual("23) override super", result, singleton0);
+ delete result;
+ }
+
+ // empty service should not recognize anything
+ service.reset();
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* result = (UnicodeString*)service.get("en_US", status);
+ confirmIdentical("24) empty", result, NULL);
+ }
+
+ // create a custom multiple key factory
+ {
+ UnicodeString xids[] = {
+ "en_US_VALLEY_GIRL",
+ "en_US_VALLEY_BOY",
+ "en_US_SURFER_GAL",
+ "en_US_SURFER_DUDE"
+ };
+ int32_t count = sizeof(xids)/sizeof(UnicodeString);
+
+ ICUServiceFactory* f = new TestMultipleKeyStringFactory(xids, count, "Later");
+ service.registerFactory(f, status);
+ }
+
+ // iterate over the visual ids returned by the multiple factory
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
+ service.getVisibleIDs(ids, status);
+ for (int i = 0; i < ids.size(); ++i) {
+ const UnicodeString* id = (const UnicodeString*)ids[i];
+ UnicodeString* result = (UnicodeString*)service.get(*id, status);
+ if (result) {
+ logln(" " + *id + " --> " + *result);
+ delete result;
+ } else {
+ errln("could not find " + *id);
+ }
+ }
+ // four visible ids
+ confirmIdentical("25) visible ids", ids.size(), 4);
+ }
+
+ // iterate over the display names
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector names(status);
+ service.getDisplayNames(names, status);
+ for (int i = 0; i < names.size(); ++i) {
+ const StringPair* pair = (const StringPair*)names[i];
+ logln(" " + pair->displayName + " --> " + pair->id);
+ }
+ confirmIdentical("26) display names", names.size(), 4);
+ }
+
+ // no valid display name
+ {
+ UnicodeString name;
+ service.getDisplayName("en_US_VALLEY_GEEK", name);
+ confirmBoolean("27) get display name", name.isBogus());
+ }
+
+ {
+ UnicodeString name;
+ service.getDisplayName("en_US_SURFER_DUDE", name, Locale::getEnglish());
+ confirmStringsEqual("28) get display name", name, "English (United States, SURFER_DUDE)");
+ }
+
+ // register another multiple factory
+ {
+ UnicodeString xids[] = {
+ "en_US_SURFER",
+ "en_US_SURFER_GAL",
+ "en_US_SILICON",
+ "en_US_SILICON_GEEK",
+ };
+ int32_t count = sizeof(xids)/sizeof(UnicodeString);
+
+ ICUServiceFactory* f = new TestMultipleKeyStringFactory(xids, count, "Rad dude");
+ service.registerFactory(f, status);
+ }
+
+ // this time, we have seven display names
+ // Rad dude's surfer gal 'replaces' Later's surfer gal
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector names(status);
+ service.getDisplayNames(names, Locale("es"), status);
+ for (int i = 0; i < names.size(); ++i) {
+ const StringPair* pair = (const StringPair*)names[i];
+ logln(" " + pair->displayName + " --> " + pair->id);
+ }
+ confirmIdentical("26) display names", names.size(), 7);
+ }
+
+ // we should get the display name corresponding to the actual id
+ // returned by the id we used.
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString actualID;
+ UnicodeString id = "en_us_surfer_gal";
+ UnicodeString* gal = (UnicodeString*)service.get(id, &actualID, status);
+ if (gal != NULL) {
+ UnicodeString displayName;
+ logln("actual id: " + actualID);
+ service.getDisplayName(actualID, displayName, Locale::getEnglish());
+ logln("found actual: " + *gal + " with display name: " + displayName);
+ confirmBoolean("30) found display name for actual", !displayName.isBogus());
+
+ service.getDisplayName(id, displayName, Locale::getEnglish());
+ logln("found actual: " + *gal + " with display name: " + displayName);
+ confirmBoolean("31) found display name for query", displayName.isBogus());
+
+ delete gal;
+ } else {
+ errln("30) service could not find entry for " + id);
+ }
+ }
+
+ // this should be handled by the 'dude' factory, since it overrides en_US_SURFER.
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString actualID;
+ UnicodeString id = "en_US_SURFER_BOZO";
+ UnicodeString* bozo = (UnicodeString*)service.get(id, &actualID, status);
+ if (bozo != NULL) {
+ UnicodeString displayName;
+ service.getDisplayName(actualID, displayName, Locale::getEnglish());
+ logln("found actual: " + *bozo + " with display name: " + displayName);
+ confirmBoolean("32) found display name for actual", !displayName.isBogus());
+
+ service.getDisplayName(id, displayName, Locale::getEnglish());
+ logln("found actual: " + *bozo + " with display name: " + displayName);
+ confirmBoolean("33) found display name for query", displayName.isBogus());
+
+ delete bozo;
+ } else {
+ errln("32) service could not find entry for " + id);
+ }
+ }
+
+ // certainly not default...
+ {
+ confirmBoolean("34) is default ", !service.isDefault());
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
+ service.getVisibleIDs(ids, status);
+ for (int i = 0; i < ids.size(); ++i) {
+ const UnicodeString* id = (const UnicodeString*)ids[i];
+ msgstr(*id + "? ", service.get(*id, status));
+ }
+
+ logstr("valleygirl? ", service.get("en_US_VALLEY_GIRL", status));
+ logstr("valleyboy? ", service.get("en_US_VALLEY_BOY", status));
+ logstr("valleydude? ", service.get("en_US_VALLEY_DUDE", status));
+ logstr("surfergirl? ", service.get("en_US_SURFER_GIRL", status));
+ }
+}
+
+
+class CalifornioLanguageFactory : public ICUResourceBundleFactory
+{
+ public:
+ static const char* californio; // = "en_US_CA";
+ static const char* valley; // = californio ## "_VALLEY";
+ static const char* surfer; // = californio ## "_SURFER";
+ static const char* geek; // = californio ## "_GEEK";
+ static Hashtable* supportedIDs; // = NULL;
+
+ static void cleanup(void) {
+ delete supportedIDs;
+ supportedIDs = NULL;
+ }
+
+ const Hashtable* getSupportedIDs(UErrorCode& status) const
+ {
+ if (supportedIDs == NULL) {
+ Hashtable* table = new Hashtable();
+ table->put(UnicodeString(californio), (void*)table, status);
+ table->put(UnicodeString(valley), (void*)table, status);
+ table->put(UnicodeString(surfer), (void*)table, status);
+ table->put(UnicodeString(geek), (void*)table, status);
+
+ // not necessarily atomic, but this is a test...
+ supportedIDs = table;
+ }
+ return supportedIDs;
+ }
+
+ UnicodeString& getDisplayName(const UnicodeString& id, const Locale& locale, UnicodeString& result) const
+ {
+ UnicodeString prefix = "";
+ UnicodeString suffix = "";
+ UnicodeString ls = locale.getName();
+ if (LocaleUtility::isFallbackOf(californio, ls)) {
+ if (!ls.caseCompare(valley, 0)) {
+ prefix = "Like, you know, it's so totally ";
+ } else if (!ls.caseCompare(surfer, 0)) {
+ prefix = "Dude, it's ";
+ } else if (!ls.caseCompare(geek, 0)) {
+ prefix = "I'd estimate it is approximately ";
+ } else {
+ prefix = "Huh? Maybe ";
+ }
+ }
+ if (LocaleUtility::isFallbackOf(californio, id)) {
+ if (!id.caseCompare(valley, 0)) {
+ suffix = "like the Valley, you know? Let's go to the mall!";
+ } else if (!id.caseCompare(surfer, 0)) {
+ suffix = "time to hit those gnarly waves, Dude!!!";
+ } else if (!id.caseCompare(geek, 0)) {
+ suffix = "all systems go. T-Minus 9, 8, 7...";
+ } else {
+ suffix = "No Habla Englais";
+ }
+ } else {
+ suffix = ICUResourceBundleFactory::getDisplayName(id, locale, result);
+ }
+
+ result = prefix + suffix;
+ return result;
+ }
+};
+
+const char* CalifornioLanguageFactory::californio = "en_US_CA";
+const char* CalifornioLanguageFactory::valley = "en_US_CA_VALLEY";
+const char* CalifornioLanguageFactory::surfer = "en_US_CA_SURFER";
+const char* CalifornioLanguageFactory::geek = "en_US_CA_GEEK";
+Hashtable* CalifornioLanguageFactory::supportedIDs = NULL;
+
+void
+ICUServiceTest::testRBF()
+{
+ // resource bundle factory.
+ UErrorCode status = U_ZERO_ERROR;
+ TestStringService service;
+ service.registerFactory(new ICUResourceBundleFactory(), status);
+
+ // list all of the resources
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
+ service.getVisibleIDs(ids, status);
+ logln("all visible ids:");
+ for (int i = 0; i < ids.size(); ++i) {
+ const UnicodeString* id = (const UnicodeString*)ids[i];
+ logln(*id);
+ }
+ }
+
+ // get all the display names of these resources
+ // this should be fast since the display names were cached.
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector names(status);
+ service.getDisplayNames(names, Locale::getGermany(), status);
+ logln("service display names for de_DE");
+ for (int i = 0; i < names.size(); ++i) {
+ const StringPair* pair = (const StringPair*)names[i];
+ logln(" " + pair->displayName + " --> " + pair->id);
+ }
+ }
+
+ service.registerFactory(new CalifornioLanguageFactory(), status);
+
+ // get all the display names of these resources
+ {
+ logln("californio language factory:");
+ const char* idNames[] = {
+ CalifornioLanguageFactory::californio,
+ CalifornioLanguageFactory::valley,
+ CalifornioLanguageFactory::surfer,
+ CalifornioLanguageFactory::geek,
+ };
+ int32_t count = sizeof(idNames)/sizeof(idNames[0]);
+
+ for (int i = 0; i < count; ++i) {
+ logln(UnicodeString("\n --- ") + idNames[i] + " ---");
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector names(status);
+ service.getDisplayNames(names, idNames[i], status);
+ for (int i = 0; i < names.size(); ++i) {
+ const StringPair* pair = (const StringPair*)names[i];
+ logln(" " + pair->displayName + " --> " + pair->id);
+ }
+ }
+ }
+ }
+ CalifornioLanguageFactory::cleanup();
+}
+
+class SimpleListener : public ServiceListener {
+ ICUServiceTest* _test;
+ int32_t _n;
+ UnicodeString _name;
+
+ public:
+ SimpleListener(ICUServiceTest* test, const UnicodeString& name) : _test(test), _n(0), _name(name) {}
+
+ virtual void serviceChanged(const ICUService& service) const {
+ UnicodeString serviceName = "listener ";
+ serviceName.append(_name);
+ serviceName.append(" n++");
+ serviceName.append(" service changed: " );
+ service.getName(serviceName);
+ _test->logln(serviceName);
+ }
+};
+
+void
+ICUServiceTest::testNotification()
+{
+ SimpleListener one(this, "one");
+ SimpleListener two(this, "two");
+ {
+ UErrorCode status = U_ZERO_ERROR;
+
+ logln("simple registration notification");
+ TestStringService ls;
+ ls.addListener(&one, status);
+ ls.addListener(&two, status);
+
+ logln("registering foo... ");
+ ls.registerInstance(new UnicodeString("Foo"), "en_FOO", status);
+ logln("registering bar... ");
+ ls.registerInstance(new UnicodeString("Bar"), "en_BAR", status);
+ logln("getting foo...");
+ UnicodeString* result = (UnicodeString*)ls.get("en_FOO", status);
+ logln(*result);
+ delete result;
+
+ logln("removing listener 2...");
+ ls.removeListener(&two, status);
+ logln("registering baz...");
+ ls.registerInstance(new UnicodeString("Baz"), "en_BAZ", status);
+ logln("removing listener 1");
+ ls.removeListener(&one, status);
+ logln("registering burp...");
+ ls.registerInstance(new UnicodeString("Burp"), "en_BURP", status);
+
+ // should only get one notification even if register multiple times
+ logln("... trying multiple registration");
+ ls.addListener(&one, status);
+ ls.addListener(&one, status);
+ ls.addListener(&one, status);
+ ls.addListener(&two, status);
+ ls.registerInstance(new UnicodeString("Foo"), "en_FOO", status);
+ logln("... registered foo");
+ }
+#if 0
+ // same thread, so we can't callback within notification, unlike Java
+ ServiceListener l3 = new ServiceListener() {
+private int n;
+public void serviceChanged(ICUService s) {
+ logln("listener 3 report " + n++ + " service changed...");
+ if (s.get("en_BOINK") == null) { // don't recurse on ourselves!!!
+ logln("registering boink...");
+ s.registerInstance("boink", "en_BOINK");
+ }
+}
+ };
+ ls.addListener(l3);
+ logln("registering boo...");
+ ls.registerInstance("Boo", "en_BOO");
+#endif
+
+ logln("...done");
+}
+
+class TestStringLocaleService : public ICULocaleService {
+ public:
+ virtual UObject* cloneInstance(UObject* instance) const {
+ return instance ? new UnicodeString(*(UnicodeString*)instance) : NULL;
+ }
+};
+
+void ICUServiceTest::testLocale() {
+ UErrorCode status = U_ZERO_ERROR;
+ TestStringLocaleService service;
+
+ UnicodeString* root = new UnicodeString("root");
+ UnicodeString* german = new UnicodeString("german");
+ UnicodeString* germany = new UnicodeString("german_Germany");
+ UnicodeString* japanese = new UnicodeString("japanese");
+ UnicodeString* japan = new UnicodeString("japanese_Japan");
+
+ service.registerInstance(root, "", status);
+ service.registerInstance(german, "de", status);
+ service.registerInstance(germany, Locale::getGermany(), status);
+ service.registerInstance(japanese, (UnicodeString)"ja", TRUE, status);
+ service.registerInstance(japan, Locale::getJapan(), status);
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* target = (UnicodeString*)service.get("de_US", status);
+ confirmEqual("test de_US", german, target);
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* target = (UnicodeString*)service.get("de_US", LocaleKey::KIND_ANY, status);
+ confirmEqual("test de_US 2", german, target);
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* target = (UnicodeString*)service.get("de_US", 1234, status);
+ confirmEqual("test de_US 3", german, target);
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Locale actualReturn;
+ UnicodeString* target = (UnicodeString*)service.get("de_US", &actualReturn, status);
+ confirmEqual("test de_US 5", german, target);
+ confirmEqual("test de_US 6", &actualReturn, &Locale::getGerman());
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Locale actualReturn;
+ UnicodeString* target = (UnicodeString*)service.get("de_US", LocaleKey::KIND_ANY, &actualReturn, status);
+ confirmEqual("test de_US 7", &actualReturn, &Locale::getGerman());
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Locale actualReturn;
+ UnicodeString* target = (UnicodeString*)service.get("de_US", 1234, &actualReturn, status);
+ confirmEqual("test de_US 8", german, target);
+ confirmEqual("test de_US 9", &actualReturn, &Locale::getGerman());
+ delete target;
+ }
+
+ UnicodeString* one = new UnicodeString("one/de_US");
+ UnicodeString* two = new UnicodeString("two/de_US");
+
+ service.registerInstance(one, Locale("de_US"), 1, status);
+ service.registerInstance(two, Locale("de_US"), 2, status);
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* target = (UnicodeString*)service.get("de_US", 1, status);
+ confirmEqual("test de_US kind 1", one, target);
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* target = (UnicodeString*)service.get("de_US", 2, status);
+ confirmEqual("test de_US kind 2", two, target);
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* target = (UnicodeString*)service.get("de_US", status);
+ confirmEqual("test de_US kind 3", german, target);
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString english = "en";
+ Locale localeResult;
+ UnicodeString result;
+ LocaleKey* lkey = LocaleKey::createWithCanonicalFallback(&english, NULL, 1234, status);
+ logln("lkey prefix: " + lkey->prefix(result));
+ result.remove();
+ logln("lkey descriptor: " + lkey->currentDescriptor(result));
+ result.remove();
+ logln(UnicodeString("lkey current locale: ") + lkey->currentLocale(localeResult).getName());
+ result.remove();
+
+ lkey->fallback();
+ logln("lkey descriptor 2: " + lkey->currentDescriptor(result));
+ result.remove();
+
+ lkey->fallback();
+ logln("lkey descriptor 3: " + lkey->currentDescriptor(result));
+ result.remove();
+ delete lkey; // tentatively weiv
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* target = (UnicodeString*)service.get("za_PPP", status);
+ confirmEqual("test zappp", root, target);
+ delete target;
+ }
+
+ Locale loc = Locale::getDefault();
+ Locale::setDefault(Locale::getJapanese(), status);
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* target = (UnicodeString*)service.get("za_PPP", status);
+ confirmEqual("test with ja locale", japanese, target);
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
+ service.getVisibleIDs(ids, status);
+ logln("all visible ids:");
+ for (int i = 0; i < ids.size(); ++i) {
+ const UnicodeString* id = (const UnicodeString*)ids[i];
+ logln(*id);
+ }
+ }
+
+ Locale::setDefault(loc, status);
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, 0, status);
+ service.getVisibleIDs(ids, status);
+ logln("all visible ids:");
+ for (int i = 0; i < ids.size(); ++i) {
+ const UnicodeString* id = (const UnicodeString*)ids[i];
+ logln(*id);
+ }
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* target = (UnicodeString*)service.get("za_PPP", status);
+ confirmEqual("test with en locale", root, target);
+ delete target;
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ StringEnumeration* locales = service.getAvailableLocales();
+ if (locales) {
+ confirmIdentical("test available locales", locales->count(status), 6);
+ logln("locales: ");
+ {
+ const char* p;
+ while ((p = locales->next(NULL, status))) {
+ logln(p);
+ }
+ }
+ logln(" ");
+ delete locales;
+ } else {
+ errln("could not create available locales");
+ }
+ }
+}
+
+class WrapFactory : public ICUServiceFactory {
+ public:
+ static const UnicodeString& getGreetingID() {
+ if (greetingID == NULL) {
+ greetingID = new UnicodeString("greeting");
+ }
+ return *greetingID;
+ }
+
+ static void cleanup() {
+ delete greetingID;
+ greetingID = NULL;
+ }
+
+ UObject* create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const {
+ if (U_SUCCESS(status)) {
+ UnicodeString temp;
+ if (key.currentID(temp).compare(getGreetingID()) == 0) {
+ UnicodeString* previous = (UnicodeString*)service->getKey((ICUServiceKey&)key, NULL, this, status);
+ if (previous) {
+ previous->insert(0, "A different greeting: \"");
+ previous->append("\"");
+ return previous;
+ }
+ }
+ }
+ return NULL;
+ }
+
+ void updateVisibleIDs(Hashtable& result, UErrorCode& status) const {
+ if (U_SUCCESS(status)) {
+ result.put("greeting", (void*)this, status);
+ }
+ }
+
+ UnicodeString& getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const {
+ result.append("wrap '");
+ result.append(id);
+ result.append("'");
+ return result;
+ }
+
+ /**
+ * UObject boilerplate.
+ */
+ static UClassID getStaticClassID() {
+ return (UClassID)&fgClassID;
+ }
+
+ virtual UClassID getDynamicClassID() const {
+ return getStaticClassID();
+ }
+
+ private:
+ static const char fgClassID;
+ static UnicodeString* greetingID;
+};
+
+UnicodeString* WrapFactory::greetingID = NULL;
+const char WrapFactory::fgClassID = '\0';
+
+void
+ICUServiceTest::testWrapFactory()
+{
+ UnicodeString* greeting = new UnicodeString("Hello There");
+ UnicodeString greetingID = "greeting";
+ UErrorCode status = U_ZERO_ERROR;
+ TestStringService service;
+ service.registerInstance(greeting, greetingID, status);
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* result = (UnicodeString*)service.get(greetingID, status);
+ if (result) {
+ logln("test one: " + *result);
+ delete result;
+ }
+ }
+
+ service.registerFactory(new WrapFactory(), status);
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* result = (UnicodeString*)service.get(greetingID, status);
+ UnicodeString target = "A different greeting: \"Hello There\"";
+ confirmEqual("wrap test: ", result, &target);
+ delete result;
+ }
+
+ WrapFactory::cleanup();
+}
+
+ // misc coverage tests
+void ICUServiceTest::testCoverage()
+{
+ // ICUServiceKey
+ {
+ UnicodeString temp;
+ ICUServiceKey key("foobar");
+ logln("ID: " + key.getID());
+ logln("canonicalID: " + key.canonicalID(temp));
+ logln("currentID: " + key.currentID(temp.remove()));
+ logln("has fallback: " + UnicodeString(key.fallback() ? "true" : "false"));
+
+ if (key.getDynamicClassID() != ICUServiceKey::getStaticClassID()) {
+ errln("service key rtt failed.");
+ }
+ }
+
+ // SimpleFactory
+ {
+ UErrorCode status = U_ZERO_ERROR;
+
+ UnicodeString* obj = new UnicodeString("An Object");
+ SimpleFactory* sf = new SimpleFactory(obj, "object");
+
+ UnicodeString temp;
+ logln(sf->getDisplayName("object", Locale::getDefault(), temp));
+
+ if (sf->getDynamicClassID() != SimpleFactory::getStaticClassID()) {
+ errln("simple factory rtti failed.");
+ }
+
+ // ICUService
+ {
+ TestStringService service;
+ service.registerFactory(sf, status);
+
+ {
+ UnicodeString* result = (UnicodeString*)service.get("object", status);
+ if (result) {
+ logln("object is: " + *result);
+ delete result;
+ } else {
+ errln("could not get object");
+ }
+ }
+ }
+ }
+
+ // ICUServiceKey
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString* howdy = new UnicodeString("Howdy");
+
+ TestStringSimpleKeyService service;
+ service.registerInstance(howdy, "Greetings", status);
+ {
+ UnicodeString* result = (UnicodeString*)service.get("Greetings", status);
+ if (result) {
+ logln("object is: " + *result);
+ delete result;
+ } else {
+ errln("could not get object");
+ }
+ }
+
+ UVector ids(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+ // yuck, this is awkward to use. All because we pass null in an overload.
+ // TODO: change this.
+ UnicodeString str("Greet");
+ service.getVisibleIDs(ids, &str, status);
+ confirmIdentical("no fallback of greet", ids.size(), 0);
+ }
+
+ // ICULocaleService
+
+ // LocaleKey
+ {
+ UnicodeString primary("en_US");
+ UnicodeString fallback("ja_JP");
+ UErrorCode status = U_ZERO_ERROR;
+ LocaleKey* key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, status);
+
+ if (key->getDynamicClassID() != LocaleKey::getStaticClassID()) {
+ errln("localekey rtti error");
+ }
+
+ if (!key->isFallbackOf("en_US_FOOBAR")) {
+ errln("localekey should be fallback for en_US_FOOBAR");
+ }
+ if (!key->isFallbackOf("en_US")) {
+ errln("localekey should be fallback for en_US");
+ }
+ if (key->isFallbackOf("en")) {
+ errln("localekey should not be fallback for en");
+ }
+
+ do {
+ Locale loc;
+ logln(UnicodeString("current locale: ") + key->currentLocale(loc).getName());
+ logln(UnicodeString("canonical locale: ") + key->canonicalLocale(loc).getName());
+ logln(UnicodeString("is fallback of en: ") + (key->isFallbackOf("en") ? "true" : " false"));
+ } while (key->fallback());
+ delete key;
+
+ // LocaleKeyFactory
+ key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, status);
+
+ UnicodeString result;
+ LKFSubclass lkf(TRUE); // empty
+ Hashtable table;
+
+ UObject *obj = lkf.create(*key, NULL, status);
+ logln("obj: " + UnicodeString(obj ? "obj" : "null"));
+ logln(lkf.getDisplayName("en_US", Locale::getDefault(), result));
+ lkf.updateVisibleIDs(table, status);
+ delete obj;
+ if (table.count() != 1) {
+ errln("visible IDs does not contain en_US");
+ }
+
+ LKFSubclass invisibleLKF(FALSE);
+ obj = lkf.create(*key, NULL, status);
+ logln("obj: " + UnicodeString(obj ? "obj" : "null"));
+ logln(invisibleLKF.getDisplayName("en_US", Locale::getDefault(), result.remove()));
+ invisibleLKF.updateVisibleIDs(table, status);
+ if (table.count() != 0) {
+ errln("visible IDs contains en_US");
+ }
+ delete obj;
+ delete key;
+
+ key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, 123, status);
+ if (U_SUCCESS(status)) {
+ UnicodeString str;
+ key->currentDescriptor(str);
+ key->parsePrefix(str);
+ if (str != "123") {
+ errln("did not get expected prefix");
+ }
+ delete key;
+ }
+
+ // coverage, getSupportedIDs is either overridden or the calling method is
+ LKFSubclass0 lkFactory;
+ Hashtable table0;
+ lkFactory.updateVisibleIDs(table0, status);
+ if (table0.count() != 0) {
+ errln("LKF returned non-empty hashtable");
+ }
+
+
+ // ResourceBundleFactory
+ key = LocaleKey::createWithCanonicalFallback(&primary, &fallback, status);
+ ICUResourceBundleFactory rbf;
+ UObject* icurb = rbf.create(*key, NULL, status);
+ if (icurb != NULL) {
+ logln("got resource bundle for key");
+ delete icurb;
+ }
+ delete key;
+ }
+
+ #if 0
+ // ICUNotifier
+ ICUNotifier nf = new ICUNSubclass();
+ try {
+ nf.addListener(null);
+ errln("added null listener");
+ }
+ catch (NullPointerException e) {
+ logln(e.getMessage());
+ }
+ catch (Exception e) {
+ errln("got wrong exception");
+ }
+
+ try {
+ nf.addListener(new WrongListener());
+ errln("added wrong listener");
+ }
+ catch (InternalError e) {
+ logln(e.getMessage());
+ }
+ catch (Exception e) {
+ errln("got wrong exception");
+ }
+
+ try {
+ nf.removeListener(null);
+ errln("removed null listener");
+ }
+ catch (NullPointerException e) {
+ logln(e.getMessage());
+ }
+ catch (Exception e) {
+ errln("got wrong exception");
+ }
+
+ nf.removeListener(new MyListener());
+ nf.notifyChanged();
+ nf.addListener(new MyListener());
+ nf.removeListener(new MyListener());
+#endif
+}
+
+
+/* !UCONFIG_NO_SERVICE */
+#endif
+
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/icusvtst.h b/Build/source/libs/icu/icu-xetex/test/intltest/icusvtst.h
new file mode 100644
index 00000000000..21d1f6a4836
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/icusvtst.h
@@ -0,0 +1,62 @@
+/**
+ *******************************************************************************
+ * Copyright (C) 2001-2003, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ *
+ *******************************************************************************
+ */
+
+#ifndef ICUSVTST_H
+#define ICUSVTST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_SERVICE
+
+#include "intltest.h"
+
+class Integer;
+
+class ICUServiceTest : public IntlTest
+{
+ public:
+ ICUServiceTest();
+ virtual ~ICUServiceTest();
+
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL);
+
+ void testAPI_One(void);
+ void testAPI_Two(void);
+ void testRBF(void);
+ void testNotification(void);
+ void testLocale(void);
+ void testWrapFactory(void);
+ void testCoverage(void);
+
+ private:
+ UnicodeString& lrmsg(UnicodeString& result, const UnicodeString& message, const UObject* lhs, const UObject* rhs) const;
+ void confirmBoolean(const UnicodeString& message, UBool val);
+#if 0
+ void confirmEqual(const UnicodeString& message, const UObject* lhs, const UObject* rhs);
+#else
+ void confirmEqual(const UnicodeString& message, const Integer* lhs, const Integer* rhs);
+ void confirmEqual(const UnicodeString& message, const UnicodeString* lhs, const UnicodeString* rhs);
+ void confirmEqual(const UnicodeString& message, const Locale* lhs, const Locale* rhs);
+#endif
+ void confirmStringsEqual(const UnicodeString& message, const UnicodeString& lhs, const UnicodeString& rhs);
+ void confirmIdentical(const UnicodeString& message, const UObject* lhs, const UObject* rhs);
+ void confirmIdentical(const UnicodeString& message, int32_t lhs, int32_t rhs);
+
+ void msgstr(const UnicodeString& message, UObject* obj, UBool err = TRUE);
+ void logstr(const UnicodeString& message, UObject* obj) {
+ msgstr(message, obj, FALSE);
+ }
+};
+
+
+/* UCONFIG_NO_SERVICE */
+#endif
+
+/* ICUSVTST_H */
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/idnaconf.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/idnaconf.cpp
new file mode 100644
index 00000000000..cf199438467
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/idnaconf.cpp
@@ -0,0 +1,352 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2005-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ *
+ * created on: 2005jun15
+ * created by: Raymond Yang
+ */
+
+#if !UCONFIG_NO_IDNA
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "unicode/utypes.h"
+#include "unicode/ucnv.h"
+#include "unicode/ustring.h"
+#include "unicode/uidna.h"
+
+#include "idnaconf.h"
+
+static const UChar C_TAG[] = {0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0}; // =====
+static const UChar C_NAMEZONE[] = {0x6E, 0x61, 0x6D, 0x65, 0x7A, 0x6F, 0x6E, 0x65, 0}; // namezone
+static const UChar C_NAMEBASE[] = {0x6E, 0x61, 0x6D, 0x65, 0x62, 0x61, 0x73, 0x65, 0}; // namebase
+static const UChar C_NAMEUTF8[] = {0x6E, 0x61, 0x6D, 0x65, 0x75, 0x74, 0x66, 0x38, 0}; // nameutf8
+
+static const UChar C_TYPE[] = {0x74, 0x79, 0x70, 0x65, 0}; // type
+static const UChar C_TOASCII[] = {0x74, 0x6F, 0x61, 0x73, 0x63, 0x69, 0x69, 0}; // toascii
+static const UChar C_TOUNICODE[] = {0x74, 0x6F, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0}; // tounicode
+
+static const UChar C_PASSFAIL[] = {0x70, 0x61, 0x73, 0x73, 0x66, 0x61, 0x69, 0x6C, 0}; // passfail
+static const UChar C_PASS[] = {0x70, 0x61, 0x73, 0x73, 0}; // pass
+static const UChar C_FAIL[] = {0x66, 0x61, 0x69, 0x6C, 0}; // fail
+
+static const UChar C_DESC[] = {0x64, 0x65, 0x73, 0x63, 0}; // desc
+static const UChar C_USESTD3ASCIIRULES[] = {0x55, 0x73, 0x65, 0x53, 0x54, 0x44,
+ 0x33, 0x41, 0x53, 0x43, 0x49, 0x49, 0x52, 0x75, 0x6C, 0x65, 0x73, 0}; // UseSTD3ASCIIRules
+
+IdnaConfTest::IdnaConfTest(){
+ base = NULL;
+ len = 0;
+ curOffset = 0;
+
+ type = option = passfail = -1;
+ namebase.setToBogus();
+ namezone.setToBogus();
+}
+IdnaConfTest::~IdnaConfTest(){
+ delete [] base;
+}
+
+#if !UCONFIG_NO_IDNA
+/* this function is modified from RBBITest::ReadAndConvertFile()
+ *
+ */
+UBool IdnaConfTest::ReadAndConvertFile(){
+
+ char * source = NULL;
+ size_t source_len;
+
+ // read the test data file to memory
+ FILE* f = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+
+ const char *path = IntlTest::getSourceTestData(status);
+ if (U_FAILURE(status)) {
+ errln("%s", u_errorName(status));
+ return FALSE;
+ }
+
+ const char* name = "idna_conf.txt"; // test data file
+ int t = strlen(path) + strlen(name) + 1;
+ char* absolute_name = new char[t];
+ strcpy(absolute_name, path);
+ strcat(absolute_name, name);
+ f = fopen(absolute_name, "rb");
+ delete [] absolute_name;
+
+ if (f == NULL){
+ errln("fopen error on %s", name);
+ return FALSE;
+ }
+
+ fseek( f, 0, SEEK_END);
+ if ((source_len = ftell(f)) <= 0){
+ errln("Error reading test data file.");
+ fclose(f);
+ return FALSE;
+ }
+
+ source = new char[source_len];
+ fseek(f, 0, SEEK_SET);
+ if (fread(source, 1, source_len, f) != source_len) {
+ errln("Error reading test data file.");
+ delete [] source;
+ fclose(f);
+ return FALSE;
+ }
+ fclose(f);
+
+ // convert the UTF-8 encoded stream to UTF-16 stream
+ UConverter* conv = ucnv_open("utf-8", &status);
+ int dest_len = ucnv_toUChars(conv,
+ NULL, // dest,
+ 0, // destCapacity,
+ source,
+ source_len,
+ &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ // Buffer Overflow is expected from the preflight operation.
+ status = U_ZERO_ERROR;
+ UChar * dest = NULL;
+ dest = new UChar[ dest_len + 1];
+ ucnv_toUChars(conv, dest, dest_len + 1, source, source_len, &status);
+ // Do not know the "if possible" behavior of ucnv_toUChars()
+ // Do it by ourself.
+ dest[dest_len] = 0;
+ len = dest_len;
+ base = dest;
+ delete [] source;
+ ucnv_close(conv);
+ return TRUE; // The buffer will owned by caller.
+ }
+ errln("UConverter error: %s", u_errorName(status));
+ delete [] source;
+ ucnv_close(conv);
+ return FALSE;
+}
+
+int IdnaConfTest::isNewlineMark(){
+ static const UChar LF = 0x0a;
+ static const UChar CR = 0x0d;
+ UChar c = base[curOffset];
+ // CR LF
+ if ( c == CR && curOffset + 1 < len && base[curOffset + 1] == LF){
+ return 2;
+ }
+
+ // CR or LF
+ if ( c == CR || c == LF) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Read a logical line.
+ *
+ * All lines ending in a backslash (\) and immediately followed by a newline
+ * character are joined with the next line in the source file forming logical
+ * lines from the physical lines.
+ *
+ */
+UBool IdnaConfTest::ReadOneLine(UnicodeString& buf){
+ if ( !(curOffset < len) ) return FALSE; // stream end
+
+ static const UChar BACKSLASH = 0x5c;
+ buf.remove();
+ int t = 0;
+ while (curOffset < len){
+ if ((t = isNewlineMark())) { // end of line
+ curOffset += t;
+ break;
+ }
+ UChar c = base[curOffset];
+ if (c == BACKSLASH && curOffset < len -1){ // escaped new line mark
+ if ((t = isNewlineMark())){
+ curOffset += 1 + t; // BACKSLAH and NewlineMark
+ continue;
+ }
+ };
+ buf.append(c);
+ curOffset++;
+ }
+ return TRUE;
+}
+
+//
+//===============================================================
+//
+
+/* Explain <xxxxx> tag to a native value
+ *
+ * Since <xxxxx> is always larger than the native value,
+ * the operation will replace the tag directly in the buffer,
+ * and, of course, will shift tail elements.
+ */
+void IdnaConfTest::ExplainCodePointTag(UnicodeString& buf){
+ buf.append((UChar)0); // add a terminal NULL
+ UChar* bufBase = buf.getBuffer(buf.length());
+ UChar* p = bufBase;
+ while (*p != 0){
+ if ( *p != 0x3C){ // <
+ *bufBase++ = *p++;
+ } else {
+ p++; // skip <
+ UChar32 cp = 0;
+ for ( ;*p != 0x3E; p++){ // >
+ if (0x30 <= *p && *p <= 0x39){ // 0-9
+ cp = (cp * 16) + (*p - 0x30);
+ } else if (0x61 <= *p && *p <= 0x66){ // a-f
+ cp = (cp * 16) + (*p - 0x61) + 10;
+ } else if (0x41 <= *p && *p <= 0x46) {// A-F
+ cp = (cp * 16) + (*p - 0x41) + 10;
+ }
+ // no else. hope everything is good.
+ }
+ p++; // skip >
+ if (U_IS_BMP(cp)){
+ *bufBase++ = cp;
+ } else {
+ *bufBase++ = U16_LEAD(cp);
+ *bufBase++ = U16_TRAIL(cp);
+ }
+ }
+ }
+ *bufBase = 0; // close our buffer
+ buf.releaseBuffer();
+}
+
+void IdnaConfTest::Call(){
+ if (type == -1 || option == -1 || passfail == -1 || namebase.isBogus() || namezone.isBogus()){
+ errln("Incomplete record");
+ } else {
+ UErrorCode status = U_ZERO_ERROR;
+ UChar result[200] = {0,}; // simple life
+ const UChar *p = namebase.getTerminatedBuffer();
+ const int p_len = namebase.length();
+
+ if (type == 0 && option == 0){
+ uidna_IDNToASCII(p, p_len, result, 200, UIDNA_USE_STD3_RULES, NULL, &status);
+ } else if (type == 0 && option == 1){
+ uidna_IDNToASCII(p, p_len, result, 200, UIDNA_ALLOW_UNASSIGNED, NULL, &status);
+ } else if (type == 1 && option == 0){
+ uidna_IDNToUnicode(p, p_len, result, 200, UIDNA_USE_STD3_RULES, NULL, &status);
+ } else if (type == 1 && option == 1){
+ uidna_IDNToUnicode(p, p_len, result, 200, UIDNA_ALLOW_UNASSIGNED, NULL, &status);
+ }
+ if (passfail == 0){
+ if (U_FAILURE(status)){
+ id.append(" should pass, but failed.");
+ errln(id);
+ } else{
+ if (namezone.compare(result, -1) == 0){
+ // expected
+ logln(UnicodeString("namebase: ") + prettify(namebase) + UnicodeString(" result: ") + prettify(result));
+ } else {
+ id.append(" no error, but result is not as expected.");
+ errln(id);
+ }
+ }
+ } else if (passfail == 1){
+ if (U_FAILURE(status)){
+ // expected
+ // TODO: Uncomment this when U_IDNA_ZERO_LENGTH_LABEL_ERROR is added to u_errorName
+ //logln("Got the expected error: " + UnicodeString(u_errorName(status)));
+ } else{
+ if (namebase.compare(result, -1) == 0){
+ // garbage in -> garbage out
+ logln(UnicodeString("ICU will not recognize malformed ACE-Prefixes or incorrect ACE-Prefixes. ") + UnicodeString("namebase: ") + prettify(namebase) + UnicodeString(" result: ") + prettify(result));
+ } else {
+ id.append(" should fail, but not failed. ");
+ id.append(u_errorName(status));
+ errln(id);
+ }
+ }
+ }
+ }
+ type = option = passfail = -1;
+ namebase.setToBogus();
+ namezone.setToBogus();
+ id.remove();
+ return;
+}
+
+void IdnaConfTest::Test(void){
+ if (!ReadAndConvertFile())return;
+
+ UnicodeString s;
+ UnicodeString key;
+ UnicodeString value;
+
+ // skip everything before the first "=====" and "=====" itself
+ do {
+ if (!ReadOneLine(s)) {
+ errln("End of file prematurely found");
+ break;
+ }
+ }
+ while (s.compare(C_TAG, -1) != 0); //"====="
+
+ while(ReadOneLine(s)){
+ s.trim();
+ key.remove();
+ value.remove();
+ if (s.compare(C_TAG, -1) == 0){ //"====="
+ Call();
+ } else {
+ // explain key:value
+ int p = s.indexOf((UChar)0x3A); // :
+ key.setTo(s,0,p).trim();
+ value.setTo(s,p+1).trim();
+ if (key.compare(C_TYPE, -1) == 0){
+ if (value.compare(C_TOASCII, -1) == 0) {
+ type = 0;
+ } else if (value.compare(C_TOUNICODE, -1) == 0){
+ type = 1;
+ }
+ } else if (key.compare(C_PASSFAIL, -1) == 0){
+ if (value.compare(C_PASS, -1) == 0){
+ passfail = 0;
+ } else if (value.compare(C_FAIL, -1) == 0){
+ passfail = 1;
+ }
+ } else if (key.compare(C_DESC, -1) == 0){
+ if (value.indexOf(C_USESTD3ASCIIRULES, u_strlen(C_USESTD3ASCIIRULES), 0) == -1){
+ option = 1; // not found
+ } else {
+ option = 0;
+ }
+ id.setTo(value, 0, value.indexOf((UChar)0x20)); // space
+ } else if (key.compare(C_NAMEZONE, -1) == 0){
+ ExplainCodePointTag(value);
+ namezone.setTo(value);
+ } else if (key.compare(C_NAMEBASE, -1) == 0){
+ ExplainCodePointTag(value);
+ namebase.setTo(value);
+ }
+ // just skip other lines
+ }
+ }
+
+ Call(); // for last record
+}
+#else
+void IdnaConfTest::Test(void)
+{
+ // test nothing...
+}
+#endif
+
+void IdnaConfTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/){
+ switch (index) {
+ TESTCASE(0,Test);
+ default: name = ""; break;
+ }
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/idnaconf.h b/Build/source/libs/icu/icu-xetex/test/intltest/idnaconf.h
new file mode 100644
index 00000000000..35e9063ab87
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/idnaconf.h
@@ -0,0 +1,49 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2005, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ *
+ * created on: 2005jun15
+ * created by: Raymond Yang
+ */
+
+#ifndef IDNA_CONF_TEST_H
+#define IDNA_CONF_TEST_H
+
+#include "intltest.h"
+#include "unicode/ustring.h"
+
+
+class IdnaConfTest: public IntlTest {
+public:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par=NULL);
+ IdnaConfTest();
+ virtual ~IdnaConfTest();
+private:
+ void Test(void);
+
+ // for test file handling
+ UChar* base;
+ int len ;
+ int curOffset;
+
+ UBool ReadAndConvertFile();
+ int isNewlineMark();
+ UBool ReadOneLine(UnicodeString&);
+
+ // for parsing one test record
+ UnicodeString id; // for debug & error output
+ UnicodeString namebase;
+ UnicodeString namezone;
+ int type; // 0 toascii, 1 tounicode
+ int option; // 0 UseSTD3ASCIIRules, 1 ALLOW_UNASSIGNED
+ int passfail; // 0 pass, 1 fail
+
+ void ExplainCodePointTag(UnicodeString& buf);
+ void Call();
+};
+
+#endif /*IDNA_CONF_TEST_H*/
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/idnaref.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/idnaref.cpp
new file mode 100644
index 00000000000..eabe1f56d3a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/idnaref.cpp
@@ -0,0 +1,1048 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2003-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: idnaref.cpp
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2003feb1
+ * created by: Ram Viswanadha
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA && !UCONFIG_NO_TRANSLITERATION
+#include "idnaref.h"
+#include "punyref.h"
+#include "ustr_imp.h"
+#include "cmemory.h"
+#include "sprpimpl.h"
+#include "nptrans.h"
+#include "testidna.h"
+#include "punycode.h"
+#include "unicode/ustring.h"
+
+/* it is official IDNA ACE Prefix is "xn--" */
+static const UChar ACE_PREFIX[] ={ 0x0078,0x006E,0x002d,0x002d } ;
+#define ACE_PREFIX_LENGTH 4
+
+#define MAX_LABEL_LENGTH 63
+#define HYPHEN 0x002D
+/* The Max length of the labels should not be more than 64 */
+#define MAX_LABEL_BUFFER_SIZE 100
+#define MAX_IDN_BUFFER_SIZE 300
+
+#define CAPITAL_A 0x0041
+#define CAPITAL_Z 0x005A
+#define LOWER_CASE_DELTA 0x0020
+#define FULL_STOP 0x002E
+
+
+inline static UBool
+startsWithPrefix(const UChar* src , int32_t srcLength){
+ UBool startsWithPrefix = TRUE;
+
+ if(srcLength < ACE_PREFIX_LENGTH){
+ return FALSE;
+ }
+
+ for(int8_t i=0; i< ACE_PREFIX_LENGTH; i++){
+ if(u_tolower(src[i]) != ACE_PREFIX[i]){
+ startsWithPrefix = FALSE;
+ }
+ }
+ return startsWithPrefix;
+}
+
+inline static UChar
+toASCIILower(UChar ch){
+ if(CAPITAL_A <= ch && ch <= CAPITAL_Z){
+ return ch + LOWER_CASE_DELTA;
+ }
+ return ch;
+}
+
+inline static int32_t
+compareCaseInsensitiveASCII(const UChar* s1, int32_t s1Len,
+ const UChar* s2, int32_t s2Len){
+ if(s1Len != s2Len){
+ return (s1Len > s2Len) ? s1Len : s2Len;
+ }
+ UChar c1,c2;
+ int32_t rc;
+
+ for(int32_t i =0;/* no condition */;i++) {
+ /* If we reach the ends of both strings then they match */
+ if(i == s1Len) {
+ return 0;
+ }
+
+ c1 = s1[i];
+ c2 = s2[i];
+
+ /* Case-insensitive comparison */
+ if(c1!=c2) {
+ rc=(int32_t)toASCIILower(c1)-(int32_t)toASCIILower(c2);
+ if(rc!=0) {
+ return rc;
+ }
+ }
+ }
+
+}
+
+static UErrorCode getError(enum punycode_status status){
+ switch(status){
+ case punycode_success:
+ return U_ZERO_ERROR;
+ case punycode_bad_input: /* Input is invalid. */
+ return U_INVALID_CHAR_FOUND;
+ case punycode_big_output: /* Output would exceed the space provided. */
+ return U_BUFFER_OVERFLOW_ERROR;
+ case punycode_overflow : /* Input requires wider integers to process. */
+ return U_INDEX_OUTOFBOUNDS_ERROR;
+ default:
+ return U_INTERNAL_PROGRAM_ERROR;
+ }
+}
+
+static inline int32_t convertASCIIToUChars(const char* src,UChar* dest, int32_t length){
+ int i;
+ for(i=0;i<length;i++){
+ dest[i] = src[i];
+ }
+ return i;
+}
+static inline int32_t convertUCharsToASCII(const UChar* src,char* dest, int32_t length){
+ int i;
+ for(i=0;i<length;i++){
+ dest[i] = (char)src[i];
+ }
+ return i;
+}
+// wrapper around the reference Punycode implementation
+static int32_t convertToPuny(const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ UErrorCode& status){
+ uint32_t b1Stack[MAX_LABEL_BUFFER_SIZE];
+ int32_t b1Len = 0, b1Capacity = MAX_LABEL_BUFFER_SIZE;
+ uint32_t* b1 = b1Stack;
+ char b2Stack[MAX_LABEL_BUFFER_SIZE];
+ char* b2 = b2Stack;
+ int32_t b2Len =MAX_LABEL_BUFFER_SIZE ;
+ punycode_status error;
+ unsigned char* caseFlags = NULL;
+
+ u_strToUTF32((UChar32*)b1,b1Capacity,&b1Len,src,srcLength,&status);
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b1 = (uint32_t*) uprv_malloc(b1Len * sizeof(uint32_t));
+ if(b1==NULL){
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ status = U_ZERO_ERROR; // reset error
+
+ u_strToUTF32((UChar32*)b1,b1Len,&b1Len,src,srcLength,&status);
+ }
+ if(U_FAILURE(status)){
+ goto CLEANUP;
+ }
+
+ //caseFlags = (unsigned char*) uprv_malloc(b1Len *sizeof(unsigned char));
+
+ error = punycode_encode(b1Len,b1,caseFlags, (uint32_t*)&b2Len, b2);
+ status = getError(error);
+
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ /* we do not have enough room so grow the buffer*/
+ b2 = (char*) uprv_malloc( b2Len * sizeof(char));
+ if(b2==NULL){
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ status = U_ZERO_ERROR; // reset error
+
+ punycode_status error = punycode_encode(b1Len,b1,caseFlags, (uint32_t*)&b2Len, b2);
+ status = getError(error);
+ }
+ if(U_FAILURE(status)){
+ goto CLEANUP;
+ }
+
+ if(b2Len < destCapacity){
+ convertASCIIToUChars(b2,dest,b2Len);
+ }else{
+ status =U_BUFFER_OVERFLOW_ERROR;
+ }
+
+CLEANUP:
+ if(b1Stack != b1){
+ uprv_free(b1);
+ }
+ if(b2Stack != b2){
+ uprv_free(b2);
+ }
+ uprv_free(caseFlags);
+
+ return b2Len;
+}
+
+static int32_t convertFromPuny( const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ UErrorCode& status){
+ char b1Stack[MAX_LABEL_BUFFER_SIZE];
+ char* b1 = b1Stack;
+ int32_t destLen =0;
+
+ convertUCharsToASCII(src, b1,srcLength);
+
+ uint32_t b2Stack[MAX_LABEL_BUFFER_SIZE];
+ uint32_t* b2 = b2Stack;
+ int32_t b2Len =MAX_LABEL_BUFFER_SIZE;
+ unsigned char* caseFlags = NULL; //(unsigned char*) uprv_malloc(srcLength * sizeof(unsigned char*));
+ punycode_status error = punycode_decode(srcLength,b1,(uint32_t*)&b2Len,b2,caseFlags);
+ status = getError(error);
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ b2 = (uint32_t*) uprv_malloc(b2Len * sizeof(uint32_t));
+ if(b2 == NULL){
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+ error = punycode_decode(srcLength,b1,(uint32_t*)&b2Len,b2,caseFlags);
+ status = getError(error);
+ }
+
+ if(U_FAILURE(status)){
+ goto CLEANUP;
+ }
+
+ u_strFromUTF32(dest,destCapacity,&destLen,(UChar32*)b2,b2Len,&status);
+
+CLEANUP:
+ if(b1Stack != b1){
+ uprv_free(b1);
+ }
+ if(b2Stack != b2){
+ uprv_free(b2);
+ }
+ uprv_free(caseFlags);
+
+ return destLen;
+}
+
+
+U_CFUNC int32_t U_EXPORT2
+idnaref_toASCII(const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ int32_t options,
+ UParseError* parseError,
+ UErrorCode* status){
+
+ if(status == NULL || U_FAILURE(*status)){
+ return 0;
+ }
+ if((src == NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UChar b1Stack[MAX_LABEL_BUFFER_SIZE], b2Stack[MAX_LABEL_BUFFER_SIZE];
+ //initialize pointers to stack buffers
+ UChar *b1 = b1Stack, *b2 = b2Stack;
+ int32_t b1Len=0, b2Len=0,
+ b1Capacity = MAX_LABEL_BUFFER_SIZE,
+ b2Capacity = MAX_LABEL_BUFFER_SIZE ,
+ reqLength=0;
+
+ //get the options
+ UBool allowUnassigned = (UBool)((options & IDNAREF_ALLOW_UNASSIGNED) != 0);
+ UBool useSTD3ASCIIRules = (UBool)((options & IDNAREF_USE_STD3_RULES) != 0);
+
+ UBool* caseFlags = NULL;
+
+ // assume the source contains all ascii codepoints
+ UBool srcIsASCII = TRUE;
+ // assume the source contains all LDH codepoints
+ UBool srcIsLDH = TRUE;
+ int32_t j=0;
+
+ if(srcLength == -1){
+ srcLength = u_strlen(src);
+ }
+
+ // step 1
+ for( j=0;j<srcLength;j++){
+ if(src[j] > 0x7F){
+ srcIsASCII = FALSE;
+ }
+ b1[b1Len++] = src[j];
+ }
+ // step 2
+ NamePrepTransform* prep = TestIDNA::getInstance(*status);
+
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+
+ b1Len = prep->process(src,srcLength,b1, b1Capacity,allowUnassigned,parseError,*status);
+
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+ if(b1==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b1Len = prep->process(src,srcLength,b1, b1Len,allowUnassigned, parseError, *status);
+ }
+ // error bail out
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+
+ if(b1Len == 0){
+ *status = U_IDNA_ZERO_LENGTH_LABEL_ERROR;
+ goto CLEANUP;
+ }
+
+ srcIsASCII = TRUE;
+ // step 3 & 4
+ for( j=0;j<b1Len;j++){
+ if(b1[j] > 0x7F){// check if output of usprep_prepare is all ASCII
+ srcIsASCII = FALSE;
+ }else if(prep->isLDHChar(b1[j])==FALSE){ // if the char is in ASCII range verify that it is an LDH character{
+ srcIsLDH = FALSE;
+ }
+ }
+
+ if(useSTD3ASCIIRules == TRUE){
+ // verify 3a and 3b
+ if( srcIsLDH == FALSE /* source contains some non-LDH characters */
+ || b1[0] == HYPHEN || b1[b1Len-1] == HYPHEN){
+ *status = U_IDNA_STD3_ASCII_RULES_ERROR;
+ goto CLEANUP;
+ }
+ }
+ if(srcIsASCII){
+ if(b1Len <= destCapacity){
+ uprv_memmove(dest, b1, b1Len * U_SIZEOF_UCHAR);
+ reqLength = b1Len;
+ }else{
+ reqLength = b1Len;
+ goto CLEANUP;
+ }
+ }else{
+ // step 5 : verify the sequence does not begin with ACE prefix
+ if(!startsWithPrefix(b1,b1Len)){
+
+ //step 6: encode the sequence with punycode
+ //caseFlags = (UBool*) uprv_malloc(b1Len * sizeof(UBool));
+
+ b2Len = convertToPuny(b1,b1Len, b2,b2Capacity,*status);
+ //b2Len = u_strToPunycode(b2,b2Capacity,b1,b1Len, caseFlags, status);
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
+ if(b2 == NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b2Len = convertToPuny(b1, b1Len, b2, b2Len, *status);
+ //b2Len = u_strToPunycode(b2,b2Len,b1,b1Len, caseFlags, status);
+
+ }
+ //error bail out
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+ reqLength = b2Len+ACE_PREFIX_LENGTH;
+
+ if(reqLength > destCapacity){
+ *status = U_BUFFER_OVERFLOW_ERROR;
+ goto CLEANUP;
+ }
+ //Step 7: prepend the ACE prefix
+ uprv_memcpy(dest,ACE_PREFIX,ACE_PREFIX_LENGTH * U_SIZEOF_UCHAR);
+ //Step 6: copy the contents in b2 into dest
+ uprv_memcpy(dest+ACE_PREFIX_LENGTH, b2, b2Len * U_SIZEOF_UCHAR);
+
+ }else{
+ *status = U_IDNA_ACE_PREFIX_ERROR;
+ goto CLEANUP;
+ }
+ }
+
+ if(reqLength > MAX_LABEL_LENGTH){
+ *status = U_IDNA_LABEL_TOO_LONG_ERROR;
+ }
+
+CLEANUP:
+ if(b1 != b1Stack){
+ uprv_free(b1);
+ }
+ if(b2 != b2Stack){
+ uprv_free(b2);
+ }
+ uprv_free(caseFlags);
+
+// delete prep;
+
+ return u_terminateUChars(dest, destCapacity, reqLength, status);
+}
+
+
+U_CFUNC int32_t U_EXPORT2
+idnaref_toUnicode(const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ int32_t options,
+ UParseError* parseError,
+ UErrorCode* status){
+
+ if(status == NULL || U_FAILURE(*status)){
+ return 0;
+ }
+ if((src == NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+
+
+ UChar b1Stack[MAX_LABEL_BUFFER_SIZE], b2Stack[MAX_LABEL_BUFFER_SIZE], b3Stack[MAX_LABEL_BUFFER_SIZE];
+
+ //initialize pointers to stack buffers
+ UChar *b1 = b1Stack, *b2 = b2Stack, *b1Prime=NULL, *b3=b3Stack;
+ int32_t b1Len, b2Len, b1PrimeLen, b3Len,
+ b1Capacity = MAX_LABEL_BUFFER_SIZE,
+ b2Capacity = MAX_LABEL_BUFFER_SIZE,
+ b3Capacity = MAX_LABEL_BUFFER_SIZE,
+ reqLength=0;
+// UParseError parseError;
+
+ NamePrepTransform* prep = TestIDNA::getInstance(*status);
+ b1Len = 0;
+ UBool* caseFlags = NULL;
+
+ //get the options
+ UBool allowUnassigned = (UBool)((options & IDNAREF_ALLOW_UNASSIGNED) != 0);
+ UBool useSTD3ASCIIRules = (UBool)((options & IDNAREF_USE_STD3_RULES) != 0);
+
+ UBool srcIsASCII = TRUE;
+ UBool srcIsLDH = TRUE;
+ int32_t failPos =0;
+
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+ // step 1: find out if all the codepoints in src are ASCII
+ if(srcLength==-1){
+ srcLength = 0;
+ for(;src[srcLength]!=0;){
+ if(src[srcLength]> 0x7f){
+ srcIsASCII = FALSE;
+ }if(prep->isLDHChar(src[srcLength])==FALSE){
+ // here we do not assemble surrogates
+ // since we know that LDH code points
+ // are in the ASCII range only
+ srcIsLDH = FALSE;
+ failPos = srcLength;
+ }
+ srcLength++;
+ }
+ }else{
+ for(int32_t j=0; j<srcLength; j++){
+ if(src[j]> 0x7f){
+ srcIsASCII = FALSE;
+ }else if(prep->isLDHChar(src[j])==FALSE){
+ // here we do not assemble surrogates
+ // since we know that LDH code points
+ // are in the ASCII range only
+ srcIsLDH = FALSE;
+ failPos = j;
+ }
+ }
+ }
+
+ if(srcIsASCII == FALSE){
+ // step 2: process the string
+ b1Len = prep->process(src,srcLength,b1,b1Capacity,allowUnassigned, parseError, *status);
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+ if(b1==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b1Len = prep->process(src,srcLength,b1, b1Len,allowUnassigned, parseError, *status);
+ }
+ //bail out on error
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+ }else{
+
+ // copy everything to b1
+ if(srcLength < b1Capacity){
+ uprv_memmove(b1,src, srcLength * U_SIZEOF_UCHAR);
+ }else{
+ /* we do not have enough room so grow the buffer*/
+ b1 = (UChar*) uprv_malloc(srcLength * U_SIZEOF_UCHAR);
+ if(b1==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+ uprv_memmove(b1,src, srcLength * U_SIZEOF_UCHAR);
+ }
+ b1Len = srcLength;
+ }
+ //step 3: verify ACE Prefix
+ if(startsWithPrefix(src,srcLength)){
+
+ //step 4: Remove the ACE Prefix
+ b1Prime = b1 + ACE_PREFIX_LENGTH;
+ b1PrimeLen = b1Len - ACE_PREFIX_LENGTH;
+
+ //step 5: Decode using punycode
+ b2Len = convertFromPuny(b1Prime,b1PrimeLen, b2, b2Capacity, *status);
+ //b2Len = u_strFromPunycode(b2, b2Capacity,b1Prime,b1PrimeLen, caseFlags, status);
+
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
+ if(b2==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b2Len = convertFromPuny(b1Prime,b1PrimeLen, b2, b2Len, *status);
+ //b2Len = u_strFromPunycode(b2, b2Len,b1Prime,b1PrimeLen,caseFlags, status);
+ }
+
+
+ //step 6:Apply toASCII
+ b3Len = idnaref_toASCII(b2,b2Len,b3,b3Capacity,options,parseError, status);
+
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b3 = (UChar*) uprv_malloc(b3Len * U_SIZEOF_UCHAR);
+ if(b3==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b3Len = idnaref_toASCII(b2,b2Len,b3,b3Len, options, parseError, status);
+
+ }
+ //bail out on error
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+
+ //step 7: verify
+ if(compareCaseInsensitiveASCII(b1, b1Len, b3, b3Len) !=0){
+ *status = U_IDNA_VERIFICATION_ERROR;
+ goto CLEANUP;
+ }
+
+ //step 8: return output of step 5
+ reqLength = b2Len;
+ if(b2Len <= destCapacity) {
+ uprv_memmove(dest, b2, b2Len * U_SIZEOF_UCHAR);
+ }
+ }else{
+ // verify that STD3 ASCII rules are satisfied
+ if(useSTD3ASCIIRules == TRUE){
+ if( srcIsLDH == FALSE /* source contains some non-LDH characters */
+ || src[0] == HYPHEN || src[srcLength-1] == HYPHEN){
+ *status = U_IDNA_STD3_ASCII_RULES_ERROR;
+
+ /* populate the parseError struct */
+ if(srcIsLDH==FALSE){
+ // failPos is always set the index of failure
+ uprv_syntaxError(src,failPos, srcLength,parseError);
+ }else if(src[0] == HYPHEN){
+ // fail position is 0
+ uprv_syntaxError(src,0,srcLength,parseError);
+ }else{
+ // the last index in the source is always length-1
+ uprv_syntaxError(src, (srcLength>0) ? srcLength-1 : srcLength, srcLength,parseError);
+ }
+
+ goto CLEANUP;
+ }
+ }
+ //copy the source to destination
+ if(srcLength <= destCapacity){
+ uprv_memmove(dest,src,srcLength * U_SIZEOF_UCHAR);
+ }
+ reqLength = srcLength;
+ }
+
+CLEANUP:
+
+ if(b1 != b1Stack){
+ uprv_free(b1);
+ }
+ if(b2 != b2Stack){
+ uprv_free(b2);
+ }
+ uprv_free(caseFlags);
+
+ // The RFC states that
+ // <quote>
+ // ToUnicode never fails. If any step fails, then the original input
+ // is returned immediately in that step.
+ // </quote>
+ // So if any step fails lets copy source to destination
+ if(U_FAILURE(*status)){
+ //copy the source to destination
+ if(dest && srcLength <= destCapacity){
+ if(srcLength == -1) {
+ uprv_memmove(dest,src,u_strlen(src)* U_SIZEOF_UCHAR);
+ } else {
+ uprv_memmove(dest,src,srcLength * U_SIZEOF_UCHAR);
+ }
+ }
+ reqLength = srcLength;
+ *status = U_ZERO_ERROR;
+ }
+ return u_terminateUChars(dest, destCapacity, reqLength, status);
+}
+
+
+static int32_t
+getNextSeparator(UChar *src,int32_t srcLength,NamePrepTransform* prep,
+ UChar **limit,
+ UBool *done,
+ UErrorCode *status){
+ if(srcLength == -1){
+ int32_t i;
+ for(i=0 ; ;i++){
+ if(src[i] == 0){
+ *limit = src + i; // point to null
+ *done = TRUE;
+ return i;
+ }
+ if(prep->isLabelSeparator(src[i],*status)){
+ *limit = src + (i+1); // go past the delimiter
+ return i;
+
+ }
+ }
+ }else{
+ int32_t i;
+ for(i=0;i<srcLength;i++){
+ if(prep->isLabelSeparator(src[i],*status)){
+ *limit = src + (i+1); // go past the delimiter
+ return i;
+ }
+ }
+ // we have not found the delimiter
+ if(i==srcLength){
+ *limit = src+srcLength;
+ *done = TRUE;
+ }
+ return i;
+ }
+}
+
+U_CFUNC int32_t U_EXPORT2
+idnaref_IDNToASCII( const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ int32_t options,
+ UParseError* parseError,
+ UErrorCode* status){
+
+ if(status == NULL || U_FAILURE(*status)){
+ return 0;
+ }
+ if((src == NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ int32_t reqLength = 0;
+// UParseError parseError;
+
+ NamePrepTransform* prep = TestIDNA::getInstance(*status);
+
+ //initialize pointers to stack buffers
+ UChar b1Stack[MAX_LABEL_BUFFER_SIZE];
+ UChar *b1 = b1Stack;
+ int32_t b1Len, labelLen;
+ UChar* delimiter = (UChar*)src;
+ UChar* labelStart = (UChar*)src;
+ int32_t remainingLen = srcLength;
+ int32_t b1Capacity = MAX_LABEL_BUFFER_SIZE;
+
+ //get the options
+// UBool allowUnassigned = (UBool)((options & IDNAREF_ALLOW_UNASSIGNED) != 0);
+// UBool useSTD3ASCIIRules = (UBool)((options & IDNAREF_USE_STD3_RULES) != 0);
+ UBool done = FALSE;
+
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+
+
+ if(srcLength == -1){
+ for(;;){
+
+ if(*delimiter == 0){
+ break;
+ }
+
+ labelLen = getNextSeparator(labelStart, -1, prep, &delimiter, &done, status);
+ b1Len = 0;
+ if(!(labelLen==0 && done)){// make sure this is not a root label separator.
+
+ b1Len = idnaref_toASCII(labelStart, labelLen, b1, b1Capacity,
+ options, parseError, status);
+
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+ if(b1==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b1Len = idnaref_toASCII(labelStart, labelLen, b1, b1Len,
+ options, parseError, status);
+
+ }
+ }
+
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+ int32_t tempLen = (reqLength + b1Len );
+ // copy to dest
+ if( tempLen< destCapacity){
+ uprv_memmove(dest+reqLength, b1, b1Len * U_SIZEOF_UCHAR);
+ }
+
+ reqLength = tempLen;
+
+ // add the label separator
+ if(done == FALSE){
+ if(reqLength < destCapacity){
+ dest[reqLength] = FULL_STOP;
+ }
+ reqLength++;
+ }
+
+ labelStart = delimiter;
+ }
+ }else{
+ for(;;){
+
+ if(delimiter == src+srcLength){
+ break;
+ }
+
+ labelLen = getNextSeparator(labelStart, remainingLen, prep, &delimiter, &done, status);
+
+ b1Len = idnaref_toASCII(labelStart, labelLen, b1, b1Capacity,
+ options,parseError, status);
+
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+ if(b1==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b1Len = idnaref_toASCII(labelStart, labelLen, b1, b1Len,
+ options, parseError, status);
+
+ }
+
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+ int32_t tempLen = (reqLength + b1Len );
+ // copy to dest
+ if( tempLen< destCapacity){
+ uprv_memmove(dest+reqLength, b1, b1Len * U_SIZEOF_UCHAR);
+ }
+
+ reqLength = tempLen;
+
+ // add the label separator
+ if(done == FALSE){
+ if(reqLength < destCapacity){
+ dest[reqLength] = FULL_STOP;
+ }
+ reqLength++;
+ }
+
+ labelStart = delimiter;
+ remainingLen = srcLength - (delimiter - src);
+ }
+ }
+
+
+CLEANUP:
+
+ if(b1 != b1Stack){
+ uprv_free(b1);
+ }
+
+// delete prep;
+
+ return u_terminateUChars(dest, destCapacity, reqLength, status);
+}
+
+U_CFUNC int32_t U_EXPORT2
+idnaref_IDNToUnicode( const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ int32_t options,
+ UParseError* parseError,
+ UErrorCode* status){
+
+ if(status == NULL || U_FAILURE(*status)){
+ return 0;
+ }
+ if((src == NULL) || (srcLength < -1) || (destCapacity<0) || (!dest && destCapacity > 0)){
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ int32_t reqLength = 0;
+
+ UBool done = FALSE;
+
+ NamePrepTransform* prep = TestIDNA::getInstance(*status);
+
+ //initialize pointers to stack buffers
+ UChar b1Stack[MAX_LABEL_BUFFER_SIZE];
+ UChar *b1 = b1Stack;
+ int32_t b1Len, labelLen;
+ UChar* delimiter = (UChar*)src;
+ UChar* labelStart = (UChar*)src;
+ int32_t remainingLen = srcLength;
+ int32_t b1Capacity = MAX_LABEL_BUFFER_SIZE;
+
+ //get the options
+// UBool allowUnassigned = (UBool)((options & IDNAREF_ALLOW_UNASSIGNED) != 0);
+// UBool useSTD3ASCIIRules = (UBool)((options & IDNAREF_USE_STD3_RULES) != 0);
+
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+
+ if(srcLength == -1){
+ for(;;){
+
+ if(*delimiter == 0){
+ break;
+ }
+
+ labelLen = getNextSeparator(labelStart, -1, prep, &delimiter, &done, status);
+
+ if(labelLen==0 && done==FALSE){
+ *status = U_IDNA_ZERO_LENGTH_LABEL_ERROR;
+ }
+ b1Len = idnaref_toUnicode(labelStart, labelLen, b1, b1Capacity,
+ options, parseError, status);
+
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+ if(b1==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b1Len = idnaref_toUnicode( labelStart, labelLen, b1, b1Len,
+ options, parseError, status);
+
+ }
+
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+ int32_t tempLen = (reqLength + b1Len );
+ // copy to dest
+ if( tempLen< destCapacity){
+ uprv_memmove(dest+reqLength, b1, b1Len * U_SIZEOF_UCHAR);
+ }
+
+ reqLength = tempLen;
+ // add the label separator
+ if(done == FALSE){
+ if(reqLength < destCapacity){
+ dest[reqLength] = FULL_STOP;
+ }
+ reqLength++;
+ }
+
+ labelStart = delimiter;
+ }
+ }else{
+ for(;;){
+
+ if(delimiter == src+srcLength){
+ break;
+ }
+
+ labelLen = getNextSeparator(labelStart, remainingLen, prep, &delimiter, &done, status);
+
+ if(labelLen==0 && done==FALSE){
+ *status = U_IDNA_ZERO_LENGTH_LABEL_ERROR;
+ }
+
+ b1Len = idnaref_toUnicode( labelStart,labelLen, b1, b1Capacity,
+ options, parseError, status);
+
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+ if(b1==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b1Len = idnaref_toUnicode( labelStart, labelLen, b1, b1Len,
+ options, parseError, status);
+
+ }
+
+ if(U_FAILURE(*status)){
+ goto CLEANUP;
+ }
+ int32_t tempLen = (reqLength + b1Len );
+ // copy to dest
+ if( tempLen< destCapacity){
+ uprv_memmove(dest+reqLength, b1, b1Len * U_SIZEOF_UCHAR);
+ }
+
+ reqLength = tempLen;
+
+ // add the label separator
+ if(done == FALSE){
+ if(reqLength < destCapacity){
+ dest[reqLength] = FULL_STOP;
+ }
+ reqLength++;
+ }
+
+ labelStart = delimiter;
+ remainingLen = srcLength - (delimiter - src);
+ }
+ }
+
+CLEANUP:
+
+ if(b1 != b1Stack){
+ uprv_free(b1);
+ }
+
+// delete prep;
+
+ return u_terminateUChars(dest, destCapacity, reqLength, status);
+}
+
+U_CFUNC int32_t U_EXPORT2
+idnaref_compare( const UChar *s1, int32_t length1,
+ const UChar *s2, int32_t length2,
+ int32_t options,
+ UErrorCode* status){
+
+ if(status == NULL || U_FAILURE(*status)){
+ return -1;
+ }
+
+ UChar b1Stack[MAX_IDN_BUFFER_SIZE], b2Stack[MAX_IDN_BUFFER_SIZE];
+ UChar *b1 = b1Stack, *b2 = b2Stack;
+ int32_t b1Len, b2Len, b1Capacity = MAX_IDN_BUFFER_SIZE, b2Capacity = MAX_IDN_BUFFER_SIZE;
+ int32_t result = -1;
+
+ UParseError parseError;
+
+ b1Len = idnaref_IDNToASCII(s1, length1, b1, b1Capacity, options, &parseError, status);
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b1 = (UChar*) uprv_malloc(b1Len * U_SIZEOF_UCHAR);
+ if(b1==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b1Len = idnaref_IDNToASCII(s1,length1,b1,b1Len, options, &parseError, status);
+
+ }
+
+ b2Len = idnaref_IDNToASCII(s2,length2,b2,b2Capacity,options, &parseError, status);
+ if(*status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ b2 = (UChar*) uprv_malloc(b2Len * U_SIZEOF_UCHAR);
+ if(b2==NULL){
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ *status = U_ZERO_ERROR; // reset error
+
+ b2Len = idnaref_IDNToASCII(s2,length2,b2,b2Len,options, &parseError, status);
+
+ }
+ // when toASCII is applied all label separators are replaced with FULL_STOP
+ result = compareCaseInsensitiveASCII(b1,b1Len,b2,b2Len);
+
+CLEANUP:
+ if(b1 != b1Stack){
+ uprv_free(b1);
+ }
+
+ if(b2 != b2Stack){
+ uprv_free(b2);
+ }
+
+ return result;
+}
+#endif /* #if !UCONFIG_NO_IDNA */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/idnaref.h b/Build/source/libs/icu/icu-xetex/test/intltest/idnaref.h
new file mode 100644
index 00000000000..78af44b6fd3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/idnaref.h
@@ -0,0 +1,228 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2003-2004, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: idnaref.h
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2003feb1
+ * created by: Ram Viswanadha
+ */
+
+#ifndef __IDNAREF_H__
+#define __IDNAREF_H__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+#include "unicode/parseerr.h"
+
+#define IDNAREF_DEFAULT 0x0000
+#define IDNAREF_ALLOW_UNASSIGNED 0x0001
+#define IDNAREF_USE_STD3_RULES 0x0002
+
+/**
+ * This function implements the ToASCII operation as defined in the IDNA draft.
+ * This operation is done on <b>single labels</b> before sending it to something that expects
+ * ASCII names. A label is an individual part of a domain name. Labels are usually
+ * separated by dots; for e.g." "www.example.com" is composed of 3 labels
+ * "www","example", and "com".
+ *
+ *
+ * @param src Input Unicode label.
+ * @param srcLength Number of UChars in src, or -1 if NUL-terminated.
+ * @param dest Output Unicode array with ACE encoded ASCII label.
+ * @param destCapacity Size of dest.
+ * @param options A bit set of options:
+ *
+ * - idnaref_UNASSIGNED Unassigned values can be converted to ASCII for query operations
+ * If TRUE unassigned values are treated as normal Unicode code points.
+ * If FALSE the operation fails with U_UNASSIGNED_CODE_POINT_FOUND error code.
+ * - idnaref_USE_STD3_RULES Use STD3 ASCII rules for host name syntax restrictions
+ * If TRUE and the input does not statisfy STD3 rules, the operation
+ * will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param parseError Pointer to UParseError struct to recieve information on position
+ * of error if an error is encountered. Can be NULL.
+ * @param status ICU in/out error code parameter.
+ * U_INVALID_CHAR_FOUND if src contains
+ * unmatched single surrogates.
+ * U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ * too many code points.
+ * U_BUFFER_OVERFLOW_ERROR if destCapacity is not enough
+ * @return Number of ASCII characters converted.
+ * @draft ICU 2.6
+ */
+U_CFUNC int32_t U_EXPORT2
+idnaref_toASCII(const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ int32_t options,
+ UParseError* parseError,
+ UErrorCode* status);
+
+
+/**
+ * This function implements the ToUnicode operation as defined in the IDNA draft.
+ * This operation is done on <b>single labels</b> before sending it to something that expects
+ * ASCII names. A label is an individual part of a domain name. Labels are usually
+ * separated by dots; for e.g." "www.example.com" is composed of 3 labels
+ * "www","example", and "com".
+ *
+ * @param src Input ASCII (ACE encoded) label.
+ * @param srcLength Number of UChars in src, or -1 if NUL-terminated.
+ * @param dest Output Converted Unicode array.
+ * @param destCapacity Size of dest.
+ * @param options A bit set of options:
+ *
+ * - idnaref_UNASSIGNED Unassigned values can be converted to ASCII for query operations
+ * If TRUE unassigned values are treated as normal Unicode code points.
+ * If FALSE the operation fails with U_UNASSIGNED_CODE_POINT_FOUND error code.
+ * - idnaref_USE_STD3_RULES Use STD3 ASCII rules for host name syntax restrictions
+ * If TRUE and the input does not statisfy STD3 rules, the operation
+ * will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param parseError Pointer to UParseError struct to recieve information on position
+ * of error if an error is encountered. Can be NULL.
+ * @param status ICU in/out error code parameter.
+ * U_INVALID_CHAR_FOUND if src contains
+ * unmatched single surrogates.
+ * U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ * too many code points.
+ * U_BUFFER_OVERFLOW_ERROR if destCapacity is not enough
+ * @return Number of Unicode characters converted.
+ * @draft ICU 2.6
+ */
+U_CFUNC int32_t U_EXPORT2
+idnaref_toUnicode(const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ int32_t options,
+ UParseError* parseError,
+ UErrorCode* status);
+
+
+/**
+ * Convenience function that implements the IDNToASCII operation as defined in the IDNA draft.
+ * This operation is done on complete domain names, e.g: "www.example.com".
+ * It is important to note that this operation can fail. If it fails, then the input
+ * domain name cannot be used as an Internationalized Domain Name and the application
+ * should have methods defined to deal with the failure.
+ *
+ * <b>Note:</b> IDNA draft specifies that a conformant application should divide a domain name
+ * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each,
+ * and then convert. This function does not offer that level of granularity. The options once
+ * set will apply to all labels in the domain name
+ *
+ * @param src Input ASCII IDN.
+ * @param srcLength Number of UChars in src, or -1 if NUL-terminated.
+ * @param dest Output Unicode array.
+ * @param destCapacity Size of dest.
+ * @param options A bit set of options:
+ *
+ * - idnaref_UNASSIGNED Unassigned values can be converted to ASCII for query operations
+ * If TRUE unassigned values are treated as normal Unicode code points.
+ * If FALSE the operation fails with U_UNASSIGNED_CODE_POINT_FOUND error code.
+ * - idnaref_USE_STD3_RULES Use STD3 ASCII rules for host name syntax restrictions
+ * If TRUE and the input does not statisfy STD3 rules, the operation
+ * will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param parseError Pointer to UParseError struct to recieve information on position
+ * of error if an error is encountered. Can be NULL.
+ * @param status ICU in/out error code parameter.
+ * U_INVALID_CHAR_FOUND if src contains
+ * unmatched single surrogates.
+ * U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ * too many code points.
+ * U_BUFFER_OVERFLOW_ERROR if destCapacity is not enough
+ * @return Number of ASCII characters converted.
+ * @draft ICU 2.6
+ */
+U_CFUNC int32_t U_EXPORT2
+idnaref_IDNToASCII( const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ int32_t options,
+ UParseError* parseError,
+ UErrorCode* status);
+
+/**
+ * Convenience function that implements the IDNToUnicode operation as defined in the IDNA draft.
+ * This operation is done on complete domain names, e.g: "www.example.com".
+ *
+ * <b>Note:</b> IDNA draft specifies that a conformant application should divide a domain name
+ * into separate labels, decide whether to apply allowUnassigned and useSTD3ASCIIRules on each,
+ * and then convert. This function does not offer that level of granularity. The options once
+ * set will apply to all labels in the domain name
+ *
+ * @param src Input Unicode IDN.
+ * @param srcLength Number of UChars in src, or -1 if NUL-terminated.
+ * @param dest Output ASCII array.
+ * @param destCapacity Size of dest.
+ * @param options A bit set of options:
+ *
+ * - idnaref_UNASSIGNED Unassigned values can be converted to ASCII for query operations
+ * If TRUE unassigned values are treated as normal Unicode code points.
+ * If FALSE the operation fails with U_UNASSIGNED_CODE_POINT_FOUND error code.
+ * - idnaref_USE_STD3_RULES Use STD3 ASCII rules for host name syntax restrictions
+ * If TRUE and the input does not statisfy STD3 rules, the operation
+ * will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param parseError Pointer to UParseError struct to recieve information on position
+ * of error if an error is encountered. Can be NULL.
+ * @param status ICU in/out error code parameter.
+ * U_INVALID_CHAR_FOUND if src contains
+ * unmatched single surrogates.
+ * U_INDEX_OUTOFBOUNDS_ERROR if src contains
+ * too many code points.
+ * U_BUFFER_OVERFLOW_ERROR if destCapacity is not enough
+ * @return Number of ASCII characters converted.
+ * @draft ICU 2.6
+ */
+U_CFUNC int32_t U_EXPORT2
+idnaref_IDNToUnicode( const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ int32_t options,
+ UParseError* parseError,
+ UErrorCode* status);
+
+/**
+ * Compare two strings for IDNs for equivalence.
+ * This function splits the domain names into labels and compares them.
+ * According to IDN draft, whenever two labels are compared, they are
+ * considered equal if and only if their ASCII forms (obtained by
+ * applying toASCII) match using an case-insensitive ASCII comparison.
+ * Two domain names are considered a match if and only if all labels
+ * match regardless of whether label separators match.
+ *
+ * @param s1 First source string.
+ * @param length1 Length of first source string, or -1 if NUL-terminated.
+ *
+ * @param s2 Second source string.
+ * @param length2 Length of second source string, or -1 if NUL-terminated.
+ * @param options A bit set of options:
+ *
+ * - idnaref_UNASSIGNED Unassigned values can be converted to ASCII for query operations
+ * If TRUE unassigned values are treated as normal Unicode code points.
+ * If FALSE the operation fails with U_UNASSIGNED_CODE_POINT_FOUND error code.
+ * - idnaref_USE_STD3_RULES Use STD3 ASCII rules for host name syntax restrictions
+ * If TRUE and the input does not statisfy STD3 rules, the operation
+ * will fail with U_IDNA_STD3_ASCII_RULES_ERROR
+ *
+ * @param status ICU error code in/out parameter.
+ * Must fulfill U_SUCCESS before the function call.
+ * @return <0 or 0 or >0 as usual for string comparisons
+ * @draft ICU 2.6
+ */
+U_CFUNC int32_t U_EXPORT2
+idnaref_compare( const UChar *s1, int32_t length1,
+ const UChar *s2, int32_t length2,
+ int32_t options,
+ UErrorCode* status);
+
+#endif /* #if !UCONFIG_NO_IDNA */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/incaltst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/incaltst.cpp
new file mode 100644
index 00000000000..ecc7377ba35
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/incaltst.cpp
@@ -0,0 +1,813 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+/* Test Internationalized Calendars for C++ */
+
+#include "unicode/utypes.h"
+#include "string.h"
+#include "unicode/locid.h"
+#include "japancal.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include <stdio.h>
+#include "caltest.h"
+
+#define CHECK(status, msg) \
+ if (U_FAILURE(status)) { \
+ errln((UnicodeString(u_errorName(status)) + UnicodeString(" : " ) )+ msg); \
+ return; \
+ }
+
+
+static UnicodeString escape( const UnicodeString&src)
+{
+ UnicodeString dst;
+ dst.remove();
+ for (int32_t i = 0; i < src.length(); ++i) {
+ UChar c = src[i];
+ if(c < 0x0080)
+ dst += c;
+ else {
+ dst += UnicodeString("[");
+ char buf [8];
+ sprintf(buf, "%#x", c);
+ dst += UnicodeString(buf);
+ dst += UnicodeString("]");
+ }
+ }
+
+ return dst;
+}
+
+
+#include "incaltst.h"
+#include "unicode/gregocal.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/simpletz.h"
+
+// *****************************************************************************
+// class IntlCalendarTest
+// *****************************************************************************
+//--- move to CalendarTest?
+
+static const double JULIAN_EPOCH = -210866760000000.;
+
+
+// Turn this on to dump the calendar fields
+#define U_DEBUG_DUMPCALS
+
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
+
+
+void IntlCalendarTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite IntlCalendarTest");
+ switch (index) {
+ CASE(0,TestTypes);
+ CASE(1,TestGregorian);
+ CASE(2,TestBuddhist);
+ CASE(3,TestJapanese);
+ CASE(4,TestBuddhistFormat);
+ CASE(5,TestJapaneseFormat);
+ CASE(6,TestJapanese3860);
+ CASE(7,TestPersian);
+ CASE(8,TestPersianFormat);
+ CASE(9,TestTaiwan);
+ default: name = ""; break;
+ }
+}
+
+#undef CASE
+
+// ---------------------------------------------------------------------------------
+
+
+/**
+ * Test various API methods for API completeness.
+ */
+void
+IntlCalendarTest::TestTypes()
+{
+ Calendar *c = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ int j;
+ const char *locs [40] = { "en_US_VALLEYGIRL",
+ "en_US_VALLEYGIRL@collation=phonebook;calendar=japanese",
+ "en_US_VALLEYGIRL@collation=phonebook;calendar=gregorian",
+ "ja_JP@calendar=japanese",
+ "th_TH@calendar=buddhist",
+ "ja_JP_TRADITIONAL",
+ "th_TH_TRADITIONAL",
+ "th_TH_TRADITIONAL@calendar=gregorian",
+ "en_US", NULL };
+ const char *types[40] = { "gregorian",
+ "japanese",
+ "gregorian",
+ "japanese",
+ "buddhist",
+ "japanese",
+ "buddhist",
+ "gregorian",
+ "gregorian", NULL };
+
+ for(j=0;locs[j];j++) {
+ logln(UnicodeString("Creating calendar of locale ") + locs[j]);
+ status = U_ZERO_ERROR;
+ c = Calendar::createInstance(locs[j], status);
+ CHECK(status, "creating '" + UnicodeString(locs[j]) + "' calendar");
+ if(U_SUCCESS(status)) {
+ logln(UnicodeString(" type is ") + c->getType());
+ if(strcmp(c->getType(), types[j])) {
+ errln(UnicodeString(locs[j]) + UnicodeString("Calendar type ") + c->getType() + " instead of " + types[j]);
+ }
+ }
+ delete c;
+ }
+}
+
+
+
+/**
+ * Run a test of a quasi-Gregorian calendar. This is a calendar
+ * that behaves like a Gregorian but has different year/era mappings.
+ * The int[] data array should have the format:
+ *
+ * { era, year, gregorianYear, month, dayOfMonth, ... ... , -1 }
+ */
+void IntlCalendarTest::quasiGregorianTest(Calendar& cal, const Locale& gcl, const int32_t *data) {
+ UErrorCode status = U_ZERO_ERROR;
+ // As of JDK 1.4.1_01, using the Sun JDK GregorianCalendar as
+ // a reference throws us off by one hour. This is most likely
+ // due to the JDK 1.4 incorporation of historical time zones.
+ //java.util.Calendar grego = java.util.Calendar.getInstance();
+ Calendar *grego = Calendar::createInstance(gcl, status);
+ if (U_FAILURE(status)) {
+ dataerrln("Error calling Calendar::createInstance");
+ return;
+ }
+
+ int32_t tz1 = cal.get(UCAL_ZONE_OFFSET,status);
+ int32_t tz2 = grego -> get (UCAL_ZONE_OFFSET, status);
+ if(tz1 != tz2) {
+ errln((UnicodeString)"cal's tz " + tz1 + " != grego's tz " + tz2);
+ }
+
+ for (int32_t i=0; data[i]!=-1; ) {
+ int32_t era = data[i++];
+ int32_t year = data[i++];
+ int32_t gregorianYear = data[i++];
+ int32_t month = data[i++];
+ int32_t dayOfMonth = data[i++];
+
+ grego->clear();
+ grego->set(gregorianYear, month, dayOfMonth);
+ UDate D = grego->getTime(status);
+
+ cal.clear();
+ cal.set(UCAL_ERA, era);
+ cal.set(year, month, dayOfMonth);
+ UDate d = cal.getTime(status);
+#ifdef U_DEBUG_DUMPCALS
+ logln((UnicodeString)"cal : " + CalendarTest::calToStr(cal));
+ logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
+#endif
+ if (d == D) {
+ logln(UnicodeString("OK: ") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
+ " => " + d + " (" + UnicodeString(cal.getType()) + ")");
+ } else {
+ errln(UnicodeString("Fail: (fields to millis)") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth +
+ " => " + d + ", expected " + D + " (" + UnicodeString(cal.getType()) + "Off by: " + (d-D));
+ }
+
+ // Now, set the gregorian millis on the other calendar
+ cal.clear();
+ cal.setTime(D, status);
+ int e = cal.get(UCAL_ERA, status);
+ int y = cal.get(UCAL_YEAR, status);
+#ifdef U_DEBUG_DUMPCALS
+ logln((UnicodeString)"cal : " + CalendarTest::calToStr(cal));
+ logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego));
+#endif
+ if (y == year && e == era) {
+ logln((UnicodeString)"OK: " + D + " => " + cal.get(UCAL_ERA, status) + ":" +
+ cal.get(UCAL_YEAR, status) + "/" +
+ (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) + " (" + UnicodeString(cal.getType()) + ")");
+ } else {
+ errln((UnicodeString)"Fail: (millis to fields)" + D + " => " + cal.get(UCAL_ERA, status) + ":" +
+ cal.get(UCAL_YEAR, status) + "/" +
+ (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) +
+ ", expected " + era + ":" + year + "/" + (month+1) + "/" +
+ dayOfMonth + " (" + UnicodeString(cal.getType()));
+ }
+ }
+ delete grego;
+ CHECK(status, "err during quasiGregorianTest()");
+}
+
+// Verify that Gregorian works like Gregorian
+void IntlCalendarTest::TestGregorian() {
+ UDate timeA = Calendar::getNow();
+ int32_t data[] = {
+ GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 8,
+ GregorianCalendar::AD, 1868, 1868, UCAL_SEPTEMBER, 9,
+ GregorianCalendar::AD, 1869, 1869, UCAL_JUNE, 4,
+ GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 29,
+ GregorianCalendar::AD, 1912, 1912, UCAL_JULY, 30,
+ GregorianCalendar::AD, 1912, 1912, UCAL_AUGUST, 1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+ };
+
+ Calendar *cal;
+ UErrorCode status = U_ZERO_ERROR;
+ cal = Calendar::createInstance(/*"de_DE", */ status);
+ CHECK(status, UnicodeString("Creating de_CH calendar"));
+ // Sanity check the calendar
+ UDate timeB = Calendar::getNow();
+ UDate timeCal = cal->getTime(status);
+
+ if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
+ errln((UnicodeString)"Error: Calendar time " + timeCal +
+ " is not within sampled times [" + timeA + " to " + timeB + "]!");
+ }
+ // end sanity check
+
+ // Note, the following is a good way to test the sanity of the constructed calendars,
+ // using Collation as a delay-loop:
+ //
+ // $ intltest format/IntlCalendarTest collate/G7CollationTest format/IntlCalendarTest
+
+ quasiGregorianTest(*cal,Locale("fr_FR"),data);
+ delete cal;
+}
+
+/**
+ * Verify that BuddhistCalendar shifts years to Buddhist Era but otherwise
+ * behaves like GregorianCalendar.
+ */
+void IntlCalendarTest::TestBuddhist() {
+ // BE 2542 == 1999 CE
+ UDate timeA = Calendar::getNow();
+
+ int32_t data[] = {
+ 0, // B. era [928479600000]
+ 2542, // B. year
+ 1999, // G. year
+ UCAL_JUNE, // month
+ 4, // day
+
+ 0, // B. era [-79204842000000]
+ 3, // B. year
+ -540, // G. year
+ UCAL_FEBRUARY, // month
+ 12, // day
+
+ 0, // test month calculation: 4795 BE = 4252 AD is a leap year, but 4795 AD is not.
+ 4795, // BE [72018057600000]
+ 4252, // AD
+ UCAL_FEBRUARY,
+ 29,
+
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+ };
+ Calendar *cal;
+ UErrorCode status = U_ZERO_ERROR;
+ cal = Calendar::createInstance("th_TH@calendar=buddhist", status);
+ CHECK(status, UnicodeString("Creating th_TH@calendar=buddhist calendar"));
+
+ // Sanity check the calendar
+ UDate timeB = Calendar::getNow();
+ UDate timeCal = cal->getTime(status);
+
+ if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
+ errln((UnicodeString)"Error: Calendar time " + timeCal +
+ " is not within sampled times [" + timeA + " to " + timeB + "]!");
+ }
+ // end sanity check
+
+
+ quasiGregorianTest(*cal,Locale("th_TH@calendar=gregorian"),data);
+ delete cal;
+}
+
+
+/**
+ * Verify that TaiWanCalendar shifts years to Minguo Era but otherwise
+ * behaves like GregorianCalendar.
+ */
+void IntlCalendarTest::TestTaiwan() {
+ // MG 1 == 1912 AD
+ UDate timeA = Calendar::getNow();
+
+ // TODO port these to the data items
+ int32_t data[] = {
+ 1, // B. era [928479600000]
+ 1, // B. year
+ 1912, // G. year
+ UCAL_JUNE, // month
+ 4, // day
+
+ 1, // B. era [-79204842000000]
+ 3, // B. year
+ 1914, // G. year
+ UCAL_FEBRUARY, // month
+ 12, // day
+
+ 1, // B. era [-79204842000000]
+ 96, // B. year
+ 2007, // G. year
+ UCAL_FEBRUARY, // month
+ 12, // day
+
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+ };
+ Calendar *cal;
+ UErrorCode status = U_ZERO_ERROR;
+ cal = Calendar::createInstance("en_US@calendar=taiwan", status);
+ CHECK(status, UnicodeString("Creating en_US@calendar=taiwan calendar"));
+
+ // Sanity check the calendar
+ UDate timeB = Calendar::getNow();
+ UDate timeCal = cal->getTime(status);
+
+ if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
+ errln((UnicodeString)"Error: Calendar time " + timeCal +
+ " is not within sampled times [" + timeA + " to " + timeB + "]!");
+ }
+ // end sanity check
+
+
+ quasiGregorianTest(*cal,Locale("en_US"),data);
+ delete cal;
+}
+
+
+
+/**
+ * Verify that JapaneseCalendar shifts years to Japanese Eras but otherwise
+ * behaves like GregorianCalendar.
+ */
+void IntlCalendarTest::TestJapanese() {
+ UDate timeA = Calendar::getNow();
+
+ /* Sorry.. japancal.h is private! */
+#define JapaneseCalendar_MEIJI 232
+#define JapaneseCalendar_TAISHO 233
+#define JapaneseCalendar_SHOWA 234
+#define JapaneseCalendar_HEISEI 235
+
+ // BE 2542 == 1999 CE
+ int32_t data[] = {
+ // Jera Jyr Gyear m d
+ JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 8,
+ JapaneseCalendar_MEIJI, 1, 1868, UCAL_SEPTEMBER, 9,
+ JapaneseCalendar_MEIJI, 2, 1869, UCAL_JUNE, 4,
+ JapaneseCalendar_MEIJI, 45, 1912, UCAL_JULY, 29,
+ JapaneseCalendar_TAISHO, 1, 1912, UCAL_JULY, 30,
+ JapaneseCalendar_TAISHO, 1, 1912, UCAL_AUGUST, 1,
+
+ // new tests (not in java)
+ JapaneseCalendar_SHOWA, 64, 1989, UCAL_JANUARY, 7, // Test current era transition (different code path than others)
+ JapaneseCalendar_HEISEI, 1, 1989, UCAL_JANUARY, 8,
+ JapaneseCalendar_HEISEI, 1, 1989, UCAL_JANUARY, 9,
+ JapaneseCalendar_HEISEI, 1, 1989, UCAL_DECEMBER, 20,
+ JapaneseCalendar_HEISEI, 15, 2003, UCAL_MAY, 22,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1
+ };
+
+ Calendar *cal;
+ UErrorCode status = U_ZERO_ERROR;
+ cal = Calendar::createInstance("ja_JP@calendar=japanese", status);
+ CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
+ // Sanity check the calendar
+ UDate timeB = Calendar::getNow();
+ UDate timeCal = cal->getTime(status);
+
+ if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
+ errln((UnicodeString)"Error: Calendar time " + timeCal +
+ " is not within sampled times [" + timeA + " to " + timeB + "]!");
+ }
+ // end sanity check
+ quasiGregorianTest(*cal,Locale("ja_JP"),data);
+ delete cal;
+}
+
+
+
+void IntlCalendarTest::TestBuddhistFormat() {
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Test simple parse/format with adopt
+
+ // First, a contrived english test..
+ UDate aDate = 999932400000.0;
+ SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=buddhist"), status);
+ CHECK(status, "creating date format instance");
+ SimpleDateFormat *fmt2 = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
+ CHECK(status, "creating gregorian date format instance");
+ if(!fmt) {
+ errln("Coudln't create en_US instance");
+ } else {
+ UnicodeString str;
+ fmt2->format(aDate, str);
+ logln(UnicodeString() + "Test Date: " + str);
+ str.remove();
+ fmt->format(aDate, str);
+ logln(UnicodeString() + "as Buddhist Calendar: " + escape(str));
+ UnicodeString expected("September 8, 2544 BE");
+ if(str != expected) {
+ errln("Expected " + escape(expected) + " but got " + escape(str));
+ }
+ UDate otherDate = fmt->parse(expected, status);
+ if(otherDate != aDate) {
+ UnicodeString str3;
+ fmt->format(otherDate, str3);
+ errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate + ", " + escape(str3));
+ } else {
+ logln("Parsed OK: " + expected);
+ }
+ delete fmt;
+ }
+ delete fmt2;
+
+ CHECK(status, "Error occured testing Buddhist Calendar in English ");
+
+ status = U_ZERO_ERROR;
+ // Now, try in Thai
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
+ " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
+ UDate expectDate = 999932400000.0;
+ Locale loc("th_TH_TRADITIONAL"); // legacy
+
+ simpleTest(loc, expect, expectDate, status);
+ }
+ status = U_ZERO_ERROR;
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
+ " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e1e.\\u0e28. 2544");
+ UDate expectDate = 999932400000.0;
+ Locale loc("th_TH@calendar=buddhist");
+
+ simpleTest(loc, expect, expectDate, status);
+ }
+ status = U_ZERO_ERROR;
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
+ " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
+ UDate expectDate = 999932400000.0;
+ Locale loc("th_TH@calendar=gregorian");
+
+ simpleTest(loc, expect, expectDate, status);
+ }
+ status = U_ZERO_ERROR;
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u0E27\\u0E31\\u0E19\\u0E40\\u0E2A\\u0E32\\u0E23\\u0E4C\\u0E17\\u0E35\\u0E48"
+ " 8 \\u0E01\\u0E31\\u0e19\\u0e22\\u0e32\\u0e22\\u0e19 \\u0e04.\\u0e28. 2001");
+ UDate expectDate = 999932400000.0;
+ Locale loc("th_TH_TRADITIONAL@calendar=gregorian");
+
+ simpleTest(loc, expect, expectDate, status);
+ }
+}
+
+// TaiwanFormat has been moved to testdata/format.txt
+
+
+void IntlCalendarTest::TestJapaneseFormat() {
+ Calendar *cal;
+ UErrorCode status = U_ZERO_ERROR;
+ cal = Calendar::createInstance("ja_JP_TRADITIONAL", status);
+ CHECK(status, UnicodeString("Creating ja_JP_TRADITIONAL calendar"));
+
+ Calendar *cal2 = cal->clone();
+ delete cal;
+ cal = NULL;
+
+ // Test simple parse/format with adopt
+
+ UDate aDate = 999932400000.0;
+ SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yy G"), Locale("en_US@calendar=japanese"), status);
+ SimpleDateFormat *fmt2 = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
+ CHECK(status, "creating date format instance");
+ if(!fmt) {
+ errln("Coudln't create en_US instance");
+ } else {
+ UnicodeString str;
+ fmt2->format(aDate, str);
+ logln(UnicodeString() + "Test Date: " + str);
+ str.remove();
+ fmt->format(aDate, str);
+ logln(UnicodeString() + "as Japanese Calendar: " + str);
+ UnicodeString expected("September 8, 13 Heisei");
+ if(str != expected) {
+ errln("Expected " + expected + " but got " + str);
+ }
+ UDate otherDate = fmt->parse(expected, status);
+ if(otherDate != aDate) {
+ UnicodeString str3;
+ ParsePosition pp;
+ fmt->parse(expected, *cal2, pp);
+ fmt->format(otherDate, str3);
+ errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " + " = " + otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
+
+ } else {
+ logln("Parsed OK: " + expected);
+ }
+ delete fmt;
+ }
+
+ // Test parse with incomplete information
+ fmt = new SimpleDateFormat(UnicodeString("G y"), Locale("en_US@calendar=japanese"), status);
+ /* The test data below should points to 1868-09-08T00:00:00 in America/Los_Angeles.
+ * The time calculated by original test code uses -7:00 UTC offset, because it assumes
+ * DST is observed (because of a timezone bug, DST is observed for early 20th century
+ * day to infinite past time). The bug was fixed and DST is no longer used for time before
+ * 1900 for any zones. However, ICU timezone transition data is represented by 32-bit integer
+ * (sec) and cannot represent transitions before 1901 defined in Olson tzdata. For example,
+ * based on Olson definition, offset -7:52:58 should be used for Nov 18, 1883 or older dates.
+ * If ICU properly capture entire Olson zone definition, the start time of "Meiji 1" is
+ * -3197117222000. -Yoshito
+ */
+ /* TODO: When ICU support the Olson LMT offset for America/Los_Angeles, we need to update
+ * the reference data.
+ */
+ //aDate = -3197120400000.;
+ aDate = -3197116800000.;
+ CHECK(status, "creating date format instance");
+ if(!fmt) {
+ errln("Coudln't create en_US instance");
+ } else {
+ UnicodeString str;
+ fmt2->format(aDate, str);
+ logln(UnicodeString() + "Test Date: " + str);
+ str.remove();
+ fmt->format(aDate, str);
+ logln(UnicodeString() + "as Japanese Calendar: " + str);
+ UnicodeString expected("Meiji 1");
+ if(str != expected) {
+ errln("Expected " + expected + " but got " + str);
+ }
+ UDate otherDate = fmt->parse(expected, status);
+ if(otherDate != aDate) {
+ UnicodeString str3;
+ ParsePosition pp;
+ fmt->parse(expected, *cal2, pp);
+ fmt->format(otherDate, str3);
+ errln("Parse incorrect of " + expected + " - wanted " + aDate + " but got " + " = " +
+ otherDate + ", " + str3 + " = " + CalendarTest::calToStr(*cal2) );
+ } else {
+ logln("Parsed OK: " + expected);
+ }
+ delete fmt;
+ }
+
+ delete cal2;
+ delete fmt2;
+ CHECK(status, "Error occured");
+
+ // Now, try in Japanese
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
+ UDate expectDate = 999932400000.0; // Testing a recent date
+ Locale loc("ja_JP@calendar=japanese");
+
+ status = U_ZERO_ERROR;
+ simpleTest(loc, expect, expectDate, status);
+ }
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u5e73\\u621013\\u5e749\\u67088\\u65e5\\u571f\\u66dc\\u65e5");
+ UDate expectDate = 999932400000.0; // Testing a recent date
+ Locale loc("ja_JP_TRADITIONAL"); // legacy
+
+ status = U_ZERO_ERROR;
+ simpleTest(loc, expect, expectDate, status);
+ }
+ {
+ UnicodeString expect = CharsToUnicodeString("\\u5b89\\u6c385\\u5e747\\u67084\\u65e5\\u6728\\u66dc\\u65e5");
+ //UDate expectDate = -6106035600000.0;
+ UDate expectDate = -6106032000000.0; // 1776-07-04T00:00:00Z-0800
+ Locale loc("ja_JP@calendar=japanese");
+
+ status = U_ZERO_ERROR;
+ simpleTest(loc, expect, expectDate, status);
+
+ }
+ { // Jitterbug 1869 - this is an ambiguous era. (Showa 64 = Jan 6 1989, but Showa could be 2 other eras) )
+ UnicodeString expect = CharsToUnicodeString("\\u662d\\u548c64\\u5e741\\u67086\\u65e5\\u91d1\\u66dc\\u65e5");
+ UDate expectDate = 600076800000.0;
+ Locale loc("ja_JP@calendar=japanese");
+
+ status = U_ZERO_ERROR;
+ simpleTest(loc, expect, expectDate, status);
+
+ }
+ { // This Feb 29th falls on a leap year by gregorian year, but not by Japanese year.
+ UnicodeString expect = CharsToUnicodeString("\\u5EB7\\u6B632\\u5e742\\u670829\\u65e5\\u65e5\\u66dc\\u65e5");
+ // Add -1:00 to the following for historical TZ - aliu
+ //UDate expectDate = -16214403600000.0; // courtesy of date format round trip test
+ UDate expectDate = -16214400000000.0; // 1456-03-09T00:00:00Z-0800
+ Locale loc("ja_JP@calendar=japanese");
+
+ status = U_ZERO_ERROR;
+ simpleTest(loc, expect, expectDate, status);
+
+ }
+}
+
+void IntlCalendarTest::TestJapanese3860()
+{
+ Calendar *cal;
+ UErrorCode status = U_ZERO_ERROR;
+ cal = Calendar::createInstance("ja_JP@calendar=japanese", status);
+ CHECK(status, UnicodeString("Creating ja_JP@calendar=japanese calendar"));
+ Calendar *cal2 = cal->clone();
+ SimpleDateFormat *fmt2 = new SimpleDateFormat(UnicodeString("HH:mm:ss.S MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
+ UnicodeString str;
+
+
+ {
+ // Test simple parse/format with adopt
+ UDate aDate = 0;
+
+ // Test parse with missing era (should default to current era, heisei)
+ // Test parse with incomplete information
+ logln("Testing parse w/ missing era...");
+ SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("y.M.d"), Locale("ja_JP@calendar=japanese"), status);
+ CHECK(status, "creating date format instance");
+ if(!fmt) {
+ errln("Coudln't create en_US instance");
+ } else {
+ UErrorCode s2 = U_ZERO_ERROR;
+ cal2->clear();
+ UnicodeString samplestr("1.1.9");
+ logln(UnicodeString() + "Test Year: " + samplestr);
+ aDate = fmt->parse(samplestr, s2);
+ ParsePosition pp=0;
+ fmt->parse(samplestr, *cal2, pp);
+ CHECK(s2, "parsing the 1.1.9 string");
+ logln("*cal2 after 119 parse:");
+ str.remove();
+ fmt2->format(aDate, str);
+ logln(UnicodeString() + "as Gregorian Calendar: " + str);
+
+ cal2->setTime(aDate, s2);
+ int32_t gotYear = cal2->get(UCAL_YEAR, s2);
+ int32_t gotEra = cal2->get(UCAL_ERA, s2);
+ int32_t expectYear = 1;
+ int32_t expectEra = JapaneseCalendar::getCurrentEra();
+ if((gotYear!=1) || (gotEra != expectEra)) {
+ errln(UnicodeString("parse "+samplestr+" of 'y.m.d' as Japanese Calendar, expected year ") + expectYear +
+ UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
+ } else {
+ logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
+ }
+ delete fmt;
+ }
+ }
+
+#if 0
+ // this will NOT work - *all the time*. If it is the 1st of the month, for example it will get Jan 1 heisei 1 => jan 1 showa 64, wrong era.
+ {
+ // Test simple parse/format with adopt
+ UDate aDate = 0;
+
+ // Test parse with missing era (should default to current era, heisei)
+ // Test parse with incomplete information
+ logln("Testing parse w/ just year...");
+ SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("y"), Locale("ja_JP@calendar=japanese"), status);
+ CHECK(status, "creating date format instance");
+ if(!fmt) {
+ errln("Coudln't create en_US instance");
+ } else {
+ UErrorCode s2 = U_ZERO_ERROR;
+ cal2->clear();
+ UnicodeString samplestr("1");
+ logln(UnicodeString() + "Test Year: " + samplestr);
+ aDate = fmt->parse(samplestr, s2);
+ ParsePosition pp=0;
+ fmt->parse(samplestr, *cal2, pp);
+ CHECK(s2, "parsing the 1 string");
+ logln("*cal2 after 1 parse:");
+ str.remove();
+ fmt2->format(aDate, str);
+ logln(UnicodeString() + "as Gregorian Calendar: " + str);
+
+ cal2->setTime(aDate, s2);
+ int32_t gotYear = cal2->get(UCAL_YEAR, s2);
+ int32_t gotEra = cal2->get(UCAL_ERA, s2);
+ int32_t expectYear = 1;
+ int32_t expectEra = JapaneseCalendar::kCurrentEra;
+ if((gotYear!=1) || (gotEra != expectEra)) {
+ errln(UnicodeString("parse "+samplestr+" of 'y' as Japanese Calendar, expected year ") + expectYear +
+ UnicodeString(" and era ") + expectEra +", but got year " + gotYear + " and era " + gotEra + " (Gregorian:" + str +")");
+ } else {
+ logln(UnicodeString() + " year: " + gotYear + ", era: " + gotEra);
+ }
+ delete fmt;
+ }
+ }
+#endif
+ delete cal2;
+ delete cal;
+ delete fmt2;
+}
+
+
+
+
+/**
+ * Verify the Persian Calendar.
+ */
+void IntlCalendarTest::TestPersian() {
+ UDate timeA = Calendar::getNow();
+
+ Calendar *cal;
+ UErrorCode status = U_ZERO_ERROR;
+ cal = Calendar::createInstance("fa_IR@calendar=persian", status);
+ CHECK(status, UnicodeString("Creating fa_IR@calendar=persian calendar"));
+ // Sanity check the calendar
+ UDate timeB = Calendar::getNow();
+ UDate timeCal = cal->getTime(status);
+
+ if(!(timeA <= timeCal) || !(timeCal <= timeB)) {
+ errln((UnicodeString)"Error: Calendar time " + timeCal +
+ " is not within sampled times [" + timeA + " to " + timeB + "]!");
+ }
+ // end sanity check
+// quasiGregorianTest(*cal,Locale("ja_JP"),data);
+ delete cal;
+}
+
+void IntlCalendarTest::TestPersianFormat() {
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *fmt = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale(" en_US@calendar=persian"), status);
+ CHECK(status, "creating date format instance");
+ SimpleDateFormat *fmt2 = new SimpleDateFormat(UnicodeString("MMMM d, yyyy G"), Locale("en_US@calendar=gregorian"), status);
+ CHECK(status, "creating gregorian date format instance");
+ UnicodeString gregorianDate("January 18, 2007 AD");
+ UDate aDate = fmt2->parse(gregorianDate, status);
+ if(!fmt) {
+ errln("Coudln't create en_US instance");
+ } else {
+ UnicodeString str;
+ fmt->format(aDate, str);
+ logln(UnicodeString() + "as Persian Calendar: " + escape(str));
+ UnicodeString expected("Dey 28, 1385 AP");
+ if(str != expected) {
+ errln("Expected " + escape(expected) + " but got " + escape(str));
+ }
+ UDate otherDate = fmt->parse(expected, status);
+ if(otherDate != aDate) {
+ UnicodeString str3;
+ fmt->format(otherDate, str3);
+ errln("Parse incorrect of " + escape(expected) + " - wanted " + aDate + " but got " + otherDate + ", " + escape(str3));
+ } else {
+ logln("Parsed OK: " + expected);
+ }
+ delete fmt;
+ }
+ delete fmt2;
+
+ CHECK(status, "Error occured testing Persian Calendar in English ");
+}
+
+
+void IntlCalendarTest::simpleTest(const Locale& loc, const UnicodeString& expect, UDate expectDate, UErrorCode& status)
+{
+ UnicodeString tmp;
+ UDate d;
+ DateFormat *fmt0 = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull);
+
+ logln("Try format/parse of " + (UnicodeString)loc.getName());
+ DateFormat *fmt2 = DateFormat::createDateInstance(DateFormat::kFull, loc);
+ if(fmt2) {
+ fmt2->format(expectDate, tmp);
+ logln(escape(tmp) + " ( in locale " + loc.getName() + ")");
+ if(tmp != expect) {
+ errln(UnicodeString("Failed to format " ) + loc.getName() + " expected " + escape(expect) + " got " + escape(tmp) );
+ }
+
+ d = fmt2->parse(expect,status);
+ CHECK(status, "Error occured parsing " + UnicodeString(loc.getName()));
+ if(d != expectDate) {
+ fmt2->format(d,tmp);
+ errln(UnicodeString("Failed to parse " ) + escape(expect) + ", " + loc.getName() + " expect " + (double)expectDate + " got " + (double)d + " " + escape(tmp));
+ logln( "wanted " + escape(fmt0->format(expectDate,tmp.remove())) + " but got " + escape(fmt0->format(d,tmp.remove())));
+ }
+ delete fmt2;
+ } else {
+ errln((UnicodeString)"Can't create " + loc.getName() + " date instance");
+ }
+ delete fmt0;
+}
+
+#undef CHECK
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/incaltst.h b/Build/source/libs/icu/icu-xetex/test/intltest/incaltst.h
new file mode 100644
index 00000000000..2c03ce32313
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/incaltst.h
@@ -0,0 +1,53 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef __IntlCalendarTest__
+#define __IntlCalendarTest__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/calendar.h"
+#include "unicode/smpdtfmt.h"
+#include "caltztst.h"
+
+class IntlCalendarTest: public CalendarTimeZoneTest {
+public:
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+ void TestTypes(void);
+
+ void TestGregorian(void);
+
+ void TestBuddhist(void);
+ void TestBuddhistFormat(void);
+
+ void TestTaiwan(void);
+
+ void TestJapanese(void);
+ void TestJapaneseFormat(void);
+ void TestJapanese3860(void);
+
+ void TestPersian(void);
+ void TestPersianFormat(void);
+
+ protected:
+ // Test a Gregorian-Like calendar
+ void quasiGregorianTest(Calendar& cal, const Locale& gregoLocale, const int32_t *data);
+ void simpleTest(const Locale& loc, const UnicodeString& expect, UDate expectDate, UErrorCode& status);
+
+public: // package
+ // internal routine for checking date
+ static UnicodeString value(Calendar* calendar);
+
+};
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __IntlCalendarTest__
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/intltest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/intltest.cpp
new file mode 100644
index 00000000000..2a676bb0d41
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/intltest.cpp
@@ -0,0 +1,1590 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#include "unicode/utypes.h"
+
+/**
+ * IntlTest is a base class for tests.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "unicode/unistr.h"
+#include "unicode/ures.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/ucnv.h"
+#include "unicode/uclean.h"
+#include "unicode/timezone.h"
+#include "unicode/curramt.h"
+#include "unicode/putil.h"
+
+#include "intltest.h"
+#include "caltztst.h"
+#include "itmajor.h"
+#include "cstring.h"
+#include "umutex.h"
+#include "uassert.h"
+#include "cmemory.h"
+#include "uoptions.h"
+
+#include "putilimp.h" // for uprv_getUTCtime()
+#include "unicode/locid.h"
+
+
+#ifdef XP_MAC_CONSOLE
+#include <console.h>
+#include "Files.h"
+#endif
+
+
+static char* _testDataPath=NULL;
+
+// Static list of errors found
+static UnicodeString errorList;
+
+//-----------------------------------------------------------------------------
+//convenience classes to ease porting code that uses the Java
+//string-concatenation operator (moved from findword test by rtg)
+
+// [LIU] Just to get things working
+UnicodeString
+UCharToUnicodeString(UChar c)
+{ return UnicodeString(c); }
+
+// [rtg] Just to get things working
+UnicodeString
+operator+(const UnicodeString& left,
+ long num)
+{
+ char buffer[64]; // nos changed from 10 to 64
+ char danger = 'p'; // guard against overrunning the buffer (rtg)
+
+ sprintf(buffer, "%ld", num);
+ assert(danger == 'p');
+
+ return left + buffer;
+}
+
+UnicodeString
+operator+(const UnicodeString& left,
+ unsigned long num)
+{
+ char buffer[64]; // nos changed from 10 to 64
+ char danger = 'p'; // guard against overrunning the buffer (rtg)
+
+ sprintf(buffer, "%lu", num);
+ assert(danger == 'p');
+
+ return left + buffer;
+}
+
+UnicodeString
+Int64ToUnicodeString(int64_t num)
+{
+ char buffer[64]; // nos changed from 10 to 64
+ char danger = 'p'; // guard against overrunning the buffer (rtg)
+
+#ifdef U_WINDOWS
+ sprintf(buffer, "%I64d", num);
+#else
+ sprintf(buffer, "%lld", (long long)num);
+#endif
+ assert(danger == 'p');
+
+ return buffer;
+}
+
+// [LIU] Just to get things working
+UnicodeString
+operator+(const UnicodeString& left,
+ double num)
+{
+ char buffer[64]; // was 32, made it arbitrarily bigger (rtg)
+ char danger = 'p'; // guard against overrunning the buffer (rtg)
+
+ // IEEE floating point has 52 bits of mantissa, plus one assumed bit
+ // 53*log(2)/log(10) = 15.95
+ // so there is no need to show more than 16 digits. [alan]
+
+ sprintf(buffer, "%.17g", num);
+ assert(danger == 'p');
+
+ return left + buffer;
+}
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * Return a string display for for this, without surrounding braces.
+ */
+UnicodeString _toString(const Formattable& f) {
+ UnicodeString s;
+ switch (f.getType()) {
+ case Formattable::kDate:
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat fmt(status);
+ if (U_SUCCESS(status)) {
+ FieldPosition pos;
+ fmt.format(f.getDate(), s, pos);
+ s.insert(0, "Date:");
+ } else {
+ s = UnicodeString("Error creating date format]");
+ }
+ }
+ break;
+ case Formattable::kDouble:
+ s = UnicodeString("double:") + f.getDouble();
+ break;
+ case Formattable::kLong:
+ s = UnicodeString("long:") + f.getLong();
+ break;
+
+ case Formattable::kInt64:
+ s = UnicodeString("int64:") + Int64ToUnicodeString(f.getInt64());
+ break;
+
+ case Formattable::kString:
+ f.getString(s);
+ s.insert(0, "String:");
+ break;
+ case Formattable::kArray:
+ {
+ int32_t i, n;
+ const Formattable* array = f.getArray(n);
+ s.insert(0, UnicodeString("Array:"));
+ UnicodeString delim(", ");
+ for (i=0; i<n; ++i) {
+ if (i > 0) {
+ s.append(delim);
+ }
+ s = s + _toString(array[i]);
+ }
+ }
+ break;
+ case Formattable::kObject:
+ if (f.getObject()->getDynamicClassID() ==
+ CurrencyAmount::getStaticClassID()) {
+ const CurrencyAmount& c = (const CurrencyAmount&) *f.getObject();
+ s = _toString(c.getNumber()) + " " + UnicodeString(c.getISOCurrency());
+ } else {
+ s = UnicodeString("Unknown UObject");
+ }
+ break;
+ default:
+ s = UnicodeString("Unknown Formattable type=") + (int32_t)f.getType();
+ break;
+ }
+ return s;
+}
+
+/**
+ * Originally coded this as operator+, but that makes the expression
+ * + char* ambiguous. - liu
+ */
+UnicodeString toString(const Formattable& f) {
+ UnicodeString s((UChar)91/*[*/);
+ s.append(_toString(f));
+ s.append((UChar)0x5d/*]*/);
+ return s;
+}
+
+#endif
+
+// useful when operator+ won't cooperate
+UnicodeString toString(int32_t n) {
+ return UnicodeString() + (long)n;
+}
+
+// stephen - cleaned up 05/05/99
+UnicodeString operator+(const UnicodeString& left, char num)
+{ return left + (long)num; }
+UnicodeString operator+(const UnicodeString& left, short num)
+{ return left + (long)num; }
+UnicodeString operator+(const UnicodeString& left, int num)
+{ return left + (long)num; }
+UnicodeString operator+(const UnicodeString& left, unsigned char num)
+{ return left + (unsigned long)num; }
+UnicodeString operator+(const UnicodeString& left, unsigned short num)
+{ return left + (unsigned long)num; }
+UnicodeString operator+(const UnicodeString& left, unsigned int num)
+{ return left + (unsigned long)num; }
+UnicodeString operator+(const UnicodeString& left, float num)
+{ return left + (double)num; }
+
+//------------------
+
+// Append a hex string to the target
+UnicodeString&
+IntlTest::appendHex(uint32_t number,
+ int32_t digits,
+ UnicodeString& target)
+{
+ static const UChar digitString[] = {
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0
+ }; /* "0123456789ABCDEF" */
+
+ switch (digits)
+ {
+ case 8:
+ target += digitString[(number >> 28) & 0xF];
+ case 7:
+ target += digitString[(number >> 24) & 0xF];
+ case 6:
+ target += digitString[(number >> 20) & 0xF];
+ case 5:
+ target += digitString[(number >> 16) & 0xF];
+ case 4:
+ target += digitString[(number >> 12) & 0xF];
+ case 3:
+ target += digitString[(number >> 8) & 0xF];
+ case 2:
+ target += digitString[(number >> 4) & 0xF];
+ case 1:
+ target += digitString[(number >> 0) & 0xF];
+ break;
+ default:
+ target += "**";
+ }
+ return target;
+}
+
+// Replace nonprintable characters with unicode escapes
+UnicodeString&
+IntlTest::prettify(const UnicodeString &source,
+ UnicodeString &target)
+{
+ int32_t i;
+
+ target.remove();
+ target += "\"";
+
+ for (i = 0; i < source.length(); )
+ {
+ UChar32 ch = source.char32At(i);
+ i += UTF_CHAR_LENGTH(ch);
+
+ if (ch < 0x09 || (ch > 0x0A && ch < 0x20)|| ch > 0x7E)
+ {
+ if (ch <= 0xFFFF) {
+ target += "\\u";
+ appendHex(ch, 4, target);
+ } else {
+ target += "\\U";
+ appendHex(ch, 8, target);
+ }
+ }
+ else
+ {
+ target += ch;
+ }
+ }
+
+ target += "\"";
+
+ return target;
+}
+
+// Replace nonprintable characters with unicode escapes
+UnicodeString
+IntlTest::prettify(const UnicodeString &source, UBool parseBackslash)
+{
+ int32_t i;
+ UnicodeString target;
+ target.remove();
+ target += "\"";
+
+ for (i = 0; i < source.length();)
+ {
+ UChar32 ch = source.char32At(i);
+ i += UTF_CHAR_LENGTH(ch);
+
+ if (ch < 0x09 || (ch > 0x0A && ch < 0x20)|| ch > 0x7E)
+ {
+ if (parseBackslash) {
+ // If we are preceded by an odd number of backslashes,
+ // then this character has already been backslash escaped.
+ // Delete a backslash.
+ int32_t backslashCount = 0;
+ for (int32_t j=target.length()-1; j>=0; --j) {
+ if (target.charAt(j) == (UChar)92) {
+ ++backslashCount;
+ } else {
+ break;
+ }
+ }
+ if ((backslashCount % 2) == 1) {
+ target.truncate(target.length() - 1);
+ }
+ }
+ if (ch <= 0xFFFF) {
+ target += "\\u";
+ appendHex(ch, 4, target);
+ } else {
+ target += "\\U";
+ appendHex(ch, 8, target);
+ }
+ }
+ else
+ {
+ target += ch;
+ }
+ }
+
+ target += "\"";
+
+ return target;
+}
+
+/* IntlTest::setICU_DATA - if the ICU_DATA environment variable is not already
+ * set, try to deduce the directory in which ICU was built,
+ * and set ICU_DATA to "icu/source/data" in that location.
+ * The intent is to allow the tests to have a good chance
+ * of running without requiring that the user manually set
+ * ICU_DATA. Common data isn't a problem, since it is
+ * picked up via a static (build time) reference, but the
+ * tests dynamically load some data.
+ */
+void IntlTest::setICU_DATA() {
+ const char *original_ICU_DATA = getenv("ICU_DATA");
+
+ if (original_ICU_DATA != NULL && *original_ICU_DATA != 0) {
+ /* If the user set ICU_DATA, don't second-guess the person. */
+ return;
+ }
+
+ // U_TOPBUILDDIR is set by the makefiles on UNIXes when building cintltst and intltst
+ // to point to the top of the build hierarchy, which may or
+ // may not be the same as the source directory, depending on
+ // the configure options used. At any rate,
+ // set the data path to the built data from this directory.
+ // The value is complete with quotes, so it can be used
+ // as-is as a string constant.
+
+#if defined (U_TOPBUILDDIR)
+ {
+ static char env_string[] = U_TOPBUILDDIR "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING;
+ u_setDataDirectory(env_string);
+ return;
+ }
+
+#else
+ // Use #else so we don't get compiler warnings due to the return above.
+
+ /* On Windows, the file name obtained from __FILE__ includes a full path.
+ * This file is "wherever\icu\source\test\cintltst\cintltst.c"
+ * Change to "wherever\icu\source\data"
+ */
+ {
+ char p[sizeof(__FILE__) + 10];
+ char *pBackSlash;
+ int i;
+
+ strcpy(p, __FILE__);
+ /* We want to back over three '\' chars. */
+ /* Only Windows should end up here, so looking for '\' is safe. */
+ for (i=1; i<=3; i++) {
+ pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
+ if (pBackSlash != NULL) {
+ *pBackSlash = 0; /* Truncate the string at the '\' */
+ }
+ }
+
+ if (pBackSlash != NULL) {
+ /* We found and truncated three names from the path.
+ * Now append "source\data" and set the environment
+ */
+ strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
+ u_setDataDirectory(p); /* p is "ICU_DATA=wherever\icu\source\data" */
+ return;
+ }
+ else {
+ /* __FILE__ on MSVC7 does not contain the directory */
+ u_setDataDirectory(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "out" U_FILE_SEP_STRING);
+ return;
+ }
+ }
+#endif
+
+ /* No location for the data dir was identifiable.
+ * Add other fallbacks for the test data location here if the need arises
+ */
+}
+
+
+//--------------------------------------------------------------------------------------
+
+static const int32_t indentLevel_offset = 3;
+static const char delim = '/';
+
+IntlTest* IntlTest::gTest = NULL;
+
+static int32_t execCount = 0;
+
+void it_log( UnicodeString message )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->log( message );
+}
+
+void it_logln( UnicodeString message )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->logln( message );
+}
+
+void it_logln( void )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->logln();
+}
+
+void it_info( UnicodeString message )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->info( message );
+}
+
+void it_infoln( UnicodeString message )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->infoln( message );
+}
+
+void it_infoln( void )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->infoln();
+}
+
+void it_err()
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->err();
+}
+
+void it_err( UnicodeString message )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->err( message );
+}
+
+void it_errln( UnicodeString message )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->errln( message );
+}
+
+void it_dataerr( UnicodeString message )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->dataerr( message );
+}
+
+void it_dataerrln( UnicodeString message )
+{
+ if (IntlTest::gTest)
+ IntlTest::gTest->dataerrln( message );
+}
+
+IntlTest::IntlTest()
+{
+ caller = NULL;
+ testPath = NULL;
+ LL_linestart = TRUE;
+ errorCount = 0;
+ dataErrorCount = 0;
+ verbose = FALSE;
+ no_err_msg = FALSE;
+ warn_on_missing_data = FALSE;
+ quick = FALSE;
+ leaks = FALSE;
+ testoutfp = stdout;
+ LL_indentlevel = indentLevel_offset;
+}
+
+void IntlTest::setCaller( IntlTest* callingTest )
+{
+ caller = callingTest;
+ if (caller) {
+ verbose = caller->verbose;
+ no_err_msg = caller->no_err_msg;
+ quick = caller->quick;
+ testoutfp = caller->testoutfp;
+ LL_indentlevel = caller->LL_indentlevel + indentLevel_offset;
+ }
+}
+
+UBool IntlTest::callTest( IntlTest& testToBeCalled, char* par )
+{
+ execCount--; // correct a previously assumed test-exec, as this only calls a subtest
+ testToBeCalled.setCaller( this );
+ return testToBeCalled.runTest( testPath, par );
+}
+
+void IntlTest::setPath( char* pathVal )
+{
+ this->testPath = pathVal;
+}
+
+UBool IntlTest::setVerbose( UBool verboseVal )
+{
+ UBool rval = this->verbose;
+ this->verbose = verboseVal;
+ return rval;
+}
+
+UBool IntlTest::setWarnOnMissingData( UBool warn_on_missing_dataVal )
+{
+ UBool rval = this->warn_on_missing_data;
+ this->warn_on_missing_data = warn_on_missing_dataVal;
+ return rval;
+}
+
+UBool IntlTest::setNoErrMsg( UBool no_err_msgVal )
+{
+ UBool rval = this->no_err_msg;
+ this->no_err_msg = no_err_msgVal;
+ return rval;
+}
+
+UBool IntlTest::setQuick( UBool quickVal )
+{
+ UBool rval = this->quick;
+ this->quick = quickVal;
+ return rval;
+}
+
+UBool IntlTest::setLeaks( UBool leaksVal )
+{
+ UBool rval = this->leaks;
+ this->leaks = leaksVal;
+ return rval;
+}
+
+int32_t IntlTest::getErrors( void )
+{
+ return errorCount;
+}
+
+int32_t IntlTest::getDataErrors( void )
+{
+ return dataErrorCount;
+}
+
+UBool IntlTest::runTest( char* name, char* par )
+{
+ UBool rval;
+ char* pos = NULL;
+
+ if (name)
+ pos = strchr( name, delim ); // check if name contains path (by looking for '/')
+ if (pos) {
+ testPath = pos+1; // store subpath for calling subtest
+ *pos = 0; // split into two strings
+ }else{
+ testPath = NULL;
+ }
+
+ if (!name || (name[0] == 0) || (strcmp(name, "*") == 0)) {
+ rval = runTestLoop( NULL, par );
+
+ }else if (strcmp( name, "LIST" ) == 0) {
+ this->usage();
+ rval = TRUE;
+
+ }else{
+ rval = runTestLoop( name, par );
+ }
+
+ if (pos)
+ *pos = delim; // restore original value at pos
+ return rval;
+}
+
+// call individual tests, to be overriden to call implementations
+void IntlTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+{
+ // to be overriden by a method like:
+ /*
+ switch (index) {
+ case 0: name = "First Test"; if (exec) FirstTest( par ); break;
+ case 1: name = "Second Test"; if (exec) SecondTest( par ); break;
+ default: name = ""; break;
+ }
+ */
+ this->errln("*** runIndexedTest needs to be overriden! ***");
+ name = ""; exec = exec; index = index; par = par;
+}
+
+
+UBool IntlTest::runTestLoop( char* testname, char* par )
+{
+ int32_t index = 0;
+ const char* name;
+ UBool run_this_test;
+ int32_t lastErrorCount;
+ UBool rval = FALSE;
+ UBool lastTestFailed;
+
+ IntlTest* saveTest = gTest;
+ gTest = this;
+ do {
+ this->runIndexedTest( index, FALSE, name, par );
+ if (!name || (name[0] == 0))
+ break;
+ if (!testname) {
+ run_this_test = TRUE;
+ }else{
+ run_this_test = (UBool) (strcmp( name, testname ) == 0);
+ }
+ if (run_this_test) {
+ lastErrorCount = errorCount;
+ execCount++;
+ this->runIndexedTest( index, TRUE, name, par );
+ rval = TRUE; // at least one test has been called
+ char msg[256];
+ if (lastErrorCount == errorCount) {
+ sprintf( msg, "---OK: %s", name );
+ lastTestFailed = FALSE;
+ }else{
+ sprintf(msg, "---ERRORS (%li) in %s", (long)(errorCount-lastErrorCount), name);
+
+ for(int i=0;i<LL_indentlevel;i++) {
+ errorList += " ";
+ }
+ errorList += name;
+ errorList += "\n";
+ lastTestFailed = TRUE;
+ }
+ LL_indentlevel -= 3;
+ if (lastTestFailed) {
+ LL_message( "", TRUE);
+ }
+ LL_message( msg, TRUE);
+ if (lastTestFailed) {
+ LL_message( "", TRUE);
+ }
+ LL_indentlevel += 3;
+ }
+ index++;
+ }while(name);
+
+ gTest = saveTest;
+ return rval;
+}
+
+
+/**
+* Adds given string to the log if we are in verbose mode.
+*/
+void IntlTest::log( const UnicodeString &message )
+{
+ if( verbose ) {
+ LL_message( message, FALSE );
+ }
+}
+
+/**
+* Adds given string to the log if we are in verbose mode. Adds a new line to
+* the given message.
+*/
+void IntlTest::logln( const UnicodeString &message )
+{
+ if( verbose ) {
+ LL_message( message, TRUE );
+ }
+}
+
+void IntlTest::logln( void )
+{
+ if( verbose ) {
+ LL_message( "", TRUE );
+ }
+}
+
+/**
+* Unconditionally adds given string to the log.
+*/
+void IntlTest::info( const UnicodeString &message )
+{
+ LL_message( message, FALSE );
+}
+
+/**
+* Unconditionally adds given string to the log. Adds a new line to
+* the given message.
+*/
+void IntlTest::infoln( const UnicodeString &message )
+{
+ LL_message( message, TRUE );
+}
+
+void IntlTest::infoln( void )
+{
+ LL_message( "", TRUE );
+}
+
+int32_t IntlTest::IncErrorCount( void )
+{
+ errorCount++;
+ if (caller) caller->IncErrorCount();
+ return errorCount;
+}
+
+int32_t IntlTest::IncDataErrorCount( void )
+{
+ dataErrorCount++;
+ if (caller) caller->IncDataErrorCount();
+ return dataErrorCount;
+}
+
+void IntlTest::err()
+{
+ IncErrorCount();
+}
+
+void IntlTest::err( const UnicodeString &message )
+{
+ IncErrorCount();
+ if (!no_err_msg) LL_message( message, FALSE );
+}
+
+void IntlTest::errln( const UnicodeString &message )
+{
+ IncErrorCount();
+ if (!no_err_msg) LL_message( message, TRUE );
+}
+
+void IntlTest::dataerr( const UnicodeString &message )
+{
+ IncDataErrorCount();
+
+ if (!warn_on_missing_data) {
+ IncErrorCount();
+ }
+
+ if (!no_err_msg) LL_message( message, FALSE );
+}
+
+void IntlTest::dataerrln( const UnicodeString &message )
+{
+ IncDataErrorCount();
+
+ if (!warn_on_missing_data) {
+ IncErrorCount();
+ }
+
+ if (!no_err_msg) LL_message( message, TRUE );
+}
+
+/* convenience functions that include sprintf formatting */
+void IntlTest::log(const char *fmt, ...)
+{
+ char buffer[4000];
+ va_list ap;
+
+ va_start(ap, fmt);
+ /* sprintf it just to make sure that the information is valid */
+ vsprintf(buffer, fmt, ap);
+ va_end(ap);
+ if( verbose ) {
+ log(UnicodeString(buffer, ""));
+ }
+}
+
+void IntlTest::logln(const char *fmt, ...)
+{
+ char buffer[4000];
+ va_list ap;
+
+ va_start(ap, fmt);
+ /* sprintf it just to make sure that the information is valid */
+ vsprintf(buffer, fmt, ap);
+ va_end(ap);
+ if( verbose ) {
+ logln(UnicodeString(buffer, ""));
+ }
+}
+
+/* convenience functions that include sprintf formatting */
+void IntlTest::info(const char *fmt, ...)
+{
+ char buffer[4000];
+ va_list ap;
+
+ va_start(ap, fmt);
+ /* sprintf it just to make sure that the information is valid */
+ vsprintf(buffer, fmt, ap);
+ va_end(ap);
+ info(UnicodeString(buffer, ""));
+}
+
+void IntlTest::infoln(const char *fmt, ...)
+{
+ char buffer[4000];
+ va_list ap;
+
+ va_start(ap, fmt);
+ /* sprintf it just to make sure that the information is valid */
+ vsprintf(buffer, fmt, ap);
+ va_end(ap);
+ infoln(UnicodeString(buffer, ""));
+}
+
+void IntlTest::err(const char *fmt, ...)
+{
+ char buffer[4000];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsprintf(buffer, fmt, ap);
+ va_end(ap);
+ err(UnicodeString(buffer, ""));
+}
+
+void IntlTest::errln(const char *fmt, ...)
+{
+ char buffer[4000];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsprintf(buffer, fmt, ap);
+ va_end(ap);
+ errln(UnicodeString(buffer, ""));
+}
+
+void IntlTest::dataerrln(const char *fmt, ...)
+{
+ char buffer[4000];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsprintf(buffer, fmt, ap);
+ va_end(ap);
+ dataerrln(UnicodeString(buffer, ""));
+}
+
+void IntlTest::printErrors()
+{
+ IntlTest::LL_message(errorList, TRUE);
+}
+
+void IntlTest::LL_message( UnicodeString message, UBool newline )
+{
+ // string that starts with a LineFeed character and continues
+ // with spaces according to the current indentation
+ static const UChar indentUChars[] = {
+ '\n',
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32
+ };
+ UnicodeString indent(FALSE, indentUChars, 1 + LL_indentlevel);
+
+ char buffer[10000];
+ int32_t length;
+
+ // stream out the indentation string first if necessary
+ length = indent.extract(1, indent.length(), buffer, sizeof(buffer));
+ if (length > 0) {
+ fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
+ }
+
+ // replace each LineFeed by the indentation string
+ message.findAndReplace(UnicodeString((UChar)'\n'), indent);
+
+ // stream out the message
+ length = message.extract(0, message.length(), buffer, sizeof(buffer));
+ if (length > 0) {
+ length = length > 10000 ? 10000 : length;
+ fwrite(buffer, sizeof(*buffer), length, (FILE *)testoutfp);
+ }
+
+ if (newline) {
+ char newLine = '\n';
+ fwrite(&newLine, sizeof(newLine), 1, (FILE *)testoutfp);
+ }
+
+ // A newline usually flushes the buffer, but
+ // flush the message just in case of a core dump.
+ fflush((FILE *)testoutfp);
+}
+
+/**
+* Print a usage message for this test class.
+*/
+void IntlTest::usage( void )
+{
+ UBool save_verbose = setVerbose( TRUE );
+ logln("Test names:");
+ logln("-----------");
+
+ int32_t index = 0;
+ const char* name = NULL;
+ do{
+ this->runIndexedTest( index, FALSE, name );
+ if (!name) break;
+ logln(name);
+ index++;
+ }while (name && (name[0] != 0));
+ setVerbose( save_verbose );
+}
+
+
+// memory leak reporting software will be able to take advantage of the testsuite
+// being run a second time local to a specific method in order to report only actual leaks
+UBool
+IntlTest::run_phase2( char* name, char* par ) // supports reporting memory leaks
+{
+ UnicodeString* strLeak = new UnicodeString("forced leak"); // for verifying purify filter
+ strLeak->append(" for verifying purify filter");
+ return this->runTest( name, par );
+}
+
+
+#if UCONFIG_NO_LEGACY_CONVERSION
+# define TRY_CNV_1 "iso-8859-1"
+# define TRY_CNV_2 "ibm-1208"
+#else
+# define TRY_CNV_1 "iso-8859-7"
+# define TRY_CNV_2 "sjis"
+#endif
+
+int
+main(int argc, char* argv[])
+{
+ UBool syntax = FALSE;
+ UBool all = FALSE;
+ UBool verbose = FALSE;
+ UBool no_err_msg = FALSE;
+ UBool quick = TRUE;
+ UBool name = FALSE;
+ UBool leaks = FALSE;
+ UBool warnOnMissingData = FALSE;
+ UBool defaultDataFound = FALSE;
+ UErrorCode errorCode = U_ZERO_ERROR;
+ UConverter *cnv = NULL;
+ const char *warnOrErr = "Failure";
+ UDate startTime, endTime;
+ int32_t diffTime;
+
+ U_MAIN_INIT_ARGS(argc, argv);
+
+ startTime = uprv_getUTCtime();
+
+ for (int i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ const char* str = argv[i] + 1;
+ if (strcmp("verbose", str) == 0 ||
+ strcmp("v", str) == 0)
+ verbose = TRUE;
+ else if (strcmp("noerrormsg", str) == 0 ||
+ strcmp("n", str) == 0)
+ no_err_msg = TRUE;
+ else if (strcmp("exhaustive", str) == 0 ||
+ strcmp("e", str) == 0)
+ quick = FALSE;
+ else if (strcmp("all", str) == 0 ||
+ strcmp("a", str) == 0)
+ all = TRUE;
+ else if (strcmp("leaks", str) == 0 ||
+ strcmp("l", str) == 0)
+ leaks = TRUE;
+ else if (strcmp("w", str) == 0) {
+ warnOnMissingData = TRUE;
+ warnOrErr = "WARNING";
+ }
+ else {
+ syntax = TRUE;
+ }
+ }else{
+ name = TRUE;
+ }
+ }
+
+ if (!all && !name) {
+ all = TRUE;
+ } else if (all && name) {
+ syntax = TRUE;
+ }
+
+ if (syntax) {
+ fprintf(stdout,
+ "### Syntax:\n"
+ "### IntlTest [-option1 -option2 ...] [testname1 testname2 ...] \n"
+ "### where options are: verbose (v), all (a), noerrormsg (n), \n"
+ "### exhaustive (e), leaks (l)"
+ "### (Specify either -all (shortcut -a) or a test name). \n"
+ "### -all will run all of the tests.\n"
+ "### \n"
+ "### To get a list of the test names type: intltest LIST \n"
+ "### To run just the utility tests type: intltest utility \n"
+ "### \n"
+ "### Test names can be nested using slashes (\"testA/subtest1\") \n"
+ "### For example to list the utility tests type: intltest utility/LIST \n"
+ "### To run just the Locale test type: intltest utility/LocaleTest \n"
+ "### \n"
+ "### A parameter can be specified for a test by appending '@' and the value \n"
+ "### to the testname. \n\n");
+ return 1;
+ }
+
+ UBool all_tests_exist = TRUE;
+ MajorTestLevel major;
+ major.setVerbose( verbose );
+ major.setNoErrMsg( no_err_msg );
+ major.setQuick( quick );
+ major.setLeaks( leaks );
+ major.setWarnOnMissingData( warnOnMissingData );
+ fprintf(stdout, "-----------------------------------------------\n");
+ fprintf(stdout, " IntlTest (C++) Test Suite for \n");
+ fprintf(stdout, " International Components for Unicode %s\n", U_ICU_VERSION);
+ fprintf(stdout, "-----------------------------------------------\n");
+ fprintf(stdout, " Options: \n");
+ fprintf(stdout, " all (a) : %s\n", (all? "On" : "Off"));
+ fprintf(stdout, " Verbose (v) : %s\n", (verbose? "On" : "Off"));
+ fprintf(stdout, " No error messages (n) : %s\n", (no_err_msg? "On" : "Off"));
+ fprintf(stdout, " Exhaustive (e) : %s\n", (!quick? "On" : "Off"));
+ fprintf(stdout, " Leaks (l) : %s\n", (leaks? "On" : "Off"));
+ fprintf(stdout, " Warn on missing data (w) : %s\n", (warnOnMissingData? "On" : "Off"));
+ fprintf(stdout, "-----------------------------------------------\n");
+
+ /* Check whether ICU will initialize without forcing the build data directory into
+ * the ICU_DATA path. Success here means either the data dll contains data, or that
+ * this test program was run with ICU_DATA set externally. Failure of this check
+ * is normal when ICU data is not packaged into a shared library.
+ *
+ * Whether or not this test succeeds, we want to cleanup and reinitialize
+ * with a data path so that data loading from individual files can be tested.
+ */
+ u_init(&errorCode);
+ if (U_FAILURE(errorCode)) {
+ fprintf(stderr,
+ "#### Note: ICU Init without build-specific setDataDirectory() failed.\n");
+ defaultDataFound = FALSE;
+ }
+ else {
+ defaultDataFound = TRUE;
+ }
+ u_cleanup();
+ errorCode = U_ZERO_ERROR;
+
+ /* Initialize ICU */
+ if (!defaultDataFound) {
+ IntlTest::setICU_DATA(); // Must set data directory before u_init() is called.
+ }
+ u_init(&errorCode);
+ if (U_FAILURE(errorCode)) {
+ fprintf(stderr,
+ "#### ERROR! %s: u_init() failed with status = \"%s\".\n"
+ "*** Check the ICU_DATA environment variable and \n"
+ "*** check that the data files are present.\n", argv[0], u_errorName(errorCode));
+ if(warnOnMissingData == 0) {
+ fprintf(stderr, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+ u_cleanup();
+ return 1;
+ }
+ }
+
+
+ // initial check for the default converter
+ errorCode = U_ZERO_ERROR;
+ cnv = ucnv_open(0, &errorCode);
+ if(cnv != 0) {
+ // ok
+ ucnv_close(cnv);
+ } else {
+ fprintf(stdout,
+ "*** %s! The default converter [%s] cannot be opened.\n"
+ "*** Check the ICU_DATA environment variable and\n"
+ "*** check that the data files are present.\n",
+ warnOrErr, ucnv_getDefaultName());
+ if(!warnOnMissingData) {
+ fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+ return 1;
+ }
+ }
+
+ // try more data
+ cnv = ucnv_open(TRY_CNV_2, &errorCode);
+ if(cnv != 0) {
+ // ok
+ ucnv_close(cnv);
+ } else {
+ fprintf(stdout,
+ "*** %s! The converter for " TRY_CNV_2 " cannot be opened.\n"
+ "*** Check the ICU_DATA environment variable and \n"
+ "*** check that the data files are present.\n", warnOrErr);
+ if(!warnOnMissingData) {
+ fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+ return 1;
+ }
+ }
+
+ UResourceBundle *rb = ures_open(0, "en", &errorCode);
+ ures_close(rb);
+ if(U_FAILURE(errorCode)) {
+ fprintf(stdout,
+ "*** %s! The \"en\" locale resource bundle cannot be opened.\n"
+ "*** Check the ICU_DATA environment variable and \n"
+ "*** check that the data files are present.\n", warnOrErr);
+ if(!warnOnMissingData) {
+ fprintf(stdout, "*** Exiting. Use the '-w' option if data files were\n*** purposely removed, to continue test anyway.\n");
+ return 1;
+ }
+ }
+
+ Locale originalLocale; // Save the default locale for comparison later on.
+
+ /* TODO: Add option to call u_cleanup and rerun tests. */
+ if (all) {
+ major.runTest();
+ if (leaks) {
+ major.run_phase2( NULL, NULL );
+ }
+ }else{
+ for (int i = 1; i < argc; ++i) {
+ if (argv[i][0] != '-') {
+ char* name = argv[i];
+ fprintf(stdout, "\n=== Handling test: %s: ===\n", name);
+ char* parameter = strchr( name, '@' );
+ if (parameter) {
+ *parameter = 0;
+ parameter += 1;
+ }
+ execCount = 0;
+ UBool res = major.runTest( name, parameter );
+ if (leaks && res) {
+ major.run_phase2( name, parameter );
+ }
+ if (!res || (execCount <= 0)) {
+ fprintf(stdout, "\n---ERROR: Test doesn't exist: %s!\n", name);
+ all_tests_exist = FALSE;
+ }
+ }
+ }
+ }
+
+#if !UCONFIG_NO_FORMATTING
+ CalendarTimeZoneTest::cleanup();
+#endif
+
+ free(_testDataPath);
+ _testDataPath = 0;
+
+ Locale lastDefaultLocale;
+ if (originalLocale != lastDefaultLocale) {
+ major.errln("FAILURE: A test changed the default locale without resetting it.");
+ }
+
+ fprintf(stdout, "\n--------------------------------------\n");
+ if (major.getErrors() == 0) {
+ /* Call it twice to make sure that the defaults were reset. */
+ /* Call it before the OK message to verify proper cleanup. */
+ u_cleanup();
+ u_cleanup();
+
+ fprintf(stdout, "OK: All tests passed without error.\n");
+
+ if (major.getDataErrors() != 0) {
+ fprintf(stdout, "\t*WARNING* some data-loading errors were ignored by the -w option.\n");
+ }
+ }else{
+ fprintf(stdout, "Errors in total: %ld.\n", (long)major.getErrors());
+ major.printErrors();
+
+
+ if (major.getDataErrors() != 0) {
+ fprintf(stdout, "\t*Note* some errors are data-loading related. If the data used is not the \n"
+ "\tstock ICU data (i.e some have been added or removed), consider using\n"
+ "\tthe '-w' option to turn these errors into warnings.\n");
+ }
+
+ /* Call afterwards to display errors. */
+ u_cleanup();
+ }
+
+ fprintf(stdout, "--------------------------------------\n");
+
+ if (execCount <= 0) {
+ fprintf(stdout, "***** Not all called tests actually exist! *****\n");
+ }
+ endTime = uprv_getUTCtime();
+ diffTime = (int32_t)(endTime - startTime);
+ printf("Elapsed Time: %02d:%02d:%02d.%03d\n",
+ (int)((diffTime%U_MILLIS_PER_DAY)/U_MILLIS_PER_HOUR),
+ (int)((diffTime%U_MILLIS_PER_HOUR)/U_MILLIS_PER_MINUTE),
+ (int)((diffTime%U_MILLIS_PER_MINUTE)/U_MILLIS_PER_SECOND),
+ (int)(diffTime%U_MILLIS_PER_SECOND));
+ return major.getErrors();
+}
+
+const char* IntlTest::loadTestData(UErrorCode& err){
+ if( _testDataPath == NULL){
+ const char* directory=NULL;
+ UResourceBundle* test =NULL;
+ char* tdpath=NULL;
+ const char* tdrelativepath;
+
+#if defined (U_TOPBUILDDIR)
+ tdrelativepath = "test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
+ directory = U_TOPBUILDDIR;
+#else
+ tdrelativepath = ".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"out"U_FILE_SEP_STRING;
+ directory = pathToDataDirectory();
+#endif
+
+ tdpath = (char*) malloc(sizeof(char) *(( strlen(directory) * strlen(tdrelativepath)) + 100));
+
+
+ /* u_getDataDirectory shoul return \source\data ... set the
+ * directory to ..\source\data\..\test\testdata\out\testdata
+ */
+ strcpy(tdpath, directory);
+ strcat(tdpath, tdrelativepath);
+ strcat(tdpath,"testdata");
+
+ test=ures_open(tdpath, "testtypes", &err);
+
+ if(U_FAILURE(err)){
+ err = U_FILE_ACCESS_ERROR;
+ it_errln((UnicodeString)"Could not load testtypes.res in testdata bundle with path " + tdpath + (UnicodeString)" - " + u_errorName(err));
+ return "";
+ }
+ ures_close(test);
+ _testDataPath = tdpath;
+ return _testDataPath;
+ }
+ return _testDataPath;
+}
+
+const char* IntlTest::getTestDataPath(UErrorCode& err) {
+ return loadTestData(err);
+}
+
+/* Returns the path to icu/source/test/testdata/ */
+const char *IntlTest::getSourceTestData(UErrorCode& /*err*/) {
+ const char *srcDataDir = NULL;
+#ifdef U_TOPSRCDIR
+ srcDataDir = U_TOPSRCDIR U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
+#else
+ srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
+ FILE *f = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING"rbbitst.txt", "r");
+ if (f) {
+ /* We're in icu/source/test/intltest/ */
+ fclose(f);
+ }
+ else {
+ /* We're in icu/source/test/intltest/(Debug|Release) */
+ srcDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING"test"U_FILE_SEP_STRING"testdata"U_FILE_SEP_STRING;
+ }
+#endif
+ return srcDataDir;
+}
+
+const char* IntlTest::fgDataDir = NULL;
+
+/* returns the path to icu/source/data */
+const char * IntlTest::pathToDataDirectory()
+{
+
+ if(fgDataDir != NULL) {
+ return fgDataDir;
+ }
+
+ /* U_TOPSRCDIR is set by the makefiles on UNIXes when building cintltst and intltst
+ // to point to the top of the build hierarchy, which may or
+ // may not be the same as the source directory, depending on
+ // the configure options used. At any rate,
+ // set the data path to the built data from this directory.
+ // The value is complete with quotes, so it can be used
+ // as-is as a string constant.
+ */
+#if defined (U_TOPSRCDIR)
+ {
+ fgDataDir = U_TOPSRCDIR U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
+ }
+#else
+
+ /* On Windows, the file name obtained from __FILE__ includes a full path.
+ * This file is "wherever\icu\source\test\cintltst\cintltst.c"
+ * Change to "wherever\icu\source\data"
+ */
+ {
+ static char p[sizeof(__FILE__) + 10];
+ char *pBackSlash;
+ int i;
+
+ strcpy(p, __FILE__);
+ /* We want to back over three '\' chars. */
+ /* Only Windows should end up here, so looking for '\' is safe. */
+ for (i=1; i<=3; i++) {
+ pBackSlash = strrchr(p, U_FILE_SEP_CHAR);
+ if (pBackSlash != NULL) {
+ *pBackSlash = 0; /* Truncate the string at the '\' */
+ }
+ }
+
+ if (pBackSlash != NULL) {
+ /* We found and truncated three names from the path.
+ * Now append "source\data" and set the environment
+ */
+ strcpy(pBackSlash, U_FILE_SEP_STRING "data" U_FILE_SEP_STRING );
+ fgDataDir = p;
+ }
+ else {
+ /* __FILE__ on MSVC7 does not contain the directory */
+ FILE *file = fopen(".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "Makefile.in", "r");
+ if (file) {
+ fclose(file);
+ fgDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
+ }
+ else {
+ fgDataDir = ".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING".."U_FILE_SEP_STRING "data" U_FILE_SEP_STRING;
+ }
+ }
+ }
+#endif
+
+ return fgDataDir;
+
+}
+
+/*
+ * This is a variant of cintltst/ccolltst.c:CharsToUChars().
+ * It converts a character string into a UnicodeString, with
+ * unescaping \u sequences.
+ */
+UnicodeString CharsToUnicodeString(const char* chars)
+{
+ UnicodeString str(chars, ""); // Invariant conversion
+ return str.unescape();
+}
+
+UnicodeString ctou(const char* chars) {
+ return CharsToUnicodeString(chars);
+}
+
+#define RAND_M (714025)
+#define RAND_IA (1366)
+#define RAND_IC (150889)
+
+static int32_t RAND_SEED;
+
+/**
+ * Returns a uniform random value x, with 0.0 <= x < 1.0. Use
+ * with care: Does not return all possible values; returns one of
+ * 714,025 values, uniformly spaced. However, the period is
+ * effectively infinite. See: Numerical Recipes, section 7.1.
+ *
+ * @param seedp pointer to seed. Set *seedp to any negative value
+ * to restart the sequence.
+ */
+float IntlTest::random(int32_t* seedp) {
+ static int32_t iy, ir[98];
+ static UBool first=TRUE;
+ int32_t j;
+ if (*seedp < 0 || first) {
+ first = FALSE;
+ if ((*seedp=(RAND_IC-(*seedp)) % RAND_M) < 0) *seedp = -(*seedp);
+ for (j=1;j<=97;++j) {
+ *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
+ ir[j]=(*seedp);
+ }
+ *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
+ iy=(*seedp);
+ }
+ j=(int32_t)(1 + 97.0*iy/RAND_M);
+ U_ASSERT(j>=1 && j<=97);
+ iy=ir[j];
+ *seedp=(RAND_IA*(*seedp)+RAND_IC) % RAND_M;
+ ir[j]=(*seedp);
+ return (float) iy/RAND_M;
+}
+
+/**
+ * Convenience method using a global seed.
+ */
+float IntlTest::random() {
+ return random(&RAND_SEED);
+}
+
+static inline UChar toHex(int32_t i) {
+ return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10)));
+}
+
+static UnicodeString& escape(const UnicodeString& s, UnicodeString& result) {
+ for (int32_t i=0; i<s.length(); ++i) {
+ UChar c = s[i];
+ if (c <= (UChar)0x7F) {
+ result += c;
+ } else {
+ result += (UChar)0x5c;
+ result += (UChar)0x75;
+ result += toHex((c >> 12) & 0xF);
+ result += toHex((c >> 8) & 0xF);
+ result += toHex((c >> 4) & 0xF);
+ result += toHex( c & 0xF);
+ }
+ }
+ return result;
+}
+
+#define VERBOSE_ASSERTIONS
+
+UBool IntlTest::assertTrue(const char* message, UBool condition, UBool quiet) {
+ if (!condition) {
+ errln("FAIL: assertTrue() failed: %s", message);
+ } else if (!quiet) {
+ logln("Ok: %s", message);
+ }
+ return condition;
+}
+
+UBool IntlTest::assertFalse(const char* message, UBool condition, UBool quiet) {
+ if (condition) {
+ errln("FAIL: assertFalse() failed: %s", message);
+ } else if (!quiet) {
+ logln("Ok: %s", message);
+ }
+ return !condition;
+}
+
+UBool IntlTest::assertSuccess(const char* message, UErrorCode ec) {
+ if (U_FAILURE(ec)) {
+ errln("FAIL: %s (%s)", message, u_errorName(ec));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+UBool IntlTest::assertEquals(const char* message,
+ const UnicodeString& expected,
+ const UnicodeString& actual) {
+ if (expected != actual) {
+ errln((UnicodeString)"FAIL: " + message + "; got " +
+ prettify(actual) +
+ "; expected " + prettify(expected));
+ return FALSE;
+ }
+#ifdef VERBOSE_ASSERTIONS
+ else {
+ logln((UnicodeString)"Ok: " + message + "; got " + prettify(actual));
+ }
+#endif
+ return TRUE;
+}
+
+UBool IntlTest::assertEquals(const char* message,
+ const char* expected,
+ const char* actual) {
+ if (uprv_strcmp(expected, actual) != 0) {
+ errln((UnicodeString)"FAIL: " + message + "; got \"" +
+ actual +
+ "\"; expected \"" + expected + "\"");
+ return FALSE;
+ }
+#ifdef VERBOSE_ASSERTIONS
+ else {
+ logln((UnicodeString)"Ok: " + message + "; got \"" + actual + "\"");
+ }
+#endif
+ return TRUE;
+}
+
+#if !UCONFIG_NO_FORMATTING
+UBool IntlTest::assertEquals(const char* message,
+ const Formattable& expected,
+ const Formattable& actual) {
+ if (expected != actual) {
+ errln((UnicodeString)"FAIL: " + message + "; got " +
+ toString(actual) +
+ "; expected " + toString(expected));
+ return FALSE;
+ }
+#ifdef VERBOSE_ASSERTIONS
+ else {
+ logln((UnicodeString)"Ok: " + message + "; got " + toString(actual));
+ }
+#endif
+ return TRUE;
+}
+#endif
+
+static char ASSERT_BUF[256];
+
+static const char* extractToAssertBuf(const UnicodeString& message) {
+ UnicodeString buf;
+ escape(message, buf);
+ buf.extract(0, 0x7FFFFFFF, ASSERT_BUF, sizeof(ASSERT_BUF)-1, 0);
+ ASSERT_BUF[sizeof(ASSERT_BUF)-1] = 0;
+ return ASSERT_BUF;
+}
+
+UBool IntlTest::assertTrue(const UnicodeString& message, UBool condition, UBool quiet) {
+ return assertTrue(extractToAssertBuf(message), condition, quiet);
+}
+
+UBool IntlTest::assertFalse(const UnicodeString& message, UBool condition, UBool quiet) {
+ return assertFalse(extractToAssertBuf(message), condition, quiet);
+}
+
+UBool IntlTest::assertSuccess(const UnicodeString& message, UErrorCode ec) {
+ return assertSuccess(extractToAssertBuf(message), ec);
+}
+
+UBool IntlTest::assertEquals(const UnicodeString& message,
+ const UnicodeString& expected,
+ const UnicodeString& actual) {
+ return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+
+UBool IntlTest::assertEquals(const UnicodeString& message,
+ const char* expected,
+ const char* actual) {
+ return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+//--------------------------------------------------------------------
+// Time bomb - allows temporary behavior that expires at a given
+// release
+//--------------------------------------------------------------------
+
+UBool IntlTest::isICUVersionAtLeast(const UVersionInfo x) {
+ UVersionInfo v;
+ u_getVersion(v);
+ return (uprv_memcmp(v, x, U_MAX_VERSION_LENGTH) >= 0);
+}
+
+#if !UCONFIG_NO_FORMATTING
+UBool IntlTest::assertEquals(const UnicodeString& message,
+ const Formattable& expected,
+ const Formattable& actual) {
+ return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+#endif
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/intltest.h b/Build/source/libs/icu/icu-xetex/test/intltest/intltest.h
new file mode 100644
index 00000000000..975893ba93d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/intltest.h
@@ -0,0 +1,250 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+/**
+ * IntlTest is a base class for tests. */
+
+#ifndef _INTLTEST
+#define _INTLTEST
+
+// The following includes utypes.h, uobject.h and unistr.h
+#include "unicode/fmtable.h"
+#include "unicode/testlog.h"
+
+U_NAMESPACE_USE
+
+#ifdef OS390
+// avoid collision with math.h/log()
+// this must be after including utypes.h so that OS390 is actually defined
+#pragma map(IntlTest::log( const UnicodeString &message ),"logos390")
+#endif
+
+//-----------------------------------------------------------------------------
+//convenience classes to ease porting code that uses the Java
+//string-concatenation operator (moved from findword test by rtg)
+UnicodeString UCharToUnicodeString(UChar c);
+UnicodeString Int64ToUnicodeString(int64_t num);
+//UnicodeString operator+(const UnicodeString& left, int64_t num); // Some compilers don't allow this because of the long type.
+UnicodeString operator+(const UnicodeString& left, long num);
+UnicodeString operator+(const UnicodeString& left, unsigned long num);
+UnicodeString operator+(const UnicodeString& left, double num);
+UnicodeString operator+(const UnicodeString& left, char num);
+UnicodeString operator+(const UnicodeString& left, short num);
+UnicodeString operator+(const UnicodeString& left, int num);
+UnicodeString operator+(const UnicodeString& left, unsigned char num);
+UnicodeString operator+(const UnicodeString& left, unsigned short num);
+UnicodeString operator+(const UnicodeString& left, unsigned int num);
+UnicodeString operator+(const UnicodeString& left, float num);
+#if !UCONFIG_NO_FORMATTING
+UnicodeString toString(const Formattable& f); // liu
+UnicodeString toString(int32_t n);
+#endif
+//-----------------------------------------------------------------------------
+
+// Use the TESTCASE macro in subclasses of IntlTest. Define the
+// runIndexedTest method in this fashion:
+//
+//| void MyTest::runIndexedTest(int32_t index, UBool exec,
+//| const char* &name, char* /*par*/) {
+//| switch (index) {
+//| TESTCASE(0,TestSomething);
+//| TESTCASE(1,TestSomethingElse);
+//| TESTCASE(2,TestAnotherThing);
+//| default: name = ""; break;
+//| }
+//| }
+#define TESTCASE(id,test) \
+ case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ test(); \
+ } \
+ break
+
+class IntlTest : public TestLog {
+public:
+
+ IntlTest();
+
+ virtual UBool runTest( char* name = NULL, char* par = NULL ); // not to be overidden
+
+ virtual UBool setVerbose( UBool verbose = TRUE );
+ virtual UBool setNoErrMsg( UBool no_err_msg = TRUE );
+ virtual UBool setQuick( UBool quick = TRUE );
+ virtual UBool setLeaks( UBool leaks = TRUE );
+ virtual UBool setWarnOnMissingData( UBool warn_on_missing_data = TRUE );
+
+ virtual int32_t getErrors( void );
+ virtual int32_t getDataErrors (void );
+
+ virtual void setCaller( IntlTest* callingTest ); // for internal use only
+ virtual void setPath( char* path ); // for internal use only
+
+ virtual void log( const UnicodeString &message );
+
+ virtual void logln( const UnicodeString &message );
+
+ virtual void logln( void );
+
+ virtual void info( const UnicodeString &message );
+
+ virtual void infoln( const UnicodeString &message );
+
+ virtual void infoln( void );
+
+ virtual void err(void);
+
+ virtual void err( const UnicodeString &message );
+
+ virtual void errln( const UnicodeString &message );
+
+ virtual void dataerr( const UnicodeString &message );
+
+ virtual void dataerrln( const UnicodeString &message );
+
+ // convenience functions: sprintf() + errln() etc.
+ void log(const char *fmt, ...);
+ void logln(const char *fmt, ...);
+ void info(const char *fmt, ...);
+ void infoln(const char *fmt, ...);
+ void err(const char *fmt, ...);
+ void errln(const char *fmt, ...);
+ void dataerr(const char *fmt, ...);
+ void dataerrln(const char *fmt, ...);
+
+ // Print ALL named errors encountered so far
+ void printErrors();
+
+ virtual void usage( void ) ;
+
+ /**
+ * Returns a uniform random value x, with 0.0 <= x < 1.0. Use
+ * with care: Does not return all possible values; returns one of
+ * 714,025 values, uniformly spaced. However, the period is
+ * effectively infinite. See: Numerical Recipes, section 7.1.
+ *
+ * @param seedp pointer to seed. Set *seedp to any negative value
+ * to restart the sequence.
+ */
+ static float random(int32_t* seedp);
+
+ /**
+ * Convenience method using a global seed.
+ */
+ static float random();
+
+ /**
+ * Ascertain the version of ICU. Useful for
+ * time bomb testing
+ */
+ UBool isICUVersionAtLeast(const UVersionInfo x);
+
+protected:
+ /* JUnit-like assertions. Each returns TRUE if it succeeds. */
+ UBool assertTrue(const char* message, UBool condition, UBool quiet=FALSE);
+ UBool assertFalse(const char* message, UBool condition, UBool quiet=FALSE);
+ UBool assertSuccess(const char* message, UErrorCode ec);
+ UBool assertEquals(const char* message, const UnicodeString& expected,
+ const UnicodeString& actual);
+ UBool assertEquals(const char* message, const char* expected,
+ const char* actual);
+#if !UCONFIG_NO_FORMATTING
+ UBool assertEquals(const char* message, const Formattable& expected,
+ const Formattable& actual);
+ UBool assertEquals(const UnicodeString& message, const Formattable& expected,
+ const Formattable& actual);
+#endif
+ UBool assertTrue(const UnicodeString& message, UBool condition, UBool quiet=FALSE);
+ UBool assertFalse(const UnicodeString& message, UBool condition, UBool quiet=FALSE);
+ UBool assertSuccess(const UnicodeString& message, UErrorCode ec);
+ UBool assertEquals(const UnicodeString& message, const UnicodeString& expected,
+ const UnicodeString& actual);
+ UBool assertEquals(const UnicodeString& message, const char* expected,
+ const char* actual);
+
+ virtual void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL ); // overide !
+
+ virtual UBool runTestLoop( char* testname, char* par );
+
+ virtual int32_t IncErrorCount( void );
+
+ virtual int32_t IncDataErrorCount( void );
+
+ virtual UBool callTest( IntlTest& testToBeCalled, char* par );
+
+
+ UBool verbose;
+ UBool no_err_msg;
+ UBool quick;
+ UBool leaks;
+ UBool warn_on_missing_data;
+
+private:
+ UBool LL_linestart;
+ int32_t LL_indentlevel;
+
+ int32_t errorCount;
+ int32_t dataErrorCount;
+ IntlTest* caller;
+ char* testPath; // specifies subtests
+
+ //FILE *testoutfp;
+ void *testoutfp;
+
+protected:
+
+ virtual void LL_message( UnicodeString message, UBool newline );
+
+ // used for collation result reporting, defined here for convenience
+
+ static UnicodeString &prettify(const UnicodeString &source, UnicodeString &target);
+ static UnicodeString prettify(const UnicodeString &source, UBool parseBackslash=FALSE);
+ static UnicodeString &appendHex(uint32_t number, int32_t digits, UnicodeString &target);
+
+public:
+ static void setICU_DATA(); // Set up ICU_DATA if necessary.
+
+ static const char* pathToDataDirectory();
+
+public:
+ UBool run_phase2( char* name, char* par ); // internally, supports reporting memory leaks
+ static const char* loadTestData(UErrorCode& err);
+ virtual const char* getTestDataPath(UErrorCode& err);
+ static const char* getSourceTestData(UErrorCode& err);
+
+// static members
+public:
+ static IntlTest* gTest;
+ static const char* fgDataDir;
+
+};
+
+void it_log( UnicodeString message );
+void it_logln( UnicodeString message );
+void it_logln( void );
+void it_info( UnicodeString message );
+void it_infoln( UnicodeString message );
+void it_infoln( void );
+void it_err(void);
+void it_err( UnicodeString message );
+void it_errln( UnicodeString message );
+void it_dataerr( UnicodeString message );
+void it_dataerrln( UnicodeString message );
+
+/**
+ * This is a variant of cintltst/ccolltst.c:CharsToUChars().
+ * It converts a character string into a UnicodeString, with
+ * unescaping \u sequences.
+ */
+extern UnicodeString CharsToUnicodeString(const char* chars);
+
+/* alias for CharsToUnicodeString */
+extern UnicodeString ctou(const char* chars);
+
+#endif // _INTLTEST
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/intltest.vcproj b/Build/source/libs/icu/icu-xetex/test/intltest/intltest.vcproj
new file mode 100644
index 00000000000..7284d2e15e1
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/intltest.vcproj
@@ -0,0 +1,1269 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="intltest"
+ ProjectGUID="{73632960-B3A6-464D-83A3-4B43365F19B8}"
+ RootNamespace="intltest"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Debug/intltest.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\include;..\..\common;..\..\i18n;..\..\tools\toolutil;..\..\tools\ctestfw"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="true"
+ DisableLanguageExtensions="true"
+ TreatWChar_tAsBuiltInType="true"
+ PrecompiledHeaderFile=".\Debug/intltest.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\Debug/intltest.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Debug/intltest.pdb"
+ SubSystem="1"
+ FixedBaseAddress="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ UseFAT32Workaround="true"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Release/intltest.tlb"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\..\include;..\..\common;..\..\i18n;..\..\tools\toolutil;..\..\tools\ctestfw"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ DisableLanguageExtensions="true"
+ TreatWChar_tAsBuiltInType="true"
+ PrecompiledHeaderFile=".\Release/intltest.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\Release/intltest.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\Release/intltest.pdb"
+ SubSystem="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="break iteration"
+ >
+ <File
+ RelativePath=".\itrbbi.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\itrbbi.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rbbiapts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\rbbiapts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rbbitst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\rbbitst.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="collation"
+ >
+ <File
+ RelativePath=".\allcoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\allcoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\apicoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\apicoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\cntabcol.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\cntabcol.h"
+ >
+ </File>
+ <File
+ RelativePath=".\currcoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\currcoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dadrcoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dadrcoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\decoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\decoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\encoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\encoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\escoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\escoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ficoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ficoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\frcoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\frcoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\g7coll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\g7coll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\itercoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\itercoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\jacoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\jacoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\lcukocol.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\lcukocol.h"
+ >
+ </File>
+ <File
+ RelativePath=".\mnkytst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mnkytst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\regcoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\regcoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\srchtest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\srchtest.h"
+ >
+ </File>
+ <File
+ RelativePath="svccoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath="svccoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\thcoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\thcoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\trcoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\trcoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tscoll.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tscoll.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ucaconf.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ucaconf.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="collections"
+ >
+ <File
+ RelativePath=".\uvectest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\uvectest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\v32test.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\v32test.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="configuration"
+ >
+ <File
+ RelativePath=".\strtest.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\strtest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tsmthred.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\tsmthred.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tsputil.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tsputil.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="data &amp; memory"
+ >
+ <File
+ RelativePath=".\uobjtest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\uobjtest.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="formatting"
+ >
+ <File
+ RelativePath=".\astrotst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\astrotst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\calcasts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\calcasts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\callimts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\callimts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\calregts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\calregts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\caltest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\caltest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\caltztst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\caltztst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dadrcal.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dadrcal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dadrfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dadrfmt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dcfmapts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dcfmapts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dtfmapts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dtfmapts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dtfmrgts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dtfmrgts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dtfmtrtts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dtfmtrtts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dtfmttst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dtfmttst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dtptngts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\dtptngts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\fldset.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\fldset.h"
+ >
+ </File>
+ <File
+ RelativePath=".\incaltst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\incaltst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\itformat.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\itformat.h"
+ >
+ </File>
+ <File
+ RelativePath=".\itrbnf.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\itrbnf.h"
+ >
+ </File>
+ <File
+ RelativePath=".\itrbnfp.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\itrbnfp.h"
+ >
+ </File>
+ <File
+ RelativePath=".\itrbnfrt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\itrbnfrt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\miscdtfm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\miscdtfm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\msfmrgts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\msfmrgts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\nmfmapts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\nmfmapts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\nmfmtrt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\nmfmtrt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\numfmtst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\numfmtst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\numrgts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\numrgts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\pptest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\pptest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sdtfmtts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\sdtfmtts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tchcfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tchcfmt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tfsmalls.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tfsmalls.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tmsgfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tmsgfmt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tsdate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tsdate.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tsdcfmsy.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tsdcfmsy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tsdtfmsy.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tsdtfmsy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tsnmfmt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tsnmfmt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tzbdtest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tzbdtest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tzfmttst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tzfmttst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tzoffloc.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tzoffloc.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tzregts.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tzregts.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tzrulets.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tzrulets.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tztest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tztest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\windttst.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\windttst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\winnmtst.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\winnmtst.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="idna"
+ Filter="*.c,*.h"
+ >
+ <File
+ RelativePath=".\idnaconf.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\idnaconf.h"
+ >
+ </File>
+ <File
+ RelativePath=".\idnaref.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\idnaref.h"
+ >
+ </File>
+ <File
+ RelativePath=".\nptrans.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\nptrans.h"
+ >
+ </File>
+ <File
+ RelativePath=".\punyref.c"
+ >
+ </File>
+ <File
+ RelativePath=".\punyref.h"
+ >
+ </File>
+ <File
+ RelativePath=".\testidn.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\testidna.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\testidna.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="locales &amp; resources"
+ >
+ <File
+ RelativePath=".\aliastst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\aliastst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\loctest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\loctest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\restest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\restest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\restsnew.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\restsnew.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="misc"
+ >
+ <File
+ RelativePath=".\intltest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\intltest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\itmajor.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\itmajor.h"
+ >
+ </File>
+ <File
+ RelativePath=".\itutil.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\itutil.h"
+ >
+ </File>
+ <File
+ RelativePath=".\testutil.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\testutil.h"
+ >
+ </File>
+ <File
+ RelativePath=".\textfile.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\textfile.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tokiter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tokiter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\winutil.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\winutil.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="normalization"
+ >
+ <File
+ RelativePath=".\canittst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\canittst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\normconf.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\normconf.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tstnorm.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\tstnorm.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tstnrapi.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="properties &amp; sets"
+ >
+ <File
+ RelativePath=".\ucdtest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ucdtest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\usettest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\usettest.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="regex"
+ >
+ <File
+ RelativePath=".\regextst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\regextst.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="registration"
+ >
+ <File
+ RelativePath=".\icusvtst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\icusvtst.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="strings"
+ >
+ <File
+ RelativePath=".\citrtest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\citrtest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\reptest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\reptest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sfwdchit.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\sfwdchit.h"
+ >
+ </File>
+ <File
+ RelativePath=".\strcase.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ustrtest.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableLanguageExtensions="false"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\ustrtest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\utxttest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\utxttest.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="transforms"
+ >
+ <File
+ RelativePath=".\cpdtrtst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\cpdtrtst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ittrans.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ittrans.h"
+ >
+ </File>
+ <File
+ RelativePath=".\jamotest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\jamotest.h"
+ >
+ </File>
+ <File
+ RelativePath=".\transapi.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\transapi.h"
+ >
+ </File>
+ <File
+ RelativePath=".\transrt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\transrt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\transtst.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\transtst.h"
+ >
+ </File>
+ <File
+ RelativePath=".\trnserr.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\trnserr.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="conversion"
+ >
+ <File
+ RelativePath=".\convtest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\convtest.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="charset detection"
+ >
+ <File
+ RelativePath=".\csdetest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\csdetest.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itercoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/itercoll.cpp
new file mode 100644
index 00000000000..5a0078b1494
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itercoll.cpp
@@ -0,0 +1,647 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/unistr.h"
+#include "unicode/sortkey.h"
+#include "itercoll.h"
+#include "unicode/schriter.h"
+#include "unicode/chariter.h"
+#include "unicode/uchar.h"
+#include "cmemory.h"
+
+#define ARRAY_LENGTH(array) (sizeof array / sizeof array[0])
+
+static UErrorCode status = U_ZERO_ERROR;
+
+CollationIteratorTest::CollationIteratorTest()
+ : test1("What subset of all possible test cases?", ""),
+ test2("has the highest probability of detecting", "")
+{
+ en_us = (RuleBasedCollator *)Collator::createInstance(Locale::getUS(), status);
+ if(U_FAILURE(status)) {
+ delete en_us;
+ en_us = 0;
+ errln("Collator creation failed with %s", u_errorName(status));
+ return;
+ }
+
+}
+
+CollationIteratorTest::~CollationIteratorTest()
+{
+ delete en_us;
+}
+
+/**
+ * Test for CollationElementIterator previous and next for the whole set of
+ * unicode characters.
+ */
+void CollationIteratorTest::TestUnicodeChar()
+{
+ CollationElementIterator *iter;
+ UChar codepoint;
+ UnicodeString source;
+
+ for (codepoint = 1; codepoint < 0xFFFE;)
+ {
+ source.remove();
+
+ while (codepoint % 0xFF != 0)
+ {
+ if (u_isdefined(codepoint))
+ source += codepoint;
+ codepoint ++;
+ }
+
+ if (u_isdefined(codepoint))
+ source += codepoint;
+
+ if (codepoint != 0xFFFF)
+ codepoint ++;
+
+ iter = en_us->createCollationElementIterator(source);
+ /* A basic test to see if it's working at all */
+ backAndForth(*iter);
+ delete iter;
+ }
+}
+
+/**
+ * Test for CollationElementIterator.previous()
+ *
+ * @bug 4108758 - Make sure it works with contracting characters
+ *
+ */
+void CollationIteratorTest::TestPrevious(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ CollationElementIterator *iter = en_us->createCollationElementIterator(test1);
+
+ // A basic test to see if it's working at all
+ backAndForth(*iter);
+ delete iter;
+
+ // Test with a contracting character sequence
+ UnicodeString source;
+ RuleBasedCollator *c1 = NULL;
+ c1 = new RuleBasedCollator(
+ (UnicodeString)"&a,A < b,B < c,C, d,D < z,Z < ch,cH,Ch,CH", status);
+
+ if (c1 == NULL || U_FAILURE(status))
+ {
+ errln("Couldn't create a RuleBasedCollator with a contracting sequence.");
+ delete c1;
+ return;
+ }
+
+ source = "abchdcba";
+ iter = c1->createCollationElementIterator(source);
+ backAndForth(*iter);
+ delete iter;
+ delete c1;
+
+ // Test with an expanding character sequence
+ RuleBasedCollator *c2 = NULL;
+ c2 = new RuleBasedCollator((UnicodeString)"&a < b < c/abd < d", status);
+
+ if (c2 == NULL || U_FAILURE(status))
+ {
+ errln("Couldn't create a RuleBasedCollator with an expanding sequence.");
+ delete c2;
+ return;
+ }
+
+ source = "abcd";
+ iter = c2->createCollationElementIterator(source);
+ backAndForth(*iter);
+ delete iter;
+ delete c2;
+
+ // Now try both
+ RuleBasedCollator *c3 = NULL;
+ c3 = new RuleBasedCollator((UnicodeString)"&a < b < c/aba < d < z < ch", status);
+
+ if (c3 == NULL || U_FAILURE(status))
+ {
+ errln("Couldn't create a RuleBasedCollator with both an expanding and a contracting sequence.");
+ delete c3;
+ return;
+ }
+
+ source = "abcdbchdc";
+ iter = c3->createCollationElementIterator(source);
+ backAndForth(*iter);
+ delete iter;
+ delete c3;
+
+ status=U_ZERO_ERROR;
+ source= CharsToUnicodeString("\\u0e41\\u0e02\\u0e41\\u0e02\\u0e27abc");
+
+ Collator *c4 = Collator::createInstance(Locale("th", "TH", ""), status);
+ if(U_FAILURE(status)){
+ errln("Couldn't create a collator");
+ }
+ iter = ((RuleBasedCollator*)c4)->createCollationElementIterator(source);
+ backAndForth(*iter);
+ delete iter;
+ delete c4;
+
+ source= CharsToUnicodeString("\\u0061\\u30CF\\u3099\\u30FC");
+ Collator *c5 = Collator::createInstance(Locale("ja", "JP", ""), status);
+
+ iter = ((RuleBasedCollator*)c5)->createCollationElementIterator(source);
+ if(U_FAILURE(status)){
+ errln("Couldn't create Japanese collator\n");
+ }
+ backAndForth(*iter);
+ delete iter;
+ delete c5;
+}
+
+/**
+ * Test for getOffset() and setOffset()
+ */
+void CollationIteratorTest::TestOffset(/* char* par */)
+{
+ CollationElementIterator *iter = en_us->createCollationElementIterator(test1);
+ UErrorCode status = U_ZERO_ERROR;
+ // testing boundaries
+ iter->setOffset(0, status);
+ if (U_FAILURE(status) || iter->previous(status) != UCOL_NULLORDER) {
+ errln("Error: After setting offset to 0, we should be at the end "
+ "of the backwards iteration");
+ }
+ iter->setOffset(test1.length(), status);
+ if (U_FAILURE(status) || iter->next(status) != UCOL_NULLORDER) {
+ errln("Error: After setting offset to end of the string, we should "
+ "be at the end of the backwards iteration");
+ }
+
+ // Run all the way through the iterator, then get the offset
+ int32_t orderLength = 0;
+ int32_t *orders = getOrders(*iter, orderLength);
+
+ int32_t offset = iter->getOffset();
+
+ if (offset != test1.length())
+ {
+ UnicodeString msg1("offset at end != length: ");
+ UnicodeString msg2(" vs ");
+
+ errln(msg1 + offset + msg2 + test1.length());
+ }
+
+ // Now set the offset back to the beginning and see if it works
+ CollationElementIterator *pristine = en_us->createCollationElementIterator(test1);
+
+ iter->setOffset(0, status);
+
+ if (U_FAILURE(status))
+ {
+ errln("setOffset failed.");
+ }
+ else
+ {
+ assertEqual(*iter, *pristine);
+ }
+
+ // TODO: try iterating halfway through a messy string.
+
+ delete pristine;
+ delete[] orders;
+ delete iter;
+}
+
+/**
+ * Test for setText()
+ */
+void CollationIteratorTest::TestSetText(/* char* par */)
+{
+ CollationElementIterator *iter1 = en_us->createCollationElementIterator(test1);
+ CollationElementIterator *iter2 = en_us->createCollationElementIterator(test2);
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Run through the second iterator just to exercise it
+ int32_t c = iter2->next(status);
+ int32_t i = 0;
+
+ while ( ++i < 10 && c != CollationElementIterator::NULLORDER)
+ {
+ if (U_FAILURE(status))
+ {
+ errln("iter2->next() returned an error.");
+ delete iter2;
+ delete iter1;
+ }
+
+ c = iter2->next(status);
+ }
+
+ // Now set it to point to the same string as the first iterator
+ iter2->setText(test1, status);
+
+ if (U_FAILURE(status))
+ {
+ errln("call to iter2->setText(test1) failed.");
+ }
+ else
+ {
+ assertEqual(*iter1, *iter2);
+ }
+ iter1->reset();
+ //now use the overloaded setText(ChracterIterator&, UErrorCode) function to set the text
+ CharacterIterator* chariter = new StringCharacterIterator(test1);
+ iter2->setText(*chariter, status);
+ if (U_FAILURE(status))
+ {
+ errln("call to iter2->setText(chariter(test1)) failed.");
+ }
+ else
+ {
+ assertEqual(*iter1, *iter2);
+ }
+
+ // test for an empty string
+ UnicodeString empty("");
+ iter1->setText(empty, status);
+ if (U_FAILURE(status)
+ || iter1->next(status) != (int32_t)UCOL_NULLORDER) {
+ errln("Empty string should have no CEs.");
+ }
+ ((StringCharacterIterator *)chariter)->setText(empty);
+ iter1->setText(*chariter, status);
+ if (U_FAILURE(status)
+ || iter1->next(status) != (int32_t)UCOL_NULLORDER) {
+ errln("Empty string should have no CEs.");
+ }
+ delete chariter;
+ delete iter2;
+ delete iter1;
+}
+
+/** @bug 4108762
+ * Test for getMaxExpansion()
+ */
+void CollationIteratorTest::TestMaxExpansion(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString rule("&a < ab < c/aba < d < z < ch");
+ RuleBasedCollator *coll = new RuleBasedCollator(rule, status);
+ UChar ch = 0;
+ UnicodeString str(ch);
+
+ CollationElementIterator *iter = coll->createCollationElementIterator(str);
+
+ while (ch < 0xFFFF && U_SUCCESS(status)) {
+ int count = 1;
+ uint32_t order;
+ ch ++;
+ UnicodeString str(ch);
+ iter->setText(str, status);
+ order = iter->previous(status);
+
+ /* thai management */
+ if (CollationElementIterator::isIgnorable(order))
+ order = iter->previous(status);
+
+ while (U_SUCCESS(status)
+ && iter->previous(status) != (int32_t)UCOL_NULLORDER)
+ {
+ count ++;
+ }
+
+ if (U_FAILURE(status) && iter->getMaxExpansion(order) < count) {
+ errln("Failure at codepoint %d, maximum expansion count < %d\n",
+ ch, count);
+ }
+ }
+
+ delete iter;
+ delete coll;
+}
+
+/*
+ * @bug 4157299
+ */
+void CollationIteratorTest::TestClearBuffers(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *c = new RuleBasedCollator((UnicodeString)"&a < b < c & ab = d", status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Couldn't create a RuleBasedCollator.");
+ delete c;
+ return;
+ }
+
+ UnicodeString source("abcd");
+ CollationElementIterator *i = c->createCollationElementIterator(source);
+ int32_t e0 = i->next(status); // save the first collation element
+
+ if (U_FAILURE(status))
+ {
+ errln("call to i->next() failed. err=%s", u_errorName(status));
+ }
+ else
+ {
+ i->setOffset(3, status); // go to the expanding character
+
+ if (U_FAILURE(status))
+ {
+ errln("call to i->setOffset(3) failed. err=%s", u_errorName(status));
+ }
+ else
+ {
+ i->next(status); // but only use up half of it
+
+ if (U_FAILURE(status))
+ {
+ errln("call to i->next() failed. err=%s", u_errorName(status));
+ }
+ else
+ {
+ i->setOffset(0, status); // go back to the beginning
+
+ if (U_FAILURE(status))
+ {
+ errln("call to i->setOffset(0) failed. err=%s", u_errorName(status));
+ }
+ else
+ {
+ int32_t e = i->next(status); // and get this one again
+
+ if (U_FAILURE(status))
+ {
+ errln("call to i->next() failed. err=%s", u_errorName(status));
+ }
+ else if (e != e0)
+ {
+ errln("got 0x%X, expected 0x%X", e, e0);
+ }
+ }
+ }
+ }
+ }
+
+ delete i;
+ delete c;
+}
+
+/**
+ * Testing the assignment operator
+ */
+void CollationIteratorTest::TestAssignment()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *coll =
+ (RuleBasedCollator *)Collator::createInstance(status);
+
+ if (coll == NULL || U_FAILURE(status))
+ {
+ errln("Couldn't create a default collator.");
+ return;
+ }
+
+ UnicodeString source("abcd");
+ CollationElementIterator *iter1 =
+ coll->createCollationElementIterator(source);
+
+ CollationElementIterator iter2 = *iter1;
+
+ if (*iter1 != iter2) {
+ errln("Fail collation iterator assignment does not produce the same elements");
+ }
+
+ CollationElementIterator iter3(*iter1);
+
+ if (*iter1 != iter3) {
+ errln("Fail collation iterator copy constructor does not produce the same elements");
+ }
+
+ source = CharsToUnicodeString("a\\u0300\\u0325");
+ coll->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ CollationElementIterator *iter4
+ = coll->createCollationElementIterator(source);
+ CollationElementIterator iter5(*iter4);
+ if (*iter4 != iter5) {
+ errln("collation iterator assignment does not produce the same elements");
+ }
+ iter4->next(status);
+ if (U_FAILURE(status) || *iter4 == iter5) {
+ errln("collation iterator not equal");
+ }
+ iter5.next(status);
+ if (U_FAILURE(status) || *iter4 != iter5) {
+ errln("collation iterator equal");
+ }
+ iter4->next(status);
+ if (U_FAILURE(status) || *iter4 == iter5) {
+ errln("collation iterator not equal");
+ }
+ iter5.next(status);
+ if (U_FAILURE(status) || *iter4 != iter5) {
+ errln("collation iterator equal");
+ }
+ CollationElementIterator iter6(*iter4);
+ if (*iter4 != iter6) {
+ errln("collation iterator equal");
+ }
+ iter4->next(status);
+ if (U_FAILURE(status) || *iter4 == iter5) {
+ errln("collation iterator not equal");
+ }
+ iter5.next(status);
+ if (U_FAILURE(status) || *iter4 != iter5) {
+ errln("collation iterator equal");
+ }
+ iter4->next(status);
+ if (U_FAILURE(status) || *iter4 == iter5) {
+ errln("collation iterator not equal");
+ }
+ iter5.next(status);
+ if (U_FAILURE(status) || *iter4 != iter5) {
+ errln("collation iterator equal");
+ }
+ delete iter1;
+ delete iter4;
+ delete coll;
+}
+
+/**
+ * Testing the constructors
+ */
+void CollationIteratorTest::TestConstructors()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *coll =
+ (RuleBasedCollator *)Collator::createInstance(status);
+ if (coll == NULL || U_FAILURE(status))
+ {
+ errln("Couldn't create a default collator.");
+ return;
+ }
+
+ // testing protected constructor with character iterator as argument
+ StringCharacterIterator chariter(test1);
+ CollationElementIterator *iter1 =
+ coll->createCollationElementIterator(chariter);
+ if (U_FAILURE(status)) {
+ errln("Couldn't create collation element iterator with character iterator.");
+ return;
+ }
+ CollationElementIterator *iter2 =
+ coll->createCollationElementIterator(test1);
+
+ // initially the 2 collation element iterators should be the same
+ if (*iter1 != *iter1 || *iter2 != *iter2 || *iter1 != *iter2
+ || *iter2 != *iter1) {
+ errln("CollationElementIterators constructed with the same string data should be the same at the start");
+ }
+ assertEqual(*iter1, *iter2);
+
+ delete iter1;
+ delete iter2;
+
+ // tests empty strings
+ UnicodeString empty("");
+ iter1 = coll->createCollationElementIterator(empty);
+ chariter.setText(empty);
+ iter2 = coll->createCollationElementIterator(chariter);
+ if (*iter1 != *iter1 || *iter2 != *iter2 || *iter1 != *iter2
+ || *iter2 != *iter1) {
+ errln("CollationElementIterators constructed with the same string data should be the same at the start");
+ }
+ if (iter1->next(status) != (int32_t)UCOL_NULLORDER) {
+ errln("Empty string should have no CEs.");
+ }
+ if (iter2->next(status) != (int32_t)UCOL_NULLORDER) {
+ errln("Empty string should have no CEs.");
+ }
+ delete iter1;
+ delete iter2;
+ delete coll;
+}
+
+/**
+ * Testing the strength order
+ */
+void CollationIteratorTest::TestStrengthOrder()
+{
+ int order = 0x0123ABCD;
+
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *coll =
+ (RuleBasedCollator *)Collator::createInstance(status);
+ if (coll == NULL || U_FAILURE(status))
+ {
+ errln("Couldn't create a default collator.");
+ return;
+ }
+
+ coll->setStrength(Collator::PRIMARY);
+ CollationElementIterator *iter =
+ coll->createCollationElementIterator(test1);
+
+ if (iter == NULL) {
+ errln("Couldn't create a collation element iterator from default collator");
+ return;
+ }
+
+ if (iter->strengthOrder(order) != 0x01230000) {
+ errln("Strength order for a primary strength collator should be the first 2 bytes");
+ return;
+ }
+
+ coll->setStrength(Collator::SECONDARY);
+ if (iter->strengthOrder(order) != 0x0123AB00) {
+ errln("Strength order for a secondary strength collator should be the third byte");
+ return;
+ }
+
+ coll->setStrength(Collator::TERTIARY);
+ if (iter->strengthOrder(order) != order) {
+ errln("Strength order for a tertiary strength collator should be the third byte");
+ return;
+ }
+ delete iter;
+ delete coll;
+}
+
+/**
+ * Return a string containing all of the collation orders
+ * returned by calls to next on the specified iterator
+ */
+UnicodeString &CollationIteratorTest::orderString(CollationElementIterator &iter, UnicodeString &target)
+{
+ int32_t order;
+ UErrorCode status = U_ZERO_ERROR;
+
+ while ((order = iter.next(status)) != CollationElementIterator::NULLORDER)
+ {
+ target += "0x";
+ appendHex(order, 8, target);
+ target += " ";
+ }
+
+ return target;
+}
+
+void CollationIteratorTest::assertEqual(CollationElementIterator &i1, CollationElementIterator &i2)
+{
+ int32_t c1, c2, count = 0;
+ UErrorCode status = U_ZERO_ERROR;
+
+ do
+ {
+ c1 = i1.next(status);
+ c2 = i2.next(status);
+
+ if (c1 != c2)
+ {
+ errln(" %d: strength(0x%X) != strength(0x%X)", count, c1, c2);
+ break;
+ }
+
+ count += 1;
+ }
+ while (c1 != CollationElementIterator::NULLORDER);
+}
+
+void CollationIteratorTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/)
+{
+ if (exec)
+ {
+ logln("Collation Iteration Tests: ");
+ }
+
+ if(en_us) {
+ switch (index)
+ {
+ case 0: name = "TestPrevious"; if (exec) TestPrevious(/* par */); break;
+ case 1: name = "TestOffset"; if (exec) TestOffset(/* par */); break;
+ case 2: name = "TestSetText"; if (exec) TestSetText(/* par */); break;
+ case 3: name = "TestMaxExpansion"; if (exec) TestMaxExpansion(/* par */); break;
+ case 4: name = "TestClearBuffers"; if (exec) TestClearBuffers(/* par */); break;
+ case 5: name = "TestUnicodeChar"; if (exec) TestUnicodeChar(/* par */); break;
+ case 6: name = "TestAssignment"; if (exec) TestAssignment(/* par */); break;
+ case 7: name = "TestConstructors"; if (exec) TestConstructors(/* par */); break;
+ case 8: name = "TestStrengthOrder"; if (exec) TestStrengthOrder(/* par */); break;
+ default: name = ""; break;
+ }
+ } else {
+ errln("Class iterator not instantiated");
+ name = "";
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itercoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/itercoll.h
new file mode 100644
index 00000000000..747f80f6689
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itercoll.h
@@ -0,0 +1,119 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * Collation Iterator tests.
+ * (Let me reiterate my position...)
+ */
+
+#ifndef _ITERCOLL
+#define _ITERCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "tscoll.h"
+
+class CollationIteratorTest: public IntlTestCollator
+{
+public:
+
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationIteratorTest();
+ virtual ~CollationIteratorTest();
+
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL);
+
+ /**
+ * Test that results from CollationElementIterator.next is equivalent to
+ * the reversed results from CollationElementIterator.previous, for the set
+ * of BMP characters.
+ */
+ void TestUnicodeChar();
+
+ /**
+ * Test for CollationElementIterator.previous()
+ *
+ * @bug 4108758 - Make sure it works with contracting characters
+ *
+ */
+ void TestPrevious(/* char* par */);
+
+ /**
+ * Test for getOffset() and setOffset()
+ */
+ void TestOffset(/* char* par */);
+
+ /**
+ * Test for setText()
+ */
+ void TestSetText(/* char* par */);
+
+ /** @bug 4108762
+ * Test for getMaxExpansion()
+ */
+ void TestMaxExpansion(/* char* par */);
+
+ /*
+ * @bug 4157299
+ */
+ void TestClearBuffers(/* char* par */);
+
+ /**
+ * Testing the assignment operator
+ */
+ void TestAssignment();
+
+ /**
+ * Testing the constructors
+ */
+ void TestConstructors();
+
+ /**
+ * Testing the strength order functionality
+ */
+ void TestStrengthOrder();
+
+ //------------------------------------------------------------------------
+ // Internal utilities
+ //
+
+private:
+
+ struct ExpansionRecord
+ {
+ UChar character;
+ int32_t count;
+ };
+
+ /**
+ * Verify that getMaxExpansion works on a given set of collation rules
+ */
+ void verifyExpansion(UnicodeString rules, ExpansionRecord tests[], int32_t testCount);
+
+ /**
+ * Return a string containing all of the collation orders
+ * returned by calls to next on the specified iterator
+ */
+ UnicodeString &orderString(CollationElementIterator &iter, UnicodeString &target);
+
+ void assertEqual(CollationElementIterator &i1, CollationElementIterator &i2);
+
+ RuleBasedCollator *en_us;
+ const UnicodeString test1;
+ const UnicodeString test2;
+
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itformat.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/itformat.cpp
new file mode 100644
index 00000000000..eb80bad7c14
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itformat.cpp
@@ -0,0 +1,132 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * IntlTestFormat is the medium level test class for everything in the directory "format".
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "itformat.h"
+#include "tsdate.h"
+#include "tsnmfmt.h"
+#include "caltest.h"
+#include "callimts.h"
+#include "tztest.h"
+#include "tzbdtest.h"
+#include "tsdcfmsy.h" // DecimalFormatSymbols
+#include "tchcfmt.h"
+#include "tsdtfmsy.h" // DateFormatSymbols
+#include "dcfmapts.h" // DecimalFormatAPI
+#include "tfsmalls.h" // Format Small Classes
+#include "nmfmapts.h" // NumberFormatAPI
+#include "numfmtst.h" // NumberFormatTest
+#include "sdtfmtts.h" // SimpleDateFormatAPI
+#include "dtfmapts.h" // DateFormatAPI
+#include "dtfmttst.h" // DateFormatTest
+#include "tmsgfmt.h" // TestMessageFormat
+#include "dtfmrgts.h" // DateFormatRegressionTest
+#include "msfmrgts.h" // MessageFormatRegressionTest
+#include "miscdtfm.h" // DateFormatMiscTests
+#include "nmfmtrt.h" // NumberFormatRoundTripTest
+#include "numrgts.h" // NumberFormatRegressionTest
+#include "dtfmtrtts.h" // DateFormatRoundTripTest
+#include "pptest.h" // ParsePositionTest
+#include "calregts.h" // CalendarRegressionTest
+#include "tzregts.h" // TimeZoneRegressionTest
+#include "astrotst.h" // AstroTest
+#include "incaltst.h" // IntlCalendarTest
+#include "calcasts.h" // CalendarCaseTest
+#include "tzrulets.h" // TimeZoneRuleTest
+#include "dadrcal.h" // DataDrivenCalendarTest
+#include "dadrfmt.h" // DataDrivenFormatTest
+#include "dtptngts.h" // IntlTestDateTimePatternGeneratorAPI
+#include "tzoffloc.h" // TimeZoneOffsetLocalTest
+#include "tzfmttst.h" // TimeZoneFormatTest
+
+
+#define TESTCLASS(id, TestClass) \
+ case id: \
+ name = #TestClass; \
+ if (exec) { \
+ logln(#TestClass " test---"); \
+ logln((UnicodeString)""); \
+ TestClass test; \
+ callTest(test, par); \
+ } \
+ break
+
+void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+{
+ // for all format tests, always set default Locale and TimeZone to ENGLISH and PST.
+ TimeZone* saveDefaultTimeZone = NULL;
+ Locale saveDefaultLocale = Locale::getDefault();
+ if (exec) {
+ saveDefaultTimeZone = TimeZone::createDefault();
+ TimeZone *tz = TimeZone::createTimeZone("PST");
+ TimeZone::setDefault(*tz);
+ delete tz;
+ UErrorCode status = U_ZERO_ERROR;
+ Locale::setDefault( Locale::getEnglish(), status );
+ if (U_FAILURE(status)) {
+ errln("itformat: couldn't set default Locale to ENGLISH!");
+ }
+ }
+ if (exec) logln("TestSuite Format: ");
+ switch (index) {
+ TESTCLASS(0,IntlTestDateFormat);
+ TESTCLASS(1,IntlTestNumberFormat);
+ TESTCLASS(2,CalendarTest);
+ TESTCLASS(3,CalendarLimitTest);
+ TESTCLASS(4,TimeZoneTest);
+ TESTCLASS(5,TimeZoneBoundaryTest);
+ TESTCLASS(6,TestChoiceFormat);
+ TESTCLASS(7,IntlTestDecimalFormatSymbols);
+ TESTCLASS(8,IntlTestDateFormatSymbols);
+ TESTCLASS(9,IntlTestDecimalFormatAPI);
+ TESTCLASS(10,TestFormatSmallClasses);
+ TESTCLASS(11,IntlTestNumberFormatAPI);
+ TESTCLASS(12,IntlTestSimpleDateFormatAPI);
+ TESTCLASS(13,IntlTestDateFormatAPI);
+ TESTCLASS(14,DateFormatTest);
+ TESTCLASS(15,TestMessageFormat);
+ TESTCLASS(16,NumberFormatTest);
+ TESTCLASS(17,DateFormatRegressionTest);
+ TESTCLASS(18,MessageFormatRegressionTest);
+ TESTCLASS(19,DateFormatMiscTests);
+ TESTCLASS(20,NumberFormatRoundTripTest);
+ TESTCLASS(21,NumberFormatRegressionTest);
+ TESTCLASS(22,DateFormatRoundTripTest);
+ TESTCLASS(23,ParsePositionTest);
+ TESTCLASS(24,CalendarRegressionTest);
+ TESTCLASS(25,TimeZoneRegressionTest);
+ TESTCLASS(26,IntlCalendarTest);
+ TESTCLASS(27,AstroTest);
+ TESTCLASS(28,CalendarCaseTest);
+ TESTCLASS(29,TimeZoneRuleTest);
+ TESTCLASS(30,DataDrivenCalendarTest);
+ TESTCLASS(31,DataDrivenFormatTest);
+ TESTCLASS(32,IntlTestDateTimePatternGeneratorAPI);
+ TESTCLASS(33,TimeZoneOffsetLocalTest);
+ TESTCLASS(34,TimeZoneFormatTest);
+
+
+ default: name = ""; break; //needed to end loop
+ }
+ if (exec) {
+ // restore saved Locale and TimeZone
+ TimeZone::adoptDefault(saveDefaultTimeZone);
+ UErrorCode status = U_ZERO_ERROR;
+ Locale::setDefault( saveDefaultLocale, status );
+ if (U_FAILURE(status)) {
+ errln("itformat: couldn't re-set default Locale!");
+ }
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itformat.h b/Build/source/libs/icu/icu-xetex/test/intltest/itformat.h
new file mode 100644
index 00000000000..1d5d92a57c9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itformat.h
@@ -0,0 +1,27 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * MajorTestLevel is the top level test class for everything in the directory "IntlWork".
+ */
+
+#ifndef _INTLTESTFORMAT
+#define _INTLTESTFORMAT
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+
+class IntlTestFormat: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itmajor.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/itmajor.cpp
new file mode 100644
index 00000000000..97b89ea43cc
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itmajor.cpp
@@ -0,0 +1,203 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1998-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * MajorTestLevel is the top level test class for everything in the directory "IntlWork".
+ */
+
+/***********************************************************************
+* Modification history
+* Date Name Description
+* 02/14/2001 synwee Release collation for testing.
+***********************************************************************/
+
+#include "unicode/utypes.h"
+#include "itmajor.h"
+
+#include "itutil.h"
+#include "tscoll.h"
+#include "itformat.h"
+#include "ittrans.h"
+#include "itrbbi.h"
+#include "itrbnf.h"
+#include "itrbnfp.h"
+#include "itrbnfrt.h"
+#include "normconf.h"
+#include "regextst.h"
+#include "tstnorm.h"
+#include "canittst.h"
+#include "icusvtst.h"
+#include "testidna.h"
+#include "convtest.h"
+#include "csdetest.h"
+
+#define CASE_SUITE(id, suite) case id: \
+ name = #suite; \
+ if(exec) { \
+ logln(#suite "---"); \
+ suite test; \
+ callTest(test, par); \
+ } \
+ break
+
+void MajorTestLevel::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+{
+ switch (index) {
+ case 0: name = "utility";
+ if (exec) {
+ logln("TestSuite Utilities---"); logln();
+ IntlTestUtilities test;
+ callTest( test, par );
+ }
+ break;
+
+ case 1: name = "normalize";
+#if !UCONFIG_NO_NORMALIZATION
+ if (exec) {
+ logln("TestSuite Normalize---"); logln();
+ IntlTestNormalize test;
+ callTest( test, par );
+ }
+#endif
+ break;
+
+ case 2: name = "collate";
+#if !UCONFIG_NO_COLLATION
+ if (exec) {
+ logln("TestSuite Collator---"); logln();
+ IntlTestCollator test;
+ callTest( test, par );
+ }
+#endif
+ break;
+
+ case 3: name = "regex";
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+ if (exec) {
+ logln("TestSuite Regex---"); logln();
+ RegexTest test;
+ callTest( test, par );
+ }
+#endif
+ break;
+
+ case 4: name = "format";
+#if !UCONFIG_NO_FORMATTING
+ if (exec) {
+ logln("TestSuite Format---"); logln();
+ IntlTestFormat test;
+ callTest( test, par );
+ }
+#endif
+ break;
+
+ case 5: name = "translit";
+#if !UCONFIG_NO_TRANSLITERATION
+ if (exec) {
+ logln("TestSuite Transliterator---"); logln();
+ IntlTestTransliterator test;
+ callTest( test, par );
+ }
+#endif
+ break;
+
+ case 6: name = "rbbi";
+#if !UCONFIG_NO_BREAK_ITERATION
+ if (exec) {
+ logln("TestSuite RuleBasedBreakIterator---"); logln();
+ IntlTestRBBI test;
+ callTest( test, par );
+ }
+#endif
+ break;
+ case 7: name = "rbnf";
+#if !UCONFIG_NO_FORMATTING
+ if (exec) {
+ logln("TestSuite RuleBasedNumberFormat----"); logln();
+ IntlTestRBNF test;
+ callTest(test, par);
+ }
+#endif
+ break;
+ case 8: name = "rbnfrt";
+#if !UCONFIG_NO_FORMATTING
+ if (exec) {
+ logln("TestSuite RuleBasedNumberFormat RT----"); logln();
+ RbnfRoundTripTest test;
+ callTest(test, par);
+ }
+#endif
+ break;
+
+ case 9: name = "icuserv";
+#if !UCONFIG_NO_SERVICE
+ if (exec) {
+ logln("TestSuite ICUService---"); logln();
+ ICUServiceTest test;
+ callTest(test, par);
+ }
+#endif
+ break;
+ case 10: name = "idna";
+#if !UCONFIG_NO_IDNA && !UCONFIG_NO_TRANSLITERATION
+ if(exec){
+ logln("TestSuite IDNA----"); logln();
+ TestIDNA test;
+ callTest(test,par);
+ }
+#endif
+ break;
+ case 11: name = "convert";
+#if !UCONFIG_NO_LEGACY_CONVERSION
+ if (exec) {
+ logln("TestSuite Conversion---"); logln();
+ ConversionTest test;
+ callTest( test, par );
+ }
+#endif
+ break;
+
+ case 12: name = "rbnfp";
+#if !UCONFIG_NO_FORMATTING
+ if (exec) {
+ logln("TestSuite RuleBasedNumberParse ----"); logln();
+ IntlTestRBNFParse test;
+ callTest(test, par);
+ }
+#endif
+ break;
+
+ case 13: name = "csdet";
+ if (exec) {
+ logln("TestSuite CharsetDetection---"); logln();
+ CharsetDetectionTest test;
+ callTest(test, par);
+ }
+
+ break;
+
+ default: name = ""; break;
+ }
+
+
+}
+
+void IntlTestNormalize::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+{
+ if(exec) logln("TestSuite Normalize:");
+#if UCONFIG_NO_NORMALIZATION
+ name="";
+#else
+ switch (index) {
+ CASE_SUITE(0, BasicNormalizerTest);
+ CASE_SUITE(1, NormalizerConformanceTest); // this takes a long time
+ CASE_SUITE(2, CanonicalIteratorTest);
+ default:
+ name="";
+ break;
+ }
+#endif
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itmajor.h b/Build/source/libs/icu/icu-xetex/test/intltest/itmajor.h
new file mode 100644
index 00000000000..0527e159172
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itmajor.h
@@ -0,0 +1,26 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * MajorTestLevel is the top level test class for everything in the directory "IntlWork".
+ */
+
+#ifndef _INTLTESTMAJOR
+#define _INTLTESTMAJOR
+
+
+#include "intltest.h"
+
+
+class MajorTestLevel: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+};
+
+class IntlTestNormalize: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itrbbi.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/itrbbi.cpp
new file mode 100644
index 00000000000..75f01cff0d5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itrbbi.cpp
@@ -0,0 +1,48 @@
+/*
+**********************************************************************
+* Copyright (C) 1998-2001, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+*/
+/***********************************************************************
+* Date Name Description
+* 12/14/99 Madhu Creation.
+***********************************************************************/
+/**
+ * IntlTestRBBI is the medium level test class for RuleBasedBreakIterator
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "itrbbi.h"
+#include "rbbiapts.h"
+#include "rbbitst.h"
+
+void IntlTestRBBI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+{
+ if (exec) logln("TestSuite RuleBasedBreakIterator: ");
+ switch (index) {
+ case 0:
+ name = "RBBIAPITest";
+ if (exec) {
+ logln("RBBIAPITest--"); logln("");
+ RBBIAPITest test;
+ callTest( test, par );
+ }
+ break;
+
+ case 1:
+ name = "RBBITest";
+ if (exec) {
+ logln("RBBITest---"); logln("");
+ RBBITest test;
+ callTest( test, par );
+ }
+ break;
+ default: name=""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itrbbi.h b/Build/source/libs/icu/icu-xetex/test/intltest/itrbbi.h
new file mode 100644
index 00000000000..86a2ac4251c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itrbbi.h
@@ -0,0 +1,31 @@
+/*
+**********************************************************************
+* Copyright (C) 1998-2001, International Business Machines Corporation
+* and others. All Rights Reserved.
+**********************************************************************
+************************************************************************
+* Date Name Description
+* 12/14/99 Madhu Creation.
+************************************************************************/
+/**
+ * IntlTestRBBI is the top level test class for the RuleBasedBreakIterator tests
+ */
+
+#ifndef INTLTESTRBBI_H
+#define INTLTESTRBBI_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "intltest.h"
+
+
+class IntlTestRBBI: public IntlTest {
+public:
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+};
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itrbnf.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnf.cpp
new file mode 100644
index 00000000000..58233a39255
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnf.cpp
@@ -0,0 +1,1938 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "itrbnf.h"
+
+#include "unicode/umachine.h"
+
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "unicode/decimfmt.h"
+#include "unicode/udata.h"
+#include "testutil.h"
+
+//#include "llong.h"
+
+#include <string.h>
+
+// import com.ibm.text.RuleBasedNumberFormat;
+// import com.ibm.test.TestFmwk;
+
+// import java.util.Locale;
+// import java.text.NumberFormat;
+
+// current macro not in icu1.8.1
+#define TESTCASE(id,test) \
+ case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ test(); \
+ } \
+ break
+
+void IntlTestRBNF::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/)
+{
+ if (exec) logln("TestSuite RuleBasedNumberFormat");
+ switch (index) {
+#if U_HAVE_RBNF
+ TESTCASE(0, TestEnglishSpellout);
+ TESTCASE(1, TestOrdinalAbbreviations);
+ TESTCASE(2, TestDurations);
+ TESTCASE(3, TestSpanishSpellout);
+ TESTCASE(4, TestFrenchSpellout);
+ TESTCASE(5, TestSwissFrenchSpellout);
+ TESTCASE(6, TestItalianSpellout);
+ TESTCASE(7, TestGermanSpellout);
+ TESTCASE(8, TestThaiSpellout);
+ TESTCASE(9, TestAPI);
+ TESTCASE(10, TestFractionalRuleSet);
+ TESTCASE(11, TestSwedishSpellout);
+ TESTCASE(12, TestBelgianFrenchSpellout);
+ TESTCASE(13, TestSmallValues);
+ TESTCASE(14, TestLocalizations);
+ TESTCASE(15, TestAllLocales);
+ TESTCASE(16, TestHebrewFraction);
+ TESTCASE(17, TestPortugueseSpellout);
+ TESTCASE(18, TestMultiplierSubstitution);
+#else
+ TESTCASE(0, TestRBNFDisabled);
+#endif
+ default:
+ name = "";
+ break;
+ }
+}
+
+#if U_HAVE_RBNF
+
+void IntlTestRBNF::TestHebrewFraction() {
+ // this is the expected output for 123.45, with no '<' in it.
+ UChar text1[] = {
+ 0x05de, 0x05d0, 0x05d4, 0x0020,
+ 0x05e2, 0x05e9, 0x05e8, 0x05d9, 0x05dd, 0x0020,
+ 0x05d5, 0x05e9, 0x05dc, 0x05d5, 0x05e9, 0x0020,
+ 0x05e0, 0x05e7, 0x05d5, 0x05d3, 0x05d4, 0x0020,
+ 0x05d0, 0x05e8, 0x05d1, 0x05e2, 0x05d9, 0x05dd, 0x0020,
+ 0x05d5, 0x05d7, 0x05de, 0x05e9, 0x0000,
+ };
+ UChar text2[] = {
+ 0x05DE, 0x05D0, 0x05D4, 0x0020,
+ 0x05E2, 0x05E9, 0x05E8, 0x05D9, 0x05DD, 0x0020,
+ 0x05D5, 0x05E9, 0x05DC, 0x05D5, 0x05E9, 0x0020,
+ 0x05E0, 0x05E7, 0x05D5, 0x05D3, 0x05D4, 0x0020,
+ 0x05D0, 0x05E4, 0x05E1, 0x0020,
+ 0x05D0, 0x05E4, 0x05E1, 0x0020,
+ 0x05D0, 0x05E8, 0x05D1, 0x05E2, 0x05D9, 0x05DD, 0x0020,
+ 0x05D5, 0x05D7, 0x05DE, 0x05E9, 0x0000,
+ };
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter = new RuleBasedNumberFormat(URBNF_SPELLOUT, "he_IL", status);
+ UnicodeString result;
+ Formattable parseResult;
+ ParsePosition pp(0);
+ {
+ UnicodeString expected(text1);
+ formatter->format(123.45, result);
+ if (result != expected) {
+ errln((UnicodeString)"expected '" + TestUtility::hex(expected) + "'\nbut got: '" + TestUtility::hex(result) + "'");
+ } else {
+ formatter->parse(result, parseResult, pp);
+ if (parseResult.getDouble() != 123.45) {
+ errln("expected 123.45 but got: %g", parseResult.getDouble());
+ }
+ }
+ }
+ {
+ UnicodeString expected(text2);
+ result.remove();
+ formatter->format(123.0045, result);
+ if (result != expected) {
+ errln((UnicodeString)"expected '" + TestUtility::hex(expected) + "'\nbut got: '" + TestUtility::hex(result) + "'");
+ } else {
+ pp.setIndex(0);
+ formatter->parse(result, parseResult, pp);
+ if (parseResult.getDouble() != 123.0045) {
+ errln("expected 123.0045 but got: %g", parseResult.getDouble());
+ }
+ }
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestAPI() {
+ // This test goes through the APIs that were not tested before.
+ // These tests are too small to have separate test classes/functions
+
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getUS(), status);
+
+ logln("RBNF API test starting");
+ // test clone
+ {
+ logln("Testing Clone");
+ RuleBasedNumberFormat* rbnfClone = (RuleBasedNumberFormat *)formatter->clone();
+ if(rbnfClone != NULL) {
+ if(!(*rbnfClone == *formatter)) {
+ errln("Clone should be semantically equivalent to the original!");
+ }
+ delete rbnfClone;
+ } else {
+ errln("Cloning failed!");
+ }
+ }
+
+ // test assignment
+ {
+ logln("Testing assignment operator");
+ RuleBasedNumberFormat assignResult(URBNF_SPELLOUT, Locale("es", "ES", ""), status);
+ assignResult = *formatter;
+ if(!(assignResult == *formatter)) {
+ errln("Assignment result should be semantically equivalent to the original!");
+ }
+ }
+
+ // test rule constructor
+ {
+ logln("Testing rule constructor");
+ UResourceBundle *en = ures_open(U_ICUDATA_NAME U_TREE_SEPARATOR_STRING "rbnf", "en", &status);
+ if(U_FAILURE(status)) {
+ errln("Unable to access resource bundle with data!");
+ } else {
+ int32_t ruleLen = 0;
+ const UChar *spelloutRules = ures_getStringByKey(en, "SpelloutRules", &ruleLen, &status);
+ if(U_FAILURE(status) || ruleLen == 0 || spelloutRules == NULL) {
+ errln("Unable to access the rules string!");
+ } else {
+ UParseError perror;
+ RuleBasedNumberFormat ruleCtorResult(spelloutRules, Locale::getUS(), perror, status);
+ if(!(ruleCtorResult == *formatter)) {
+ errln("Formatter constructed from the original rules should be semantically equivalent to the original!");
+ }
+
+ // Jitterbug 4452, for coverage
+ RuleBasedNumberFormat nf(spelloutRules, (UnicodeString)"", Locale::getUS(), perror, status);
+ if(!(nf == *formatter)) {
+ errln("Formatter constructed from the original rules should be semantically equivalent to the original!");
+ }
+ }
+ ures_close(en);
+ }
+ }
+
+ // test getRules
+ {
+ logln("Testing getRules function");
+ UnicodeString rules = formatter->getRules();
+ UParseError perror;
+ RuleBasedNumberFormat fromRulesResult(rules, Locale::getUS(), perror, status);
+
+ if(!(fromRulesResult == *formatter)) {
+ errln("Formatter constructed from rules obtained by getRules should be semantically equivalent to the original!");
+ }
+ }
+
+
+ {
+ logln("Testing copy constructor");
+ RuleBasedNumberFormat copyCtorResult(*formatter);
+ if(!(copyCtorResult == *formatter)) {
+ errln("Copy constructor result result should be semantically equivalent to the original!");
+ }
+ }
+
+#if !UCONFIG_NO_COLLATION
+ // test ruleset names
+ {
+ logln("Testing getNumberOfRuleSetNames, getRuleSetName and format using rule set names");
+ int32_t noOfRuleSetNames = formatter->getNumberOfRuleSetNames();
+ if(noOfRuleSetNames == 0) {
+ errln("Number of rule set names should be more than zero");
+ }
+ UnicodeString ruleSetName;
+ int32_t i = 0;
+ int32_t intFormatNum = 34567;
+ double doubleFormatNum = 893411.234;
+ logln("number of rule set names is %i", noOfRuleSetNames);
+ for(i = 0; i < noOfRuleSetNames; i++) {
+ FieldPosition pos1, pos2;
+ UnicodeString intFormatResult, doubleFormatResult;
+ Formattable intParseResult, doubleParseResult;
+
+ ruleSetName = formatter->getRuleSetName(i);
+ log("Rule set name %i is ", i);
+ log(ruleSetName);
+ logln(". Format results are: ");
+ intFormatResult = formatter->format(intFormatNum, ruleSetName, intFormatResult, pos1, status);
+ doubleFormatResult = formatter->format(doubleFormatNum, ruleSetName, doubleFormatResult, pos2, status);
+ if(U_FAILURE(status)) {
+ errln("Format using a rule set failed");
+ break;
+ }
+ logln(intFormatResult);
+ logln(doubleFormatResult);
+ formatter->setLenient(TRUE);
+ formatter->parse(intFormatResult, intParseResult, status);
+ formatter->parse(doubleFormatResult, doubleParseResult, status);
+
+ logln("Parse results for lenient = TRUE, %i, %f", intParseResult.getLong(), doubleParseResult.getDouble());
+
+ formatter->setLenient(FALSE);
+ formatter->parse(intFormatResult, intParseResult, status);
+ formatter->parse(doubleFormatResult, doubleParseResult, status);
+
+ logln("Parse results for lenient = FALSE, %i, %f", intParseResult.getLong(), doubleParseResult.getDouble());
+
+ if(U_FAILURE(status)) {
+ errln("Error during parsing");
+ }
+
+ intFormatResult = formatter->format(intFormatNum, "BLABLA", intFormatResult, pos1, status);
+ if(U_SUCCESS(status)) {
+ errln("Using invalid rule set name should have failed");
+ break;
+ }
+ status = U_ZERO_ERROR;
+ doubleFormatResult = formatter->format(doubleFormatNum, "TRUC", doubleFormatResult, pos2, status);
+ if(U_SUCCESS(status)) {
+ errln("Using invalid rule set name should have failed");
+ break;
+ }
+ status = U_ZERO_ERROR;
+ }
+ status = U_ZERO_ERROR;
+ }
+#endif
+
+ // test API
+ UnicodeString expected("four point five","");
+ logln("Testing format(double)");
+ UnicodeString result;
+ formatter->format(4.5,result);
+ if(result != expected) {
+ errln("Formatted 4.5, expected " + expected + " got " + result);
+ } else {
+ logln("Formatted 4.5, expected " + expected + " got " + result);
+ }
+ result.remove();
+ expected = "four";
+ formatter->format((int32_t)4,result);
+ if(result != expected) {
+ errln("Formatted 4, expected " + expected + " got " + result);
+ } else {
+ logln("Formatted 4, expected " + expected + " got " + result);
+ }
+
+ result.remove();
+ FieldPosition pos;
+ formatter->format((int64_t)4, result, pos, status = U_ZERO_ERROR);
+ if(result != expected) {
+ errln("Formatted 4 int64_t, expected " + expected + " got " + result);
+ } else {
+ logln("Formatted 4 int64_t, expected " + expected + " got " + result);
+ }
+
+ //Jitterbug 4452, for coverage
+ result.remove();
+ FieldPosition pos2;
+ formatter->format((int64_t)4, formatter->getRuleSetName(0), result, pos2, status = U_ZERO_ERROR);
+ if(result != expected) {
+ errln("Formatted 4 int64_t, expected " + expected + " got " + result);
+ } else {
+ logln("Formatted 4 int64_t, expected " + expected + " got " + result);
+ }
+
+ // clean up
+ logln("Cleaning up");
+ delete formatter;
+}
+
+void IntlTestRBNF::TestFractionalRuleSet()
+{
+ UnicodeString fracRules(
+ "%main:\n"
+ // this rule formats the number if it's 1 or more. It formats
+ // the integral part using a DecimalFormat ("#,##0" puts
+ // thousands separators in the right places) and the fractional
+ // part using %%frac. If there is no fractional part, it
+ // just shows the integral part.
+ " x.0: <#,##0<[ >%%frac>];\n"
+ // this rule formats the number if it's between 0 and 1. It
+ // shows only the fractional part (0.5 shows up as "1/2," not
+ // "0 1/2")
+ " 0.x: >%%frac>;\n"
+ // the fraction rule set. This works the same way as the one in the
+ // preceding example: We multiply the fractional part of the number
+ // being formatted by each rule's base value and use the rule that
+ // produces the result closest to 0 (or the first rule that produces 0).
+ // Since we only provide rules for the numbers from 2 to 10, we know
+ // we'll get a fraction with a denominator between 2 and 10.
+ // "<0<" causes the numerator of the fraction to be formatted
+ // using numerals
+ "%%frac:\n"
+ " 2: 1/2;\n"
+ " 3: <0</3;\n"
+ " 4: <0</4;\n"
+ " 5: <0</5;\n"
+ " 6: <0</6;\n"
+ " 7: <0</7;\n"
+ " 8: <0</8;\n"
+ " 9: <0</9;\n"
+ " 10: <0</10;\n");
+
+ // mondo hack
+ int len = fracRules.length();
+ int change = 2;
+ for (int i = 0; i < len; ++i) {
+ UChar ch = fracRules.charAt(i);
+ if (ch == '\n') {
+ change = 2; // change ok
+ } else if (ch == ':') {
+ change = 1; // change, but once we hit a non-space char, don't change
+ } else if (ch == ' ') {
+ if (change != 0) {
+ fracRules.setCharAt(i, (UChar)0x200e);
+ }
+ } else {
+ if (change == 1) {
+ change = 0;
+ }
+ }
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError perror;
+ RuleBasedNumberFormat formatter(fracRules, Locale::getEnglish(), perror, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "0", "0" },
+ { ".1", "1/10" },
+ { ".11", "1/9" },
+ { ".125", "1/8" },
+ { ".1428", "1/7" },
+ { ".1667", "1/6" },
+ { ".2", "1/5" },
+ { ".25", "1/4" },
+ { ".333", "1/3" },
+ { ".5", "1/2" },
+ { "1.1", "1 1/10" },
+ { "2.11", "2 1/9" },
+ { "3.125", "3 1/8" },
+ { "4.1428", "4 1/7" },
+ { "5.1667", "5 1/6" },
+ { "6.2", "6 1/5" },
+ { "7.25", "7 1/4" },
+ { "8.333", "8 1/3" },
+ { "9.5", "9 1/2" },
+ { ".2222", "2/9" },
+ { ".4444", "4/9" },
+ { ".5555", "5/9" },
+ { "1.2856", "1 2/7" },
+ { NULL, NULL }
+ };
+ doTest(&formatter, testData, FALSE); // exact values aren't parsable from fractions
+ }
+}
+
+#if 0
+#define LLAssert(a) \
+ if (!(a)) errln("FAIL: " #a)
+
+void IntlTestRBNF::TestLLongConstructors()
+{
+ logln("Testing constructors");
+
+ // constant (shouldn't really be public)
+ LLAssert(llong(llong::kD32).asDouble() == llong::kD32);
+
+ // internal constructor (shouldn't really be public)
+ LLAssert(llong(0, 1).asDouble() == 1);
+ LLAssert(llong(1, 0).asDouble() == llong::kD32);
+ LLAssert(llong((uint32_t)-1, (uint32_t)-1).asDouble() == -1);
+
+ // public empty constructor
+ LLAssert(llong().asDouble() == 0);
+
+ // public int32_t constructor
+ LLAssert(llong((int32_t)0).asInt() == (int32_t)0);
+ LLAssert(llong((int32_t)1).asInt() == (int32_t)1);
+ LLAssert(llong((int32_t)-1).asInt() == (int32_t)-1);
+ LLAssert(llong((int32_t)0x7fffffff).asInt() == (int32_t)0x7fffffff);
+ LLAssert(llong((int32_t)0xffffffff).asInt() == (int32_t)-1);
+ LLAssert(llong((int32_t)0x80000000).asInt() == (int32_t)0x80000000);
+
+ // public int16_t constructor
+ LLAssert(llong((int16_t)0).asInt() == (int16_t)0);
+ LLAssert(llong((int16_t)1).asInt() == (int16_t)1);
+ LLAssert(llong((int16_t)-1).asInt() == (int16_t)-1);
+ LLAssert(llong((int16_t)0x7fff).asInt() == (int16_t)0x7fff);
+ LLAssert(llong((int16_t)0xffff).asInt() == (int16_t)0xffff);
+ LLAssert(llong((int16_t)0x8000).asInt() == (int16_t)0x8000);
+
+ // public int8_t constructor
+ LLAssert(llong((int8_t)0).asInt() == (int8_t)0);
+ LLAssert(llong((int8_t)1).asInt() == (int8_t)1);
+ LLAssert(llong((int8_t)-1).asInt() == (int8_t)-1);
+ LLAssert(llong((int8_t)0x7f).asInt() == (int8_t)0x7f);
+ LLAssert(llong((int8_t)0xff).asInt() == (int8_t)0xff);
+ LLAssert(llong((int8_t)0x80).asInt() == (int8_t)0x80);
+
+ // public uint16_t constructor
+ LLAssert(llong((uint16_t)0).asUInt() == (uint16_t)0);
+ LLAssert(llong((uint16_t)1).asUInt() == (uint16_t)1);
+ LLAssert(llong((uint16_t)-1).asUInt() == (uint16_t)-1);
+ LLAssert(llong((uint16_t)0x7fff).asUInt() == (uint16_t)0x7fff);
+ LLAssert(llong((uint16_t)0xffff).asUInt() == (uint16_t)0xffff);
+ LLAssert(llong((uint16_t)0x8000).asUInt() == (uint16_t)0x8000);
+
+ // public uint32_t constructor
+ LLAssert(llong((uint32_t)0).asUInt() == (uint32_t)0);
+ LLAssert(llong((uint32_t)1).asUInt() == (uint32_t)1);
+ LLAssert(llong((uint32_t)-1).asUInt() == (uint32_t)-1);
+ LLAssert(llong((uint32_t)0x7fffffff).asUInt() == (uint32_t)0x7fffffff);
+ LLAssert(llong((uint32_t)0xffffffff).asUInt() == (uint32_t)-1);
+ LLAssert(llong((uint32_t)0x80000000).asUInt() == (uint32_t)0x80000000);
+
+ // public double constructor
+ LLAssert(llong((double)0).asDouble() == (double)0);
+ LLAssert(llong((double)1).asDouble() == (double)1);
+ LLAssert(llong((double)0x7fffffff).asDouble() == (double)0x7fffffff);
+ LLAssert(llong((double)0x80000000).asDouble() == (double)0x80000000);
+ LLAssert(llong((double)0x80000001).asDouble() == (double)0x80000001);
+
+ // can't access uprv_maxmantissa, so fake it
+ double maxmantissa = (llong((int32_t)1) << 40).asDouble();
+ LLAssert(llong(maxmantissa).asDouble() == maxmantissa);
+ LLAssert(llong(-maxmantissa).asDouble() == -maxmantissa);
+
+ // copy constructor
+ LLAssert(llong(llong(0, 1)).asDouble() == 1);
+ LLAssert(llong(llong(1, 0)).asDouble() == llong::kD32);
+ LLAssert(llong(llong(-1, (uint32_t)-1)).asDouble() == -1);
+
+ // asInt - test unsigned to signed narrowing conversion
+ LLAssert(llong((uint32_t)-1).asInt() == (int32_t)0x7fffffff);
+ LLAssert(llong(-1, 0).asInt() == (int32_t)0x80000000);
+
+ // asUInt - test signed to unsigned narrowing conversion
+ LLAssert(llong((int32_t)-1).asUInt() == (uint32_t)-1);
+ LLAssert(llong((int32_t)0x80000000).asUInt() == (uint32_t)0x80000000);
+
+ // asDouble already tested
+
+}
+
+void IntlTestRBNF::TestLLongSimpleOperators()
+{
+ logln("Testing simple operators");
+
+ // operator==
+ LLAssert(llong() == llong(0, 0));
+ LLAssert(llong(1,0) == llong(1, 0));
+ LLAssert(llong(0,1) == llong(0, 1));
+
+ // operator!=
+ LLAssert(llong(1,0) != llong(1,1));
+ LLAssert(llong(0,1) != llong(1,1));
+ LLAssert(llong(0xffffffff,0xffffffff) != llong(0x7fffffff, 0xffffffff));
+
+ // unsigned >
+ LLAssert(llong((int32_t)-1).ugt(llong(0x7fffffff, 0xffffffff)));
+
+ // unsigned <
+ LLAssert(llong(0x7fffffff, 0xffffffff).ult(llong((int32_t)-1)));
+
+ // unsigned >=
+ LLAssert(llong((int32_t)-1).uge(llong(0x7fffffff, 0xffffffff)));
+ LLAssert(llong((int32_t)-1).uge(llong((int32_t)-1)));
+
+ // unsigned <=
+ LLAssert(llong(0x7fffffff, 0xffffffff).ule(llong((int32_t)-1)));
+ LLAssert(llong((int32_t)-1).ule(llong((int32_t)-1)));
+
+ // operator>
+ LLAssert(llong(1, 1) > llong(1, 0));
+ LLAssert(llong(0, 0x80000000) > llong(0, 0x7fffffff));
+ LLAssert(llong(0x80000000, 1) > llong(0x80000000, 0));
+ LLAssert(llong(1, 0) > llong(0, 0x7fffffff));
+ LLAssert(llong(1, 0) > llong(0, 0xffffffff));
+ LLAssert(llong(0, 0) > llong(0x80000000, 1));
+
+ // operator<
+ LLAssert(llong(1, 0) < llong(1, 1));
+ LLAssert(llong(0, 0x7fffffff) < llong(0, 0x80000000));
+ LLAssert(llong(0x80000000, 0) < llong(0x80000000, 1));
+ LLAssert(llong(0, 0x7fffffff) < llong(1, 0));
+ LLAssert(llong(0, 0xffffffff) < llong(1, 0));
+ LLAssert(llong(0x80000000, 1) < llong(0, 0));
+
+ // operator>=
+ LLAssert(llong(1, 1) >= llong(1, 0));
+ LLAssert(llong(0, 0x80000000) >= llong(0, 0x7fffffff));
+ LLAssert(llong(0x80000000, 1) >= llong(0x80000000, 0));
+ LLAssert(llong(1, 0) >= llong(0, 0x7fffffff));
+ LLAssert(llong(1, 0) >= llong(0, 0xffffffff));
+ LLAssert(llong(0, 0) >= llong(0x80000000, 1));
+ LLAssert(llong() >= llong(0, 0));
+ LLAssert(llong(1,0) >= llong(1, 0));
+ LLAssert(llong(0,1) >= llong(0, 1));
+
+ // operator<=
+ LLAssert(llong(1, 0) <= llong(1, 1));
+ LLAssert(llong(0, 0x7fffffff) <= llong(0, 0x80000000));
+ LLAssert(llong(0x80000000, 0) <= llong(0x80000000, 1));
+ LLAssert(llong(0, 0x7fffffff) <= llong(1, 0));
+ LLAssert(llong(0, 0xffffffff) <= llong(1, 0));
+ LLAssert(llong(0x80000000, 1) <= llong(0, 0));
+ LLAssert(llong() <= llong(0, 0));
+ LLAssert(llong(1,0) <= llong(1, 0));
+ LLAssert(llong(0,1) <= llong(0, 1));
+
+ // operator==(int32)
+ LLAssert(llong() == (int32_t)0);
+ LLAssert(llong(0,1) == (int32_t)1);
+
+ // operator!=(int32)
+ LLAssert(llong(1,0) != (int32_t)0);
+ LLAssert(llong(0,1) != (int32_t)2);
+ LLAssert(llong(0,0xffffffff) != (int32_t)-1);
+
+ llong negOne(0xffffffff, 0xffffffff);
+
+ // operator>(int32)
+ LLAssert(llong(0, 0x80000000) > (int32_t)0x7fffffff);
+ LLAssert(negOne > (int32_t)-2);
+ LLAssert(llong(1, 0) > (int32_t)0x7fffffff);
+ LLAssert(llong(0, 0) > (int32_t)-1);
+
+ // operator<(int32)
+ LLAssert(llong(0, 0x7ffffffe) < (int32_t)0x7fffffff);
+ LLAssert(llong(0xffffffff, 0xfffffffe) < (int32_t)-1);
+
+ // operator>=(int32)
+ LLAssert(llong(0, 0x80000000) >= (int32_t)0x7fffffff);
+ LLAssert(negOne >= (int32_t)-2);
+ LLAssert(llong(1, 0) >= (int32_t)0x7fffffff);
+ LLAssert(llong(0, 0) >= (int32_t)-1);
+ LLAssert(llong() >= (int32_t)0);
+ LLAssert(llong(0,1) >= (int32_t)1);
+
+ // operator<=(int32)
+ LLAssert(llong(0, 0x7ffffffe) <= (int32_t)0x7fffffff);
+ LLAssert(llong(0xffffffff, 0xfffffffe) <= (int32_t)-1);
+ LLAssert(llong() <= (int32_t)0);
+ LLAssert(llong(0,1) <= (int32_t)1);
+
+ // operator=
+ LLAssert((llong(2,3) = llong((uint32_t)-1)).asUInt() == (uint32_t)-1);
+
+ // operator <<=
+ LLAssert((llong(1, 1) <<= 0) == llong(1, 1));
+ LLAssert((llong(1, 1) <<= 31) == llong(0x80000000, 0x80000000));
+ LLAssert((llong(1, 1) <<= 32) == llong(1, 0));
+ LLAssert((llong(1, 1) <<= 63) == llong(0x80000000, 0));
+ LLAssert((llong(1, 1) <<= 64) == llong(1, 1)); // only lower 6 bits are used
+ LLAssert((llong(1, 1) <<= -1) == llong(0x80000000, 0)); // only lower 6 bits are used
+
+ // operator <<
+ LLAssert((llong((int32_t)1) << 5).asUInt() == 32);
+
+ // operator >>= (sign extended)
+ LLAssert((llong(0x7fffa0a0, 0xbcbcdfdf) >>= 16) == llong(0x7fff,0xa0a0bcbc));
+ LLAssert((llong(0x8000789a, 0xbcde0000) >>= 16) == llong(0xffff8000,0x789abcde));
+ LLAssert((llong(0x80000000, 0) >>= 63) == llong(0xffffffff, 0xffffffff));
+ LLAssert((llong(0x80000000, 0) >>= 47) == llong(0xffffffff, 0xffff0000));
+ LLAssert((llong(0x80000000, 0x80000000) >> 64) == llong(0x80000000, 0x80000000)); // only lower 6 bits are used
+ LLAssert((llong(0x80000000, 0) >>= -1) == llong(0xffffffff, 0xffffffff)); // only lower 6 bits are used
+
+ // operator >> sign extended)
+ LLAssert((llong(0x8000789a, 0xbcde0000) >> 16) == llong(0xffff8000,0x789abcde));
+
+ // ushr (right shift without sign extension)
+ LLAssert(llong(0x7fffa0a0, 0xbcbcdfdf).ushr(16) == llong(0x7fff,0xa0a0bcbc));
+ LLAssert(llong(0x8000789a, 0xbcde0000).ushr(16) == llong(0x00008000,0x789abcde));
+ LLAssert(llong(0x80000000, 0).ushr(63) == llong(0, 1));
+ LLAssert(llong(0x80000000, 0).ushr(47) == llong(0, 0x10000));
+ LLAssert(llong(0x80000000, 0x80000000).ushr(64) == llong(0x80000000, 0x80000000)); // only lower 6 bits are used
+ LLAssert(llong(0x80000000, 0).ushr(-1) == llong(0, 1)); // only lower 6 bits are used
+
+ // operator&(llong)
+ LLAssert((llong(0x55555555, 0x55555555) & llong(0xaaaaffff, 0xffffaaaa)) == llong(0x00005555, 0x55550000));
+
+ // operator|(llong)
+ LLAssert((llong(0x55555555, 0x55555555) | llong(0xaaaaffff, 0xffffaaaa)) == llong(0xffffffff, 0xffffffff));
+
+ // operator^(llong)
+ LLAssert((llong(0x55555555, 0x55555555) ^ llong(0xaaaaffff, 0xffffaaaa)) == llong(0xffffaaaa, 0xaaaaffff));
+
+ // operator&(uint32)
+ LLAssert((llong(0x55555555, 0x55555555) & (uint32_t)0xffffaaaa) == llong(0, 0x55550000));
+
+ // operator|(uint32)
+ LLAssert((llong(0x55555555, 0x55555555) | (uint32_t)0xffffaaaa) == llong(0x55555555, 0xffffffff));
+
+ // operator^(uint32)
+ LLAssert((llong(0x55555555, 0x55555555) ^ (uint32_t)0xffffaaaa) == llong(0x55555555, 0xaaaaffff));
+
+ // operator~
+ LLAssert(~llong(0x55555555, 0x55555555) == llong(0xaaaaaaaa, 0xaaaaaaaa));
+
+ // operator&=(llong)
+ LLAssert((llong(0x55555555, 0x55555555) &= llong(0xaaaaffff, 0xffffaaaa)) == llong(0x00005555, 0x55550000));
+
+ // operator|=(llong)
+ LLAssert((llong(0x55555555, 0x55555555) |= llong(0xaaaaffff, 0xffffaaaa)) == llong(0xffffffff, 0xffffffff));
+
+ // operator^=(llong)
+ LLAssert((llong(0x55555555, 0x55555555) ^= llong(0xaaaaffff, 0xffffaaaa)) == llong(0xffffaaaa, 0xaaaaffff));
+
+ // operator&=(uint32)
+ LLAssert((llong(0x55555555, 0x55555555) &= (uint32_t)0xffffaaaa) == llong(0, 0x55550000));
+
+ // operator|=(uint32)
+ LLAssert((llong(0x55555555, 0x55555555) |= (uint32_t)0xffffaaaa) == llong(0x55555555, 0xffffffff));
+
+ // operator^=(uint32)
+ LLAssert((llong(0x55555555, 0x55555555) ^= (uint32_t)0xffffaaaa) == llong(0x55555555, 0xaaaaffff));
+
+ // prefix inc
+ LLAssert(llong(1, 0) == ++llong(0,0xffffffff));
+
+ // prefix dec
+ LLAssert(llong(0,0xffffffff) == --llong(1, 0));
+
+ // postfix inc
+ {
+ llong n(0, 0xffffffff);
+ LLAssert(llong(0, 0xffffffff) == n++);
+ LLAssert(llong(1, 0) == n);
+ }
+
+ // postfix dec
+ {
+ llong n(1, 0);
+ LLAssert(llong(1, 0) == n--);
+ LLAssert(llong(0, 0xffffffff) == n);
+ }
+
+ // unary minus
+ LLAssert(llong(0, 0) == -llong(0, 0));
+ LLAssert(llong(0xffffffff, 0xffffffff) == -llong(0, 1));
+ LLAssert(llong(0, 1) == -llong(0xffffffff, 0xffffffff));
+ LLAssert(llong(0x7fffffff, 0xffffffff) == -llong(0x80000000, 1));
+ LLAssert(llong(0x80000000, 0) == -llong(0x80000000, 0)); // !!! we don't handle overflow
+
+ // operator-=
+ {
+ llong n;
+ LLAssert((n -= llong(0, 1)) == llong(0xffffffff, 0xffffffff));
+ LLAssert(n == llong(0xffffffff, 0xffffffff));
+
+ n = llong(1, 0);
+ LLAssert((n -= llong(0, 1)) == llong(0, 0xffffffff));
+ LLAssert(n == llong(0, 0xffffffff));
+ }
+
+ // operator-
+ {
+ llong n;
+ LLAssert((n - llong(0, 1)) == llong(0xffffffff, 0xffffffff));
+ LLAssert(n == llong(0, 0));
+
+ n = llong(1, 0);
+ LLAssert((n - llong(0, 1)) == llong(0, 0xffffffff));
+ LLAssert(n == llong(1, 0));
+ }
+
+ // operator+=
+ {
+ llong n(0xffffffff, 0xffffffff);
+ LLAssert((n += llong(0, 1)) == llong(0, 0));
+ LLAssert(n == llong(0, 0));
+
+ n = llong(0, 0xffffffff);
+ LLAssert((n += llong(0, 1)) == llong(1, 0));
+ LLAssert(n == llong(1, 0));
+ }
+
+ // operator+
+ {
+ llong n(0xffffffff, 0xffffffff);
+ LLAssert((n + llong(0, 1)) == llong(0, 0));
+ LLAssert(n == llong(0xffffffff, 0xffffffff));
+
+ n = llong(0, 0xffffffff);
+ LLAssert((n + llong(0, 1)) == llong(1, 0));
+ LLAssert(n == llong(0, 0xffffffff));
+ }
+
+}
+
+void IntlTestRBNF::TestLLong()
+{
+ logln("Starting TestLLong");
+
+ TestLLongConstructors();
+
+ TestLLongSimpleOperators();
+
+ logln("Testing operator*=, operator*");
+
+ // operator*=, operator*
+ // small and large values, positive, &NEGative, zero
+ // also test commutivity
+ {
+ const llong ZERO;
+ const llong ONE(0, 1);
+ const llong NEG_ONE((int32_t)-1);
+ const llong THREE(0, 3);
+ const llong NEG_THREE((int32_t)-3);
+ const llong TWO_TO_16(0, 0x10000);
+ const llong NEG_TWO_TO_16 = -TWO_TO_16;
+ const llong TWO_TO_32(1, 0);
+ const llong NEG_TWO_TO_32 = -TWO_TO_32;
+
+ const llong NINE(0, 9);
+ const llong NEG_NINE = -NINE;
+
+ const llong TWO_TO_16X3(0, 0x00030000);
+ const llong NEG_TWO_TO_16X3 = -TWO_TO_16X3;
+
+ const llong TWO_TO_32X3(3, 0);
+ const llong NEG_TWO_TO_32X3 = -TWO_TO_32X3;
+
+ const llong TWO_TO_48(0x10000, 0);
+ const llong NEG_TWO_TO_48 = -TWO_TO_48;
+
+ const int32_t VALUE_WIDTH = 9;
+ const llong* values[VALUE_WIDTH] = {
+ &ZERO, &ONE, &NEG_ONE, &THREE, &NEG_THREE, &TWO_TO_16, &NEG_TWO_TO_16, &TWO_TO_32, &NEG_TWO_TO_32
+ };
+
+ const llong* answers[VALUE_WIDTH*VALUE_WIDTH] = {
+ &ZERO, &ZERO, &ZERO, &ZERO, &ZERO, &ZERO, &ZERO, &ZERO, &ZERO,
+ &ZERO, &ONE, &NEG_ONE, &THREE, &NEG_THREE, &TWO_TO_16, &NEG_TWO_TO_16, &TWO_TO_32, &NEG_TWO_TO_32,
+ &ZERO, &NEG_ONE, &ONE, &NEG_THREE, &THREE, &NEG_TWO_TO_16, &TWO_TO_16, &NEG_TWO_TO_32, &TWO_TO_32,
+ &ZERO, &THREE, &NEG_THREE, &NINE, &NEG_NINE, &TWO_TO_16X3, &NEG_TWO_TO_16X3, &TWO_TO_32X3, &NEG_TWO_TO_32X3,
+ &ZERO, &NEG_THREE, &THREE, &NEG_NINE, &NINE, &NEG_TWO_TO_16X3, &TWO_TO_16X3, &NEG_TWO_TO_32X3, &TWO_TO_32X3,
+ &ZERO, &TWO_TO_16, &NEG_TWO_TO_16, &TWO_TO_16X3, &NEG_TWO_TO_16X3, &TWO_TO_32, &NEG_TWO_TO_32, &TWO_TO_48, &NEG_TWO_TO_48,
+ &ZERO, &NEG_TWO_TO_16, &TWO_TO_16, &NEG_TWO_TO_16X3, &TWO_TO_16X3, &NEG_TWO_TO_32, &TWO_TO_32, &NEG_TWO_TO_48, &TWO_TO_48,
+ &ZERO, &TWO_TO_32, &NEG_TWO_TO_32, &TWO_TO_32X3, &NEG_TWO_TO_32X3, &TWO_TO_48, &NEG_TWO_TO_48, &ZERO, &ZERO,
+ &ZERO, &NEG_TWO_TO_32, &TWO_TO_32, &NEG_TWO_TO_32X3, &TWO_TO_32X3, &NEG_TWO_TO_48, &TWO_TO_48, &ZERO, &ZERO
+ };
+
+ for (int i = 0; i < VALUE_WIDTH; ++i) {
+ for (int j = 0; j < VALUE_WIDTH; ++j) {
+ llong lhs = *values[i];
+ llong rhs = *values[j];
+ llong ans = *answers[i*VALUE_WIDTH + j];
+
+ llong n = lhs;
+
+ LLAssert((n *= rhs) == ans);
+ LLAssert(n == ans);
+
+ n = lhs;
+ LLAssert((n * rhs) == ans);
+ LLAssert(n == lhs);
+ }
+ }
+ }
+
+ logln("Testing operator/=, operator/");
+ // operator/=, operator/
+ // test num = 0, div = 0, pos/neg, > 2^32, div > num
+ {
+ const llong ZERO;
+ const llong ONE(0, 1);
+ const llong NEG_ONE = -ONE;
+ const llong MAX(0x7fffffff, 0xffffffff);
+ const llong MIN(0x80000000, 0);
+ const llong TWO(0, 2);
+ const llong NEG_TWO = -TWO;
+ const llong FIVE(0, 5);
+ const llong NEG_FIVE = -FIVE;
+ const llong TWO_TO_32(1, 0);
+ const llong NEG_TWO_TO_32 = -TWO_TO_32;
+ const llong TWO_TO_32d5 = llong(TWO_TO_32.asDouble()/5.0);
+ const llong NEG_TWO_TO_32d5 = -TWO_TO_32d5;
+ const llong TWO_TO_32X5 = TWO_TO_32 * FIVE;
+ const llong NEG_TWO_TO_32X5 = -TWO_TO_32X5;
+
+ const llong* tuples[] = { // lhs, rhs, ans
+ &ZERO, &ZERO, &ZERO,
+ &ONE, &ZERO,&MAX,
+ &NEG_ONE, &ZERO, &MIN,
+ &ONE, &ONE, &ONE,
+ &ONE, &NEG_ONE, &NEG_ONE,
+ &NEG_ONE, &ONE, &NEG_ONE,
+ &NEG_ONE, &NEG_ONE, &ONE,
+ &FIVE, &TWO, &TWO,
+ &FIVE, &NEG_TWO, &NEG_TWO,
+ &NEG_FIVE, &TWO, &NEG_TWO,
+ &NEG_FIVE, &NEG_TWO, &TWO,
+ &TWO, &FIVE, &ZERO,
+ &TWO, &NEG_FIVE, &ZERO,
+ &NEG_TWO, &FIVE, &ZERO,
+ &NEG_TWO, &NEG_FIVE, &ZERO,
+ &TWO_TO_32, &TWO_TO_32, &ONE,
+ &TWO_TO_32, &NEG_TWO_TO_32, &NEG_ONE,
+ &NEG_TWO_TO_32, &TWO_TO_32, &NEG_ONE,
+ &NEG_TWO_TO_32, &NEG_TWO_TO_32, &ONE,
+ &TWO_TO_32, &FIVE, &TWO_TO_32d5,
+ &TWO_TO_32, &NEG_FIVE, &NEG_TWO_TO_32d5,
+ &NEG_TWO_TO_32, &FIVE, &NEG_TWO_TO_32d5,
+ &NEG_TWO_TO_32, &NEG_FIVE, &TWO_TO_32d5,
+ &TWO_TO_32X5, &FIVE, &TWO_TO_32,
+ &TWO_TO_32X5, &NEG_FIVE, &NEG_TWO_TO_32,
+ &NEG_TWO_TO_32X5, &FIVE, &NEG_TWO_TO_32,
+ &NEG_TWO_TO_32X5, &NEG_FIVE, &TWO_TO_32,
+ &TWO_TO_32X5, &TWO_TO_32, &FIVE,
+ &TWO_TO_32X5, &NEG_TWO_TO_32, &NEG_FIVE,
+ &NEG_TWO_TO_32X5, &NEG_TWO_TO_32, &FIVE,
+ &NEG_TWO_TO_32X5, &TWO_TO_32, &NEG_FIVE
+ };
+ const int TUPLE_WIDTH = 3;
+ const int TUPLE_COUNT = (int)(sizeof(tuples)/sizeof(tuples[0]))/TUPLE_WIDTH;
+ for (int i = 0; i < TUPLE_COUNT; ++i) {
+ const llong lhs = *tuples[i*TUPLE_WIDTH+0];
+ const llong rhs = *tuples[i*TUPLE_WIDTH+1];
+ const llong ans = *tuples[i*TUPLE_WIDTH+2];
+
+ llong n = lhs;
+ if (!((n /= rhs) == ans)) {
+ errln("fail: (n /= rhs) == ans");
+ }
+ LLAssert(n == ans);
+
+ n = lhs;
+ LLAssert((n / rhs) == ans);
+ LLAssert(n == lhs);
+ }
+ }
+
+ logln("Testing operator%%=, operator%%");
+ //operator%=, operator%
+ {
+ const llong ZERO;
+ const llong ONE(0, 1);
+ const llong TWO(0, 2);
+ const llong THREE(0,3);
+ const llong FOUR(0, 4);
+ const llong FIVE(0, 5);
+ const llong SIX(0, 6);
+
+ const llong NEG_ONE = -ONE;
+ const llong NEG_TWO = -TWO;
+ const llong NEG_THREE = -THREE;
+ const llong NEG_FOUR = -FOUR;
+ const llong NEG_FIVE = -FIVE;
+ const llong NEG_SIX = -SIX;
+
+ const llong NINETY_NINE(0, 99);
+ const llong HUNDRED(0, 100);
+ const llong HUNDRED_ONE(0, 101);
+
+ const llong BIG(0x12345678, 0x9abcdef0);
+ const llong BIG_FIVE(BIG * FIVE);
+ const llong BIG_FIVEm1 = BIG_FIVE - ONE;
+ const llong BIG_FIVEp1 = BIG_FIVE + ONE;
+
+ const llong* tuples[] = {
+ &ZERO, &FIVE, &ZERO,
+ &ONE, &FIVE, &ONE,
+ &TWO, &FIVE, &TWO,
+ &THREE, &FIVE, &THREE,
+ &FOUR, &FIVE, &FOUR,
+ &FIVE, &FIVE, &ZERO,
+ &SIX, &FIVE, &ONE,
+ &ZERO, &NEG_FIVE, &ZERO,
+ &ONE, &NEG_FIVE, &ONE,
+ &TWO, &NEG_FIVE, &TWO,
+ &THREE, &NEG_FIVE, &THREE,
+ &FOUR, &NEG_FIVE, &FOUR,
+ &FIVE, &NEG_FIVE, &ZERO,
+ &SIX, &NEG_FIVE, &ONE,
+ &NEG_ONE, &FIVE, &NEG_ONE,
+ &NEG_TWO, &FIVE, &NEG_TWO,
+ &NEG_THREE, &FIVE, &NEG_THREE,
+ &NEG_FOUR, &FIVE, &NEG_FOUR,
+ &NEG_FIVE, &FIVE, &ZERO,
+ &NEG_SIX, &FIVE, &NEG_ONE,
+ &NEG_ONE, &NEG_FIVE, &NEG_ONE,
+ &NEG_TWO, &NEG_FIVE, &NEG_TWO,
+ &NEG_THREE, &NEG_FIVE, &NEG_THREE,
+ &NEG_FOUR, &NEG_FIVE, &NEG_FOUR,
+ &NEG_FIVE, &NEG_FIVE, &ZERO,
+ &NEG_SIX, &NEG_FIVE, &NEG_ONE,
+ &NINETY_NINE, &FIVE, &FOUR,
+ &HUNDRED, &FIVE, &ZERO,
+ &HUNDRED_ONE, &FIVE, &ONE,
+ &BIG_FIVEm1, &FIVE, &FOUR,
+ &BIG_FIVE, &FIVE, &ZERO,
+ &BIG_FIVEp1, &FIVE, &ONE
+ };
+ const int TUPLE_WIDTH = 3;
+ const int TUPLE_COUNT = (int)(sizeof(tuples)/sizeof(tuples[0]))/TUPLE_WIDTH;
+ for (int i = 0; i < TUPLE_COUNT; ++i) {
+ const llong lhs = *tuples[i*TUPLE_WIDTH+0];
+ const llong rhs = *tuples[i*TUPLE_WIDTH+1];
+ const llong ans = *tuples[i*TUPLE_WIDTH+2];
+
+ llong n = lhs;
+ if (!((n %= rhs) == ans)) {
+ errln("fail: (n %= rhs) == ans");
+ }
+ LLAssert(n == ans);
+
+ n = lhs;
+ LLAssert((n % rhs) == ans);
+ LLAssert(n == lhs);
+ }
+ }
+
+ logln("Testing pow");
+ // pow
+ LLAssert(llong(0, 0).pow(0) == llong(0, 0));
+ LLAssert(llong(0, 0).pow(2) == llong(0, 0));
+ LLAssert(llong(0, 2).pow(0) == llong(0, 1));
+ LLAssert(llong(0, 2).pow(2) == llong(0, 4));
+ LLAssert(llong(0, 2).pow(32) == llong(1, 0));
+ LLAssert(llong(0, 5).pow(10) == llong((double)5.0 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5));
+
+ // absolute value
+ {
+ const llong n(0xffffffff,0xffffffff);
+ LLAssert(n.abs() == llong(0, 1));
+ }
+
+#ifdef RBNF_DEBUG
+ logln("Testing atoll");
+ // atoll
+ const char empty[] = "";
+ const char zero[] = "0";
+ const char neg_one[] = "-1";
+ const char neg_12345[] = "-12345";
+ const char big1[] = "123456789abcdef0";
+ const char big2[] = "fFfFfFfFfFfFfFfF";
+ LLAssert(llong::atoll(empty) == llong(0, 0));
+ LLAssert(llong::atoll(zero) == llong(0, 0));
+ LLAssert(llong::atoll(neg_one) == llong(0xffffffff, 0xffffffff));
+ LLAssert(llong::atoll(neg_12345) == -llong(0, 12345));
+ LLAssert(llong::atoll(big1, 16) == llong(0x12345678, 0x9abcdef0));
+ LLAssert(llong::atoll(big2, 16) == llong(0xffffffff, 0xffffffff));
+#endif
+
+ // u_atoll
+ const UChar uempty[] = { 0 };
+ const UChar uzero[] = { 0x30, 0 };
+ const UChar uneg_one[] = { 0x2d, 0x31, 0 };
+ const UChar uneg_12345[] = { 0x2d, 0x31, 0x32, 0x33, 0x34, 0x35, 0 };
+ const UChar ubig1[] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x30, 0 };
+ const UChar ubig2[] = { 0x66, 0x46, 0x66, 0x46, 0x66, 0x46, 0x66, 0x46, 0x66, 0x46, 0x66, 0x46, 0x66, 0x46, 0x66, 0x46, 0 };
+ LLAssert(llong::utoll(uempty) == llong(0, 0));
+ LLAssert(llong::utoll(uzero) == llong(0, 0));
+ LLAssert(llong::utoll(uneg_one) == llong(0xffffffff, 0xffffffff));
+ LLAssert(llong::utoll(uneg_12345) == -llong(0, 12345));
+ LLAssert(llong::utoll(ubig1, 16) == llong(0x12345678, 0x9abcdef0));
+ LLAssert(llong::utoll(ubig2, 16) == llong(0xffffffff, 0xffffffff));
+
+#ifdef RBNF_DEBUG
+ logln("Testing lltoa");
+ // lltoa
+ {
+ char buf[64]; // ascii
+ LLAssert((llong(0, 0).lltoa(buf, (uint32_t)sizeof(buf)) == 1) && (strcmp(buf, zero) == 0));
+ LLAssert((llong(0xffffffff, 0xffffffff).lltoa(buf, (uint32_t)sizeof(buf)) == 2) && (strcmp(buf, neg_one) == 0));
+ LLAssert(((-llong(0, 12345)).lltoa(buf, (uint32_t)sizeof(buf)) == 6) && (strcmp(buf, neg_12345) == 0));
+ LLAssert((llong(0x12345678, 0x9abcdef0).lltoa(buf, (uint32_t)sizeof(buf), 16) == 16) && (strcmp(buf, big1) == 0));
+ }
+#endif
+
+ logln("Testing u_lltoa");
+ // u_lltoa
+ {
+ UChar buf[64];
+ LLAssert((llong(0, 0).lltou(buf, (uint32_t)sizeof(buf)) == 1) && (u_strcmp(buf, uzero) == 0));
+ LLAssert((llong(0xffffffff, 0xffffffff).lltou(buf, (uint32_t)sizeof(buf)) == 2) && (u_strcmp(buf, uneg_one) == 0));
+ LLAssert(((-llong(0, 12345)).lltou(buf, (uint32_t)sizeof(buf)) == 6) && (u_strcmp(buf, uneg_12345) == 0));
+ LLAssert((llong(0x12345678, 0x9abcdef0).lltou(buf, (uint32_t)sizeof(buf), 16) == 16) && (u_strcmp(buf, ubig1) == 0));
+ }
+}
+
+/* if 0 */
+#endif
+
+void
+IntlTestRBNF::TestEnglishSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getUS(), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "1", "one" },
+ { "2", "two" },
+ { "15", "fifteen" },
+ { "20", "twenty" },
+ { "23", "twenty-three" },
+ { "73", "seventy-three" },
+ { "88", "eighty-eight" },
+ { "100", "one hundred" },
+ { "106", "one hundred and six" },
+ { "127", "one hundred and twenty-seven" },
+ { "200", "two hundred" },
+ { "579", "five hundred and seventy-nine" },
+ { "1,000", "one thousand" },
+ { "2,000", "two thousand" },
+ { "3,004", "three thousand and four" },
+ { "4,567", "four thousand five hundred and sixty-seven" },
+ { "15,943", "fifteen thousand nine hundred and forty-three" },
+ { "2,345,678", "two million, three hundred and forty-five thousand, six hundred and seventy-eight" },
+ { "-36", "minus thirty-six" },
+ { "234.567", "two hundred and thirty-four point five six seven" },
+ { NULL, NULL}
+ };
+
+ doTest(formatter, testData, TRUE);
+
+#if !UCONFIG_NO_COLLATION
+ formatter->setLenient(TRUE);
+ static const char* lpTestData[][2] = {
+ { "fifty-7", "57" },
+ { " fifty-7", "57" },
+ { " fifty-7", "57" },
+ { "2 thousand six HUNDRED fifty-7", "2,657" },
+ { "fifteen hundred and zero", "1,500" },
+ { "FOurhundred thiRTY six", "436" },
+ { NULL, NULL}
+ };
+ doLenientParseTest(formatter, lpTestData);
+#endif
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestOrdinalAbbreviations()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale::getUS(), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "1", "1st" },
+ { "2", "2nd" },
+ { "3", "3rd" },
+ { "4", "4th" },
+ { "7", "7th" },
+ { "10", "10th" },
+ { "11", "11th" },
+ { "13", "13th" },
+ { "20", "20th" },
+ { "21", "21st" },
+ { "22", "22nd" },
+ { "23", "23rd" },
+ { "24", "24th" },
+ { "33", "33rd" },
+ { "102", "102nd" },
+ { "312", "312th" },
+ { "12,345", "12,345th" },
+ { NULL, NULL}
+ };
+
+ doTest(formatter, testData, FALSE);
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestDurations()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_DURATION, Locale::getUS(), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "3,600", "1:00:00" }, //move me and I fail
+ { "0", "0 sec." },
+ { "1", "1 sec." },
+ { "24", "24 sec." },
+ { "60", "1:00" },
+ { "73", "1:13" },
+ { "145", "2:25" },
+ { "666", "11:06" },
+ // { "3,600", "1:00:00" },
+ { "3,740", "1:02:20" },
+ { "10,293", "2:51:33" },
+ { NULL, NULL}
+ };
+
+ doTest(formatter, testData, TRUE);
+
+#if !UCONFIG_NO_COLLATION
+ formatter->setLenient(TRUE);
+ static const char* lpTestData[][2] = {
+ { "2-51-33", "10,293" },
+ { NULL, NULL}
+ };
+ doLenientParseTest(formatter, lpTestData);
+#endif
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestSpanishSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("es", "ES", ""), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "1", "uno" },
+ { "6", "seis" },
+ { "16", "diecis\\u00e9is" },
+ { "20", "veinte" },
+ { "24", "veinticuatro" },
+ { "26", "veintis\\u00e9is" },
+ { "73", "setenta y tres" },
+ { "88", "ochenta y ocho" },
+ { "100", "cien" },
+ { "106", "ciento seis" },
+ { "127", "ciento veintisiete" },
+ { "200", "doscientos" },
+ { "579", "quinientos setenta y nueve" },
+ { "1,000", "mil" },
+ { "2,000", "dos mil" },
+ { "3,004", "tres mil cuatro" },
+ { "4,567", "cuatro mil quinientos sesenta y siete" },
+ { "15,943", "quince mil novecientos cuarenta y tres" },
+ { "2,345,678", "dos mill\\u00f3n trescientos cuarenta y cinco mil seiscientos setenta y ocho"},
+ { "-36", "menos treinta y seis" },
+ { "234.567", "doscientos treinta y cuatro punto cinco seis siete" },
+ { NULL, NULL}
+ };
+
+ doTest(formatter, testData, TRUE);
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestFrenchSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getFrance(), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "1", "un" },
+ { "15", "quinze" },
+ { "20", "vingt" },
+ { "21", "vingt-et-un" },
+ { "23", "vingt-trois" },
+ { "62", "soixante-deux" },
+ { "70", "soixante-dix" },
+ { "71", "soixante et onze" },
+ { "73", "soixante-treize" },
+ { "80", "quatre-vingts" },
+ { "88", "quatre-vingt-huit" },
+ { "100", "cent" },
+ { "106", "cent six" },
+ { "127", "cent vingt-sept" },
+ { "200", "deux cents" },
+ { "579", "cinq cents soixante-dix-neuf" },
+ { "1,000", "mille" },
+ { "1,123", "onze cents vingt-trois" },
+ { "1,594", "mille cinq cents quatre-vingt-quatorze" },
+ { "2,000", "deux mille" },
+ { "3,004", "trois mille quatre" },
+ { "4,567", "quatre mille cinq cents soixante-sept" },
+ { "15,943", "quinze mille neuf cents quarante-trois" },
+ { "2,345,678", "deux million trois cents quarante-cinq mille six cents soixante-dix-huit" },
+ { "-36", "moins trente-six" },
+ { "234.567", "deux cents trente-quatre virgule cinq six sept" },
+ { NULL, NULL}
+ };
+
+ doTest(formatter, testData, TRUE);
+
+#if !UCONFIG_NO_COLLATION
+ formatter->setLenient(TRUE);
+ static const char* lpTestData[][2] = {
+ { "trente-un", "31" },
+ { "un cents quatre vingt dix huit", "198" },
+ { NULL, NULL}
+ };
+ doLenientParseTest(formatter, lpTestData);
+#endif
+ }
+ delete formatter;
+}
+
+static const char* const swissFrenchTestData[][2] = {
+ { "1", "un" },
+ { "15", "quinze" },
+ { "20", "vingt" },
+ { "21", "vingt-et-un" },
+ { "23", "vingt-trois" },
+ { "62", "soixante-deux" },
+ { "70", "septante" },
+ { "71", "septante-et-un" },
+ { "73", "septante-trois" },
+ { "80", "huitante" },
+ { "88", "huitante-huit" },
+ { "100", "cent" },
+ { "106", "cent six" },
+ { "127", "cent vingt-sept" },
+ { "200", "deux cents" },
+ { "579", "cinq cents septante-neuf" },
+ { "1,000", "mille" },
+ { "1,123", "onze cents vingt-trois" },
+ { "1,594", "mille cinq cents nonante-quatre" },
+ { "2,000", "deux mille" },
+ { "3,004", "trois mille quatre" },
+ { "4,567", "quatre mille cinq cents soixante-sept" },
+ { "15,943", "quinze mille neuf cents quarante-trois" },
+ { "2,345,678", "deux million trois cents quarante-cinq mille six cents septante-huit" },
+ { "-36", "moins trente-six" },
+ { "234.567", "deux cents trente-quatre virgule cinq six sept" },
+ { NULL, NULL}
+};
+
+void
+IntlTestRBNF::TestSwissFrenchSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("fr", "CH", ""), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ doTest(formatter, swissFrenchTestData, TRUE);
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestBelgianFrenchSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("fr", "BE", ""), status);
+
+ if (U_FAILURE(status)) {
+ errln("rbnf status: 0x%x (%s)\n", status, u_errorName(status));
+ errln("FAIL: could not construct formatter");
+ } else {
+ // Belgian french should match Swiss french.
+ doTest(formatter, swissFrenchTestData, TRUE);
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestItalianSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getItalian(), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "1", "uno" },
+ { "15", "quindici" },
+ { "20", "venti" },
+ { "23", "ventitr\\u00E9" },
+ { "73", "settantatr\\u00E9" },
+ { "88", "ottantotto" },
+ { "100", "cento" },
+ { "106", "centosei" },
+ { "108", "centotto" },
+ { "127", "centoventisette" },
+ { "181", "centottantuno" },
+ { "200", "duecento" },
+ { "579", "cinquecentosettantanove" },
+ { "1,000", "mille" },
+ { "2,000", "duemila" },
+ { "3,004", "tremilaquattro" },
+ { "4,567", "quattromilacinquecentosessantasette" },
+ { "15,943", "quindicimilanovecentoquarantatr\\u00E9" },
+ { "-36", "meno trentasei" },
+ { "234.567", "duecentotrentaquattro virgola cinque sei sette" },
+ { NULL, NULL}
+ };
+
+ doTest(formatter, testData, TRUE);
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestPortugueseSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("pt","BR",""), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "1", "um" },
+ { "15", "quinze" },
+ { "20", "vinte" },
+ { "23", "vinte e tr\\u00EAs" },
+ { "73", "setenta e tr\\u00EAs" },
+ { "88", "oitenta e oito" },
+ { "100", "cem" },
+ { "106", "cento e seis" },
+ { "108", "cento e oito" },
+ { "127", "cento e vinte e sete" },
+ { "181", "cento e oitenta e um" },
+ { "200", "duzcentos" },
+ { "579", "quinhentos e setenta e nove" },
+ { "1,000", "mil" },
+ { "2,000", "dois mil" },
+ { "3,004", "tr\\u00EAs mil e quatro" },
+ { "4,567", "quatro mil quinhentos e sessenta e sete" },
+ { "15,943", "quinze mil novecentos e quarenta e tr\\u00EAs" },
+ { "-36", "menos trinta e seis" },
+ { "234.567", "duzcentos e trinta e quatro ponto cinco seis sete" },
+ { NULL, NULL}
+ };
+
+ doTest(formatter, testData, TRUE);
+ }
+ delete formatter;
+}
+void
+IntlTestRBNF::TestGermanSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getGermany(), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "1", "eins" },
+ { "15", "f\\u00fcnfzehn" },
+ { "20", "zwanzig" },
+ { "23", "dreiundzwanzig" },
+ { "73", "dreiundsiebzig" },
+ { "88", "achtundachtzig" },
+ { "100", "hundert" },
+ { "106", "hundertsechs" },
+ { "127", "hundertsiebenundzwanzig" },
+ { "200", "zweihundert" },
+ { "579", "f\\u00fcnfhundertneunundsiebzig" },
+ { "1,000", "tausend" },
+ { "2,000", "zweitausend" },
+ { "3,004", "dreitausendvier" },
+ { "4,567", "viertausendf\\u00fcnfhundertsiebenundsechzig" },
+ { "15,943", "f\\u00fcnfzehntausendneunhundertdreiundvierzig" },
+ { "2,345,678", "zwei Millionen dreihundertf\\u00fcnfundvierzigtausendsechshundertachtundsiebzig" },
+ { NULL, NULL}
+ };
+
+ doTest(formatter, testData, TRUE);
+
+#if !UCONFIG_NO_COLLATION
+ formatter->setLenient(TRUE);
+ static const char* lpTestData[][2] = {
+ { "ein Tausend sechs Hundert fuenfunddreissig", "1,635" },
+ { NULL, NULL}
+ };
+ doLenientParseTest(formatter, lpTestData);
+#endif
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestThaiSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("th"), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testData[][2] = {
+ { "0", "\\u0e28\\u0e39\\u0e19\\u0e22\\u0e4c" },
+ { "1", "\\u0e2b\\u0e19\\u0e36\\u0e48\\u0e07" },
+ { "10", "\\u0e2a\\u0e34\\u0e1a" },
+ { "11", "\\u0e2a\\u0e34\\u0e1a\\u0e40\\u0e2d\\u0e47\\u0e14" },
+ { "21", "\\u0e22\\u0e35\\u0e48\\u0e2a\\u0e34\\u0e1a\\u0e40\\u0e2d\\u0e47\\u0e14" },
+ { "101", "\\u0e2b\\u0e19\\u0e36\\u0e48\\u0e07\\u0e23\\u0e49\\u0e2d\\u0e22\\u0e2b\\u0e19\\u0e36\\u0e48\\u0e07" },
+ { "1.234", "\\u0e2b\\u0e19\\u0e36\\u0e48\\u0e07\\u0e08\\u0e38\\u0e14\\u0e2a\\u0e2d\\u0e07\\u0e2a\\u0e32\\u0e21\\u0e2a\\u0e35\\u0e48" },
+ { NULL, NULL}
+ };
+
+ doTest(formatter, testData, TRUE);
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestSwedishSpellout()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("sv"), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* testDataDefault[][2] = {
+ { "101", "etthundra\\u00aden" },
+ { "123", "etthundra\\u00adtjugotre" },
+ { "1,001", "ettusen en" },
+ { "1,100", "ettusen etthundra" },
+ { "1,101", "ettusen etthundra\\u00aden" },
+ { "1,234", "ettusen tv\\u00e5hundra\\u00adtrettiofyra" },
+ { "10,001", "tio\\u00adtusen en" },
+ { "11,000", "elva\\u00adtusen" },
+ { "12,000", "tolv\\u00adtusen" },
+ { "20,000", "tjugo\\u00adtusen" },
+ { "21,000", "tjugoen\\u00adtusen" },
+ { "21,001", "tjugoen\\u00adtusen en" },
+ { "200,000", "tv\\u00e5hundra\\u00adtusen" },
+ { "201,000", "tv\\u00e5hundra\\u00aden\\u00adtusen" },
+ { "200,200", "tv\\u00e5hundra\\u00adtusen tv\\u00e5hundra" },
+ { "2,002,000", "tv\\u00e5 miljoner tv\\u00e5\\u00adtusen" },
+ { "12,345,678", "tolv miljoner trehundra\\u00adfyrtiofem\\u00adtusen sexhundra\\u00adsjuttio\\u00e5tta" },
+ { "123,456.789", "etthundra\\u00adtjugotre\\u00adtusen fyrahundra\\u00adfemtiosex komma sju \\u00e5tta nio" },
+ { "-12,345.678", "minus tolv\\u00adtusen trehundra\\u00adfyrtiofem komma sex sju \\u00e5tta" },
+ { NULL, NULL }
+ };
+ doTest(formatter, testDataDefault, TRUE);
+
+ static const char* testDataNeutrum[][2] = {
+ { "101", "etthundra\\u00adett" },
+ { "1,001", "ettusen ett" },
+ { "1,101", "ettusen etthundra\\u00adett" },
+ { "10,001", "tio\\u00adtusen ett" },
+ { "21,001", "tjugoen\\u00adtusen ett" },
+ { NULL, NULL }
+ };
+
+ formatter->setDefaultRuleSet("%neutrum", status);
+ if (U_SUCCESS(status)) {
+ logln("testing neutrum rules");
+ doTest(formatter, testDataNeutrum, TRUE);
+ }
+ else {
+ errln("Can't test neutrum rules");
+ }
+
+ static const char* testDataYear[][2] = {
+ { "101", "etthundra\\u00adett" },
+ { "900", "niohundra" },
+ { "1,001", "tiohundra\\u00adett" },
+ { "1,100", "elvahundra" },
+ { "1,101", "elvahundra\\u00adett" },
+ { "1,234", "tolvhundra\\u00adtrettiofyra" },
+ { "2,001", "tjugohundra\\u00adett" },
+ { "10,001", "tio\\u00adtusen ett" },
+ { NULL, NULL }
+ };
+
+ formatter->setDefaultRuleSet("%year", status);
+ if (U_SUCCESS(status)) {
+ logln("testing year rules");
+ doTest(formatter, testDataYear, TRUE);
+ }
+ else {
+ errln("Can't test year rules");
+ }
+
+ }
+ delete formatter;
+}
+
+void
+IntlTestRBNF::TestSmallValues()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("en_US"), status);
+
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ static const char* const testDataDefault[][2] = {
+ { "0.001", "zero point zero zero one" },
+ { "0.0001", "zero point zero zero zero one" },
+ { "0.00001", "zero point zero zero zero zero one" },
+ { "0.000001", "zero point zero zero zero zero zero one" },
+ { "0.0000001", "zero point zero zero zero zero zero zero one" },
+ { "0.00000001", "zero point zero zero zero zero zero zero zero one" },
+ { "0.000000001", "zero point zero zero zero zero zero zero zero zero one" },
+ { "0.0000000001", "zero point zero zero zero zero zero zero zero zero zero one" },
+ { "0.00000000001", "zero point zero zero zero zero zero zero zero zero zero zero one" },
+ { "0.000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero one" },
+ { "0.0000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero zero one" },
+ { "0.00000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero zero zero one" },
+ { "0.000000000000001", "zero point zero zero zero zero zero zero zero zero zero zero zero zero zero zero one" },
+ { "10,000,000.001", "ten million point zero zero one" },
+ { "10,000,000.0001", "ten million point zero zero zero one" },
+ { "10,000,000.00001", "ten million point zero zero zero zero one" },
+ { "10,000,000.000001", "ten million point zero zero zero zero zero one" },
+ { "10,000,000.0000001", "ten million point zero zero zero zero zero zero one" },
+// { "10,000,000.00000001", "ten million point zero zero zero zero zero zero zero one" },
+// { "10,000,000.000000002", "ten million point zero zero zero zero zero zero zero zero two" },
+ { "10,000,000", "ten million" },
+// { "1,234,567,890.0987654", "one billion, two hundred and thirty-four million, five hundred and sixty-seven thousand, eight hundred and ninety point zero nine eight seven six five four" },
+// { "123,456,789.9876543", "one hundred and twenty-three million, four hundred and fifty-six thousand, seven hundred and eighty-nine point nine eight seven six five four three" },
+// { "12,345,678.87654321", "twelve million, three hundred and forty-five thousand, six hundred and seventy-eight point eight seven six five four three two one" },
+ { "1,234,567.7654321", "one million, two hundred and thirty-four thousand, five hundred and sixty-seven point seven six five four three two one" },
+ { "123,456.654321", "one hundred and twenty-three thousand, four hundred and fifty-six point six five four three two one" },
+ { "12,345.54321", "twelve thousand three hundred and forty-five point five four three two one" },
+ { "1,234.4321", "one thousand two hundred and thirty-four point four three two one" },
+ { "123.321", "one hundred and twenty-three point three two one" },
+ { "0.0000000011754944", "zero point zero zero zero zero zero zero zero zero one one seven five four nine four four" },
+ { "0.000001175494351", "zero point zero zero zero zero zero one one seven five four nine four three five one" },
+ { NULL, NULL }
+ };
+
+ doTest(formatter, testDataDefault, TRUE);
+
+ delete formatter;
+ }
+}
+
+void
+IntlTestRBNF::TestLocalizations(void)
+{
+ int i;
+ UnicodeString rules("%main:0:no;1:some;100:a lot;1000:tons;\n"
+ "%other:0:nada;1:yah, some;100:plenty;1000:more'n you'll ever need");
+
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError perror;
+ RuleBasedNumberFormat formatter(rules, perror, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not construct formatter");
+ } else {
+ {
+ static const char* const testData[][2] = {
+ { "0", "nada" },
+ { "5", "yah, some" },
+ { "423", "plenty" },
+ { "12345", "more'n you'll ever need" },
+ { NULL, NULL }
+ };
+ doTest(&formatter, testData, FALSE);
+ }
+
+ {
+ UnicodeString loc("<<%main, %other>,<en, Main, Other>,<fr, leMain, leOther>,<de, 'das Main', 'etwas anderes'>>");
+ static const char* const testData[][2] = {
+ { "0", "no" },
+ { "5", "some" },
+ { "423", "a lot" },
+ { "12345", "tons" },
+ { NULL, NULL }
+ };
+ RuleBasedNumberFormat formatter0(rules, loc, perror, status);
+ if (U_FAILURE(status)) {
+ errln("failed to build second formatter");
+ } else {
+ doTest(&formatter0, testData, FALSE);
+
+ {
+ // exercise localization info
+ Locale locale0("en__VALLEY@turkey=gobblegobble");
+ Locale locale1("de_DE_FOO");
+ Locale locale2("ja_JP");
+ UnicodeString name = formatter0.getRuleSetName(0);
+ if ( formatter0.getRuleSetDisplayName(0, locale0) == "Main"
+ && formatter0.getRuleSetDisplayName(0, locale1) == "das Main"
+ && formatter0.getRuleSetDisplayName(0, locale2) == "%main"
+ && formatter0.getRuleSetDisplayName(name, locale0) == "Main"
+ && formatter0.getRuleSetDisplayName(name, locale1) == "das Main"
+ && formatter0.getRuleSetDisplayName(name, locale2) == "%main"){
+ logln("getRuleSetDisplayName tested");
+ }else {
+ errln("failed to getRuleSetDisplayName");
+ }
+ }
+
+ for (i = 0; i < formatter0.getNumberOfRuleSetDisplayNameLocales(); ++i) {
+ Locale locale = formatter0.getRuleSetDisplayNameLocale(i, status);
+ if (U_SUCCESS(status)) {
+ for (int j = 0; j < formatter0.getNumberOfRuleSetNames(); ++j) {
+ UnicodeString name = formatter0.getRuleSetName(j);
+ UnicodeString lname = formatter0.getRuleSetDisplayName(j, locale);
+ UnicodeString msg = locale.getName();
+ msg.append(": ");
+ msg.append(name);
+ msg.append(" = ");
+ msg.append(lname);
+ logln(msg);
+ }
+ }
+ }
+ }
+ }
+
+ {
+ static const char* goodLocs[] = {
+ "", // zero-length ok, same as providing no localization data
+ "<<>>", // no public rule sets ok
+ "<<%main>>", // no localizations ok
+ "<<%main,>,<en, Main,>>", // comma before close angle ok
+ "<<%main>,<en, ',<>\" '>>", // quotes everything until next quote
+ "<<%main>,<'en', \"it's ok\">>", // double quotes work too
+ " \n <\n <\n %main\n >\n , \t <\t en\t , \tfoo \t\t > \n\n > \n ", // rule whitespace ok
+ };
+ int32_t goodLocsLen = sizeof(goodLocs)/sizeof(goodLocs[0]);
+
+ static const char* badLocs[] = {
+ " ", // non-zero length
+ "<>", // empty array
+ "<", // unclosed outer array
+ "<<", // unclosed inner array
+ "<<,>>", // unexpected comma
+ "<<''>>", // empty string
+ " x<<%main>>", // first non space char not open angle bracket
+ "<%main>", // missing inner array
+ "<<%main %other>>", // elements missing separating commma (spaces must be quoted)
+ "<<%main><en, Main>>", // arrays missing separating comma
+ "<<%main>,<en, main, foo>>", // too many elements in locale data
+ "<<%main>,<en>>", // too few elements in locale data
+ "<<<%main>>>", // unexpected open angle
+ "<<%main<>>>", // unexpected open angle
+ "<<%main, %other>,<en,,>>", // implicit empty strings
+ "<<%main>,<en,''>>", // empty string
+ "<<%main>, < en, '>>", // unterminated quote
+ "<<%main>, < en, \"<>>", // unterminated quote
+ "<<%main\">>", // quote in string
+ "<<%main'>>", // quote in string
+ "<<%main<>>", // open angle in string
+ "<<%main>> x", // extra non-space text at end
+
+ };
+ int32_t badLocsLen = sizeof(badLocs)/sizeof(badLocs[0]);
+
+ for (i = 0; i < goodLocsLen; ++i) {
+ logln("[%d] '%s'", i, goodLocs[i]);
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString loc(goodLocs[i]);
+ RuleBasedNumberFormat fmt(rules, loc, perror, status);
+ if (U_FAILURE(status)) {
+ errln("Failed parse of good localization string: '%s'", goodLocs[i]);
+ }
+ }
+
+ for (i = 0; i < badLocsLen; ++i) {
+ logln("[%d] '%s'", i, badLocs[i]);
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString loc(badLocs[i]);
+ RuleBasedNumberFormat fmt(rules, loc, perror, status);
+ if (U_SUCCESS(status)) {
+ errln("Successful parse of bad localization string: '%s'", badLocs[i]);
+ }
+ }
+ }
+ }
+}
+
+void
+IntlTestRBNF::TestAllLocales()
+{
+ const char* names[] = {
+ " (spellout) ",
+ " (ordinal) ",
+ " (duration) "
+ };
+ int32_t count = 0;
+ const Locale* locales = Locale::getAvailableLocales(count);
+ for (int i = 0; i < count; ++i) {
+ const Locale* loc = &locales[i];
+ for (int j = 0; j < 3; ++j) {
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* f = new RuleBasedNumberFormat((URBNFRuleSetTag)j, *loc, status);
+ if (U_SUCCESS(status)) {
+ double n = 45.678;
+ UnicodeString str;
+ f->format(n, str);
+ delete f;
+
+ logln(UnicodeString(loc->getName()) + UnicodeString(names[j])
+ + UnicodeString("success: 45.678 -> ") + str);
+ } else {
+ errln(UnicodeString(loc->getName()) + UnicodeString(names[j])
+ + UnicodeString("ERROR could not instantiate -> ") + UnicodeString(u_errorName(status)));
+ }
+ }
+ }
+}
+
+void
+IntlTestRBNF::TestMultiplierSubstitution(void) {
+ UnicodeString rules("=#,##0=;1,000,000: <##0.###< million;");
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parse_error;
+ RuleBasedNumberFormat *rbnf =
+ new RuleBasedNumberFormat(rules, Locale::getUS(), parse_error, status);
+ if (U_SUCCESS(status)) {
+ UnicodeString res;
+ FieldPosition pos;
+ double n = 1234000.0;
+ rbnf->format(n, res, pos);
+ delete rbnf;
+
+ UnicodeString expected = UNICODE_STRING_SIMPLE("1.234 million");
+ if (expected != res) {
+ UnicodeString msg = "Expected: ";
+ msg.append(expected);
+ msg.append(" but got ");
+ msg.append(res);
+ errln(msg);
+ }
+ }
+}
+
+void
+IntlTestRBNF::doTest(RuleBasedNumberFormat* formatter, const char* const testData[][2], UBool testParsing)
+{
+ // man, error reporting would be easier with printf-style syntax for unicode string and formattable
+
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols dfs("en", status);
+ // NumberFormat* decFmt = NumberFormat::createInstance(Locale::getUS(), status);
+ DecimalFormat decFmt("#,###.################", dfs, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not create NumberFormat");
+ } else {
+ for (int i = 0; testData[i][0]; ++i) {
+ const char* numString = testData[i][0];
+ const char* expectedWords = testData[i][1];
+
+ log("[%i] %s = ", i, numString);
+ Formattable expectedNumber;
+ decFmt.parse(numString, expectedNumber, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: decFmt could not parse %s", numString);
+ break;
+ } else {
+ UnicodeString actualString;
+ FieldPosition pos;
+ formatter->format(expectedNumber, actualString/* , pos*/, status);
+ if (U_FAILURE(status)) {
+ UnicodeString msg = "Fail: formatter could not format ";
+ decFmt.format(expectedNumber, msg, status);
+ errln(msg);
+ break;
+ } else {
+ UnicodeString expectedString = UnicodeString(expectedWords).unescape();
+ if (actualString != expectedString) {
+ UnicodeString msg = "FAIL: check failed for ";
+ decFmt.format(expectedNumber, msg, status);
+ msg.append(", expected ");
+ msg.append(expectedString);
+ msg.append(" but got ");
+ msg.append(actualString);
+ errln(msg);
+ break;
+ } else {
+ logln(actualString);
+ if (testParsing) {
+ Formattable parsedNumber;
+ formatter->parse(actualString, parsedNumber, status);
+ if (U_FAILURE(status)) {
+ UnicodeString msg = "FAIL: formatter could not parse ";
+ msg.append(actualString);
+ msg.append(" status code: " );
+ msg.append(u_errorName(status));
+ errln(msg);
+ break;
+ } else {
+ if (parsedNumber != expectedNumber) {
+ UnicodeString msg = "FAIL: parse failed for ";
+ msg.append(actualString);
+ msg.append(", expected ");
+ decFmt.format(expectedNumber, msg, status);
+ msg.append(", but got ");
+ decFmt.format(parsedNumber, msg, status);
+ errln(msg);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+IntlTestRBNF::doLenientParseTest(RuleBasedNumberFormat* formatter, const char* testData[][2])
+{
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat* decFmt = NumberFormat::createInstance(Locale::getUS(), status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: could not create NumberFormat");
+ } else {
+ for (int i = 0; testData[i][0]; ++i) {
+ const char* spelledNumber = testData[i][0]; // spelled-out number
+ const char* asciiUSNumber = testData[i][1]; // number as ascii digits formatted for US locale
+
+ UnicodeString spelledNumberString = UnicodeString(spelledNumber).unescape();
+ Formattable actualNumber;
+ formatter->parse(spelledNumberString, actualNumber, status);
+ if (U_FAILURE(status)) {
+ UnicodeString msg = "FAIL: formatter could not parse ";
+ msg.append(spelledNumberString);
+ errln(msg);
+ break;
+ } else {
+ // I changed the logic of this test somewhat from Java-- instead of comparing the
+ // strings, I compare the Formattables. Hmmm, but the Formattables don't compare,
+ // so change it back.
+
+ UnicodeString asciiUSNumberString = asciiUSNumber;
+ Formattable expectedNumber;
+ decFmt->parse(asciiUSNumberString, expectedNumber, status);
+ if (U_FAILURE(status)) {
+ UnicodeString msg = "FAIL: decFmt could not parse ";
+ msg.append(asciiUSNumberString);
+ errln(msg);
+ break;
+ } else {
+ UnicodeString actualNumberString;
+ UnicodeString expectedNumberString;
+ decFmt->format(actualNumber, actualNumberString, status);
+ decFmt->format(expectedNumber, expectedNumberString, status);
+ if (actualNumberString != expectedNumberString) {
+ UnicodeString msg = "FAIL: parsing";
+ msg.append(asciiUSNumberString);
+ msg.append("\n");
+ msg.append(" lenient parse failed for ");
+ msg.append(spelledNumberString);
+ msg.append(", expected ");
+ msg.append(expectedNumberString);
+ msg.append(", but got ");
+ msg.append(actualNumberString);
+ errln(msg);
+ break;
+ }
+ }
+ }
+ }
+ delete decFmt;
+ }
+}
+
+/* U_HAVE_RBNF */
+#else
+
+void
+IntlTestRBNF::TestRBNFDisabled() {
+ errln("*** RBNF currently disabled on this platform ***\n");
+}
+
+/* U_HAVE_RBNF */
+#endif
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itrbnf.h b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnf.h
new file mode 100644
index 00000000000..939077b4752
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnf.h
@@ -0,0 +1,147 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef ITRBNF_H
+#define ITRBNF_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+#include "unicode/rbnf.h"
+
+
+class IntlTestRBNF : public IntlTest {
+ public:
+
+ // IntlTest override
+ virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par);
+
+#if U_HAVE_RBNF
+ /**
+ * Perform an API test
+ */
+ virtual void TestAPI();
+
+ /**
+ * Perform a simple spot check on the FractionalRuleSet logic
+ */
+ virtual void TestFractionalRuleSet();
+
+#if 0
+ /**
+ * Perform API tests on llong
+ */
+ virtual void TestLLong();
+ virtual void TestLLongConstructors();
+ virtual void TestLLongSimpleOperators();
+#endif
+
+ /**
+ * Perform a simple spot check on the English spellout rules
+ */
+ virtual void TestEnglishSpellout();
+
+ /**
+ * Perform a simple spot check on the English ordinal-abbreviation rules
+ */
+ virtual void TestOrdinalAbbreviations();
+
+ /**
+ * Perform a simple spot check on the duration-formatting rules
+ */
+ virtual void TestDurations();
+
+ /**
+ * Perform a simple spot check on the Spanish spellout rules
+ */
+ virtual void TestSpanishSpellout();
+
+ /**
+ * Perform a simple spot check on the French spellout rules
+ */
+ virtual void TestFrenchSpellout();
+
+ /**
+ * Perform a simple spot check on the Swiss French spellout rules
+ */
+ virtual void TestSwissFrenchSpellout();
+
+ /**
+ * Check that Belgian French matches Swiss French spellout rules
+ */
+ virtual void TestBelgianFrenchSpellout();
+
+ /**
+ * Perform a simple spot check on the Italian spellout rules
+ */
+ virtual void TestItalianSpellout();
+
+ /**
+ * Perform a simple spot check on the Portuguese spellout rules
+ */
+ virtual void TestPortugueseSpellout();
+
+ /**
+ * Perform a simple spot check on the German spellout rules
+ */
+ virtual void TestGermanSpellout();
+
+ /**
+ * Perform a simple spot check on the Thai spellout rules
+ */
+ virtual void TestThaiSpellout();
+
+ /**
+ * Perform a simple spot check on the Swedish spellout rules
+ */
+ virtual void TestSwedishSpellout();
+
+ /**
+ * Perform a simple spot check on small values
+ */
+ virtual void TestSmallValues();
+
+ /**
+ * Test localizations using string data.
+ */
+ virtual void TestLocalizations();
+
+ /**
+ * Test that all locales construct ok.
+ */
+ virtual void TestAllLocales();
+
+ /**
+ * Test that hebrew fractions format without trailing '<'
+ */
+ virtual void TestHebrewFraction();
+
+ /**
+ * Regression test, don't truncate
+ * when doing multiplier substitution to a number format rule.
+ */
+ virtual void TestMultiplierSubstitution();
+
+ protected:
+ virtual void doTest(RuleBasedNumberFormat* formatter, const char* const testData[][2], UBool testParsing);
+ virtual void doLenientParseTest(RuleBasedNumberFormat* formatter, const char* testData[][2]);
+
+/* U_HAVE_RBNF */
+#else
+
+ virtual void TestRBNFDisabled();
+
+/* U_HAVE_RBNF */
+#endif
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+// endif ITRBNF_H
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfp.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfp.cpp
new file mode 100644
index 00000000000..907647875cd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfp.cpp
@@ -0,0 +1,183 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2004, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "itrbnfp.h"
+
+#include "unicode/umachine.h"
+
+#include "unicode/tblcoll.h"
+#include "unicode/coleitr.h"
+#include "unicode/ures.h"
+#include "unicode/ustring.h"
+#include "unicode/decimfmt.h"
+
+#include <string.h>
+
+// current macro not in icu1.8.1
+#define TESTCASE(id,test) \
+ case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ test(); \
+ } \
+ break
+
+void IntlTestRBNFParse::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/)
+{
+ if (exec) logln("TestSuite RuleBasedNumberFormatParse");
+ switch (index) {
+#if U_HAVE_RBNF
+ TESTCASE(0, TestParse);
+#else
+ TESTCASE(0, TestRBNFParseDisabled);
+#endif
+ default:
+ name = "";
+ break;
+ }
+}
+
+#if U_HAVE_RBNF
+
+void
+IntlTestRBNFParse::TestParse() {
+ // Try various rule parsing errors. Shouldn't crash.
+
+ logln("RBNF Parse test starting");
+
+ // these rules make no sense but behave rationally
+ const char* okrules[] = {
+ "",
+ "random text",
+ "%foo:bar",
+ "%foo: bar",
+ "0:",
+ "0::",
+ ";",
+ ";;",
+ "%%foo:;",
+ ":",
+ "::",
+ ":1",
+ ":;",
+ ":;:;",
+ "-",
+ "-1",
+ "-:",
+ ".",
+ ".1",
+ "[",
+ "]",
+ "[]",
+ "[foo]",
+ "[[]",
+ "[]]",
+ "[[]]",
+ "[][]",
+ "<",
+ "<<",
+ "<<<",
+ "10:;9:;",
+ ">",
+ ">>",
+ ">>>",
+ "=",
+ "==",
+ "===",
+ "=foo=",
+
+ NULL,
+ };
+
+ // these rules would throw exceptions when formatting, if we could throw exceptions
+ const char* exceptrules[] = {
+ "10:", // formatting any value with a one's digit will fail
+ "11: << x", // formating a multiple of 10 causes rollback rule to fail
+ "%%foo: 0 foo; 10: =%%bar=; %%bar: 0: bar; 10: =%%foo=;",
+
+ NULL,
+ };
+
+ // none of these rules should crash the formatter
+ const char** allrules[] = {
+ okrules,
+ exceptrules,
+ NULL,
+ };
+
+ for (int j = 0; allrules[j]; ++j) {
+ const char** rules = allrules[j];
+ for (int i = 0; rules[i]; ++i) {
+ const char* rule = rules[i];
+ logln("rule[%d] \"%s\"", i, rule);
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError perr;
+ RuleBasedNumberFormat* formatter = new RuleBasedNumberFormat(rule, Locale::getUS(), perr, status);
+
+ if (U_SUCCESS(status)) {
+ // format some values
+
+ testfmt(formatter, 20, status);
+ testfmt(formatter, 1.23, status);
+ testfmt(formatter, -123, status);
+ testfmt(formatter, .123, status);
+ testfmt(formatter, 123, status);
+
+ } else if (status == U_PARSE_ERROR) {
+ logln("perror line: %x offset: %x context: %s|%s", perr.line, perr.offset, perr.preContext, perr.postContext);
+ }
+
+ delete formatter;
+ }
+ }
+}
+
+void
+IntlTestRBNFParse::testfmt(RuleBasedNumberFormat* formatter, double val, UErrorCode& status) {
+ UnicodeString us;
+ formatter->format((const Formattable)val, us, status);
+ if (U_SUCCESS(status)) {
+ us.insert(0, (UChar)'"');
+ us.append((UChar)'"');
+ logln(us);
+ } else {
+ logln("error: could not format %g, returned status: %d", val, status);
+ }
+}
+
+void
+IntlTestRBNFParse::testfmt(RuleBasedNumberFormat* formatter, int val, UErrorCode& status) {
+ UnicodeString us;
+ formatter->format((const Formattable)(int32_t)val, us, status);
+ if (U_SUCCESS(status)) {
+ us.insert(0, (UChar)'"');
+ us.append((UChar)'"');
+ logln(us);
+ } else {
+ logln("error: could not format %d, returned status: %d", val, status);
+ }
+}
+
+
+/* U_HAVE_RBNF */
+#else
+
+void
+IntlTestRBNF::TestRBNFParseDisabled() {
+ errln("*** RBNF currently disabled on this platform ***\n");
+}
+
+/* U_HAVE_RBNF */
+#endif
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfp.h b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfp.h
new file mode 100644
index 00000000000..c767ff195f8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfp.h
@@ -0,0 +1,48 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2004, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef ITRBNFP_H
+#define ITRBNFP_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+#include "unicode/rbnf.h"
+
+
+class IntlTestRBNFParse : public IntlTest {
+ public:
+
+ // IntlTest override
+ virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par);
+
+#if U_HAVE_RBNF
+ /**
+ * Perform an API test
+ */
+ virtual void TestParse();
+
+ void testfmt(RuleBasedNumberFormat* formatter, double val, UErrorCode& status);
+ void testfmt(RuleBasedNumberFormat* formatter, int val, UErrorCode& status);
+
+ protected:
+
+/* U_HAVE_RBNF */
+#else
+
+ virtual void TestRBNFParseDisabled();
+
+/* U_HAVE_RBNF */
+#endif
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+// endif ITRBNFP_H
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfrt.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfrt.cpp
new file mode 100644
index 00000000000..515b351d945
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfrt.cpp
@@ -0,0 +1,364 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2006, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "itrbnfrt.h"
+
+#include "unicode/fmtable.h"
+#include <math.h> // fabs
+#include <stdio.h>
+
+// current macro not in icu1.8.1
+#define TESTCASE(id,test) \
+ case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ test(); \
+ } \
+ break
+
+void RbnfRoundTripTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/)
+{
+ if (exec) logln("TestSuite RuleBasedNumberFormatRT");
+ switch (index) {
+#if U_HAVE_RBNF
+ TESTCASE(0, TestEnglishSpelloutRT);
+ TESTCASE(1, TestDurationsRT);
+ TESTCASE(2, TestSpanishSpelloutRT);
+ TESTCASE(3, TestFrenchSpelloutRT);
+ TESTCASE(4, TestSwissFrenchSpelloutRT);
+ TESTCASE(5, TestItalianSpelloutRT);
+ TESTCASE(6, TestGermanSpelloutRT);
+ TESTCASE(7, TestSwedishSpelloutRT);
+ TESTCASE(8, TestDutchSpelloutRT);
+ TESTCASE(9, TestJapaneseSpelloutRT);
+ TESTCASE(10, TestRussianSpelloutRT);
+ TESTCASE(11, TestPortugueseSpelloutRT);
+#else
+ TESTCASE(0, TestRBNFDisabled);
+#endif
+ default:
+ name = "";
+ break;
+ }
+}
+
+#if U_HAVE_RBNF
+
+/**
+ * Perform an exhaustive round-trip test on the English spellout rules
+ */
+void
+RbnfRoundTripTest::TestEnglishSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getUS(), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, -12345678, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the duration-formatting rules
+ */
+void
+RbnfRoundTripTest::TestDurationsRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_DURATION, Locale::getUS(), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, 0, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the Spanish spellout rules
+ */
+void
+RbnfRoundTripTest::TestSpanishSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("es", "es"), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, -12345678, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the French spellout rules
+ */
+void
+RbnfRoundTripTest::TestFrenchSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getFrance(), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, -12345678, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the Swiss French spellout rules
+ */
+void
+RbnfRoundTripTest::TestSwissFrenchSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("fr", "CH"), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, -12345678, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the Italian spellout rules
+ */
+void
+RbnfRoundTripTest::TestItalianSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getItalian(), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, -999999, 999999);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the German spellout rules
+ */
+void
+RbnfRoundTripTest::TestGermanSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getGermany(), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, 0, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the Swedish spellout rules
+ */
+void
+RbnfRoundTripTest::TestSwedishSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("sv", "SE"), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, 0, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the Dutch spellout rules
+ */
+void
+RbnfRoundTripTest::TestDutchSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("nl", "NL"), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, -12345678, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the Japanese spellout rules
+ */
+void
+RbnfRoundTripTest::TestJapaneseSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale::getJapan(), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, 0, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the Russian spellout rules
+ */
+void
+RbnfRoundTripTest::TestRussianSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("ru", "RU"), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, 0, 12345678);
+ }
+ delete formatter;
+}
+
+/**
+ * Perform an exhaustive round-trip test on the Portuguese spellout rules
+ */
+void
+RbnfRoundTripTest::TestPortugueseSpelloutRT()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat* formatter
+ = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale("pt", "BR"), status);
+
+ if (U_FAILURE(status)) {
+ errln("failed to construct formatter");
+ } else {
+ doTest(formatter, -12345678, 12345678);
+ }
+ delete formatter;
+}
+
+void
+RbnfRoundTripTest::doTest(const RuleBasedNumberFormat* formatter,
+ double lowLimit,
+ double highLimit)
+{
+ char buf[128];
+
+ uint32_t count = 0;
+ double increment = 1;
+ for (double i = lowLimit; i <= highLimit; i += increment) {
+ if (count % 1000 == 0) {
+ sprintf(buf, "%.12g", i);
+ logln(buf);
+ }
+
+ if (fabs(i) < 5000)
+ increment = 1;
+ else if (fabs(i) < 500000)
+ increment = 2737;
+ else
+ increment = 267437;
+
+ UnicodeString formatResult;
+ formatter->format(i, formatResult);
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable parseResult;
+ formatter->parse(formatResult, parseResult, status);
+ if (U_FAILURE(status)) {
+ sprintf(buf, "Round-trip status failure: %.12g, status: %d", i, status);
+ errln(buf);
+ return;
+ } else {
+ double rt = (parseResult.getType() == Formattable::kDouble) ?
+ parseResult.getDouble() :
+ (double)parseResult.getLong();
+
+ if (rt != i) {
+ sprintf(buf, "Round-trip failed: %.12g -> %.12g", i, rt);
+ errln(buf);
+ return;
+ }
+ }
+
+ ++count;
+ }
+
+ if (lowLimit < 0) {
+ double d = 1.234;
+ while (d < 1000) {
+ UnicodeString formatResult;
+ formatter->format(d, formatResult);
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable parseResult;
+ formatter->parse(formatResult, parseResult, status);
+ if (U_FAILURE(status)) {
+ sprintf(buf, "Round-trip status failure: %.12g, status: %d", d, status);
+ errln(buf);
+ return;
+ } else {
+ double rt = (parseResult.getType() == Formattable::kDouble) ?
+ parseResult.getDouble() :
+ (double)parseResult.getLong();
+
+ if (rt != d) {
+ UnicodeString msg;
+ sprintf(buf, "Round-trip failed: %.12g -> ", d);
+ msg.append(buf);
+ msg.append(formatResult);
+ sprintf(buf, " -> %.12g", rt);
+ msg.append(buf);
+ errln(msg);
+ return;
+ }
+ }
+
+ d *= 10;
+ }
+ }
+}
+
+/* U_HAVE_RBNF */
+#else
+
+void
+RbnfRoundTripTest::TestRBNFDisabled() {
+ errln("*** RBNF currently disabled on this platform ***\n");
+}
+
+/* U_HAVE_RBNF */
+#endif
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfrt.h b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfrt.h
new file mode 100644
index 00000000000..70bf23f6f5f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itrbnfrt.h
@@ -0,0 +1,99 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 1996-2006, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#ifndef ITRBNFRT_H
+#define ITRBNFRT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+#include "unicode/rbnf.h"
+
+class RbnfRoundTripTest : public IntlTest {
+
+ // IntlTest override
+ virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par);
+
+#if U_HAVE_RBNF
+ /**
+ * Perform an exhaustive round-trip test on the English spellout rules
+ */
+ virtual void TestEnglishSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the duration-formatting rules
+ */
+ virtual void TestDurationsRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the Spanish spellout rules
+ */
+ virtual void TestSpanishSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the French spellout rules
+ */
+ virtual void TestFrenchSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the Swiss French spellout rules
+ */
+ virtual void TestSwissFrenchSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the Italian spellout rules
+ */
+ virtual void TestItalianSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the German spellout rules
+ */
+ virtual void TestGermanSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the Swedish spellout rules
+ */
+ virtual void TestSwedishSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the Dutch spellout rules
+ */
+ virtual void TestDutchSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the Japanese spellout rules
+ */
+ virtual void TestJapaneseSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the Russian spellout rules
+ */
+ virtual void TestRussianSpelloutRT();
+
+ /**
+ * Perform an exhaustive round-trip test on the Portuguese spellout rules
+ */
+ virtual void TestPortugueseSpelloutRT();
+
+ protected:
+ void doTest(const RuleBasedNumberFormat* formatter, double lowLimit, double highLimit);
+
+ /* U_HAVE_RBNF */
+#else
+
+ void TestRBNFDisabled();
+
+ /* U_HAVE_RBNF */
+#endif
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+// endif ITRBNFRT_H
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ittrans.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/ittrans.cpp
new file mode 100644
index 00000000000..467ced423a1
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ittrans.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+*
+* Copyright (C) 2000-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+************************************************************************
+* Date Name Description
+* 01/03/2000 Madhu Creation.
+* 03/2000 Madhu Added additional tests
+***********************************************************************/
+/**
+ * IntlTestTransliterator is the medium level test class for Transliterator
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "ittrans.h"
+#include "transtst.h"
+#include "transapi.h"
+#include "cpdtrtst.h"
+#include "transrt.h"
+#include "jamotest.h"
+#include "trnserr.h"
+#include "reptest.h"
+
+#define CASE(id,test) case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); logln(); \
+ test t; \
+ callTest(t, par); \
+ } \
+ break
+
+void IntlTestTransliterator::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+{
+ if (exec) logln("TestSuite Transliterator");
+ switch (index) {
+ CASE(0, TransliteratorTest);
+ CASE(1, TransliteratorAPITest);
+ CASE(2, CompoundTransliteratorTest);
+ CASE(3, TransliteratorRoundTripTest);
+ CASE(4, JamoTest);
+ CASE(5, TransliteratorErrorTest);
+ CASE(6, ReplaceableTest);
+#if !UCONFIG_NO_TRANSLITERATION && defined(U_USE_UNICODE_FILTER_LOGIC_OBSOLETE_2_8)
+ CASE(7, UnicodeFilterLogicTest);
+#endif
+
+ default: name=""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ittrans.h b/Build/source/libs/icu/icu-xetex/test/intltest/ittrans.h
new file mode 100644
index 00000000000..4f4fb38dbb7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ittrans.h
@@ -0,0 +1,31 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/************************************************************************
+* Date Name Description
+* 12/14/99 Madhu Creation.
+************************************************************************/
+/**
+ * IntlTestRBBI is the top level test class for the RuleBasedBreakIterator tests
+ */
+
+#ifndef INTLTRANSLIT_H
+#define INTLTRANSLIT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "intltest.h"
+
+
+class IntlTestTransliterator: public IntlTest {
+public:
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+};
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itutil.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/itutil.cpp
new file mode 100644
index 00000000000..218c1c83049
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itutil.cpp
@@ -0,0 +1,66 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+/**
+ * IntlTestUtilities is the medium level test class for everything in the directory "utility".
+ */
+
+#include "unicode/utypes.h"
+#include "itutil.h"
+#include "strtest.h"
+#include "loctest.h"
+#include "citrtest.h"
+#include "ustrtest.h"
+#include "ucdtest.h"
+#include "restest.h"
+#include "restsnew.h"
+#include "tsmthred.h"
+#include "tsputil.h"
+#include "uobjtest.h"
+#include "utxttest.h"
+#include "v32test.h"
+#include "uvectest.h"
+#include "aliastst.h"
+#include "usettest.h"
+//#include "custrtest.h"
+//#include "ccitrtst.h"
+//#include "cloctest.h"
+//#include "ctres.h"
+//#include "ctucd.h"
+
+#define CASE(id, test) case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); logln(); \
+ test t; \
+ callTest(t, par); \
+ } \
+ break
+
+void IntlTestUtilities::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+{
+ if (exec) logln("TestSuite Utilities: ");
+ switch (index) {
+ CASE(0, MultithreadTest);
+ CASE(1, StringTest);
+ CASE(2, UnicodeStringTest);
+ CASE(3, LocaleTest);
+ CASE(4, CharIterTest);
+ CASE(5, UnicodeTest);
+ CASE(6, ResourceBundleTest);
+ CASE(7, NewResourceBundleTest);
+ CASE(8, PUtilTest);
+ CASE(9, UObjectTest);
+ CASE(10, UVector32Test);
+ CASE(11, UVectorTest);
+ CASE(12, UTextTest);
+ CASE(13, MultithreadTest);
+ CASE(14, UnicodeSetTest);
+ default: name = ""; break; //needed to end loop
+ }
+}
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/itutil.h b/Build/source/libs/icu/icu-xetex/test/intltest/itutil.h
new file mode 100644
index 00000000000..e2dd8e10e3c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/itutil.h
@@ -0,0 +1,24 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * MajorTestLevel is the top level test class for everything in the directory "IntlWork".
+ */
+
+#ifndef _INTLTESTUTILITIES
+#define _INTLTESTUTILITIES
+
+
+#include "intltest.h"
+
+
+class IntlTestUtilities: public IntlTest {
+public:
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+};
+
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/jacoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/jacoll.cpp
new file mode 100644
index 00000000000..8c8c3d67d58
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/jacoll.cpp
@@ -0,0 +1,199 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/unistr.h"
+#include "unicode/sortkey.h"
+#include "jacoll.h"
+
+#include "sfwdchit.h"
+
+CollationKanaTest::CollationKanaTest()
+: myCollation(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation = Collator::createInstance(Locale::getJapan(), status);
+ if(!myCollation || U_FAILURE(status)) {
+ errln(__FILE__ "failed to create! err " + UnicodeString(u_errorName(status)));
+ /* if it wasn't already: */
+ delete myCollation;
+ myCollation = NULL;
+ return;
+ }
+}
+
+CollationKanaTest::~CollationKanaTest()
+{
+ delete myCollation;
+}
+
+const UChar CollationKanaTest::testSourceCases[][CollationKanaTest::MAX_TOKEN_LEN] = {
+ {0xff9E, 0x0000},
+ {0x3042, 0x0000},
+ {0x30A2, 0x0000},
+ {0x3042, 0x3042, 0x0000},
+ {0x30A2, 0x30FC, 0x0000},
+ {0x30A2, 0x30FC, 0x30C8, 0x0000} /* 6 */
+};
+
+const UChar CollationKanaTest::testTargetCases[][CollationKanaTest::MAX_TOKEN_LEN] = {
+ {0xFF9F, 0x0000},
+ {0x30A2, 0x0000},
+ {0x3042, 0x3042, 0x0000},
+ {0x30A2, 0x30FC, 0x0000},
+ {0x30A2, 0x30FC, 0x30C8, 0x0000},
+ {0x3042, 0x3042, 0x3068, 0x0000} /* 6 */
+};
+
+const Collator::EComparisonResult CollationKanaTest::results[] = {
+ Collator::LESS,
+ Collator::EQUAL, //Collator::LESS, /* Katakanas and Hiraganas are equal on tertiary level(ICU 2.0)*/
+ Collator::LESS,
+ Collator::GREATER, // Collator::LESS, /* Prolonged sound mark sorts BEFORE equivalent vowel (ICU 2.0)*/
+ Collator::LESS,
+ Collator::LESS, //Collator::GREATER /* Prolonged sound mark sorts BEFORE equivalent vowel (ICU 2.0)*//* 6 */
+};
+
+const UChar CollationKanaTest::testBaseCases[][CollationKanaTest::MAX_TOKEN_LEN] = {
+ {0x30AB, 0x0000},
+ {0x30AB, 0x30AD, 0x0000},
+ {0x30AD, 0x0000},
+ {0x30AD, 0x30AD, 0x0000}
+};
+
+const UChar CollationKanaTest::testPlainDakutenHandakutenCases[][CollationKanaTest::MAX_TOKEN_LEN] = {
+ {0x30CF, 0x30AB, 0x0000},
+ {0x30D0, 0x30AB, 0x0000},
+ {0x30CF, 0x30AD, 0x0000},
+ {0x30D0, 0x30AD, 0x0000}
+};
+
+const UChar CollationKanaTest::testSmallLargeCases[][CollationKanaTest::MAX_TOKEN_LEN] = {
+ {0x30C3, 0x30CF, 0x0000},
+ {0x30C4, 0x30CF, 0x0000},
+ {0x30C3, 0x30D0, 0x0000},
+ {0x30C4, 0x30D0, 0x0000}
+};
+
+const UChar CollationKanaTest::testKatakanaHiraganaCases[][CollationKanaTest::MAX_TOKEN_LEN] = {
+ {0x3042, 0x30C3, 0x0000},
+ {0x30A2, 0x30C3, 0x0000},
+ {0x3042, 0x30C4, 0x0000},
+ {0x30A2, 0x30C4, 0x0000}
+};
+
+const UChar CollationKanaTest::testChooonKigooCases[][CollationKanaTest::MAX_TOKEN_LEN] = {
+ /*0*/ {0x30AB, 0x30FC, 0x3042, 0x0000},
+ /*1*/ {0x30AB, 0x30FC, 0x30A2, 0x0000},
+ /*2*/ {0x30AB, 0x30A4, 0x3042, 0x0000},
+ /*3*/ {0x30AB, 0x30A4, 0x30A2, 0x0000},
+ /*6*/ {0x30AD, 0x30FC, 0x3042, 0x0000}, /* Prolonged sound mark sorts BEFORE equivalent vowel (ICU 2.0)*/
+ /*7*/ {0x30AD, 0x30FC, 0x30A2, 0x0000}, /* Prolonged sound mark sorts BEFORE equivalent vowel (ICU 2.0)*/
+ /*4*/ {0x30AD, 0x30A4, 0x3042, 0x0000},
+ /*5*/ {0x30AD, 0x30A4, 0x30A2, 0x0000},
+};
+
+void CollationKanaTest::TestTertiary(/* char* par */)
+{
+ int32_t i = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation->setStrength(Collator::TERTIARY);
+ /* for one case, strcollinc fails, since it doesn't have good handling of contractions*/
+ /* normalization is turned off to stop strcollinc from executing */
+ myCollation->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ myCollation->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status);
+ for (i = 0; i < 6; i++) {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+
+/* Testing base letters */
+void CollationKanaTest::TestBase()
+{
+ int32_t i;
+ myCollation->setStrength(Collator::PRIMARY);
+ for (i = 0; i < 3 ; i++)
+ doTest(myCollation, testBaseCases[i], testBaseCases[i + 1], Collator::LESS);
+}
+
+/* Testing plain, Daku-ten, Handaku-ten letters */
+void CollationKanaTest::TestPlainDakutenHandakuten(void)
+{
+ int32_t i;
+ myCollation->setStrength(Collator::SECONDARY);
+ for (i = 0; i < 3 ; i++)
+ doTest(myCollation, testPlainDakutenHandakutenCases[i], testPlainDakutenHandakutenCases[i + 1],
+ Collator::LESS);
+}
+
+/*
+* Test Small, Large letters
+*/
+void CollationKanaTest::TestSmallLarge(void)
+{
+ int32_t i;
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation->setStrength(Collator::TERTIARY);
+ myCollation->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status);
+ for (i = 0; i < 3 ; i++)
+ doTest(myCollation, testSmallLargeCases[i], testSmallLargeCases[i + 1], Collator::LESS);
+}
+
+/*
+* Test Katakana, Hiragana letters
+*/
+void CollationKanaTest::TestKatakanaHiragana(void)
+{
+ int32_t i;
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation->setStrength(Collator::QUATERNARY);
+ myCollation->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status);
+ for (i = 0; i < 3 ; i++) {
+ doTest(myCollation, testKatakanaHiraganaCases[i], testKatakanaHiraganaCases[i + 1],
+ Collator::LESS);
+ }
+}
+
+/*
+* Test Choo-on kigoo
+*/
+void CollationKanaTest::TestChooonKigoo(void)
+{
+ int32_t i;
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation->setStrength(Collator::QUATERNARY);
+ myCollation->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status);
+ for (i = 0; i < 7 ; i++) {
+ doTest(myCollation, testChooonKigooCases[i], testChooonKigooCases[i + 1], Collator::LESS);
+ }
+}
+
+
+void CollationKanaTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CollationKanaTest: ");
+ if(myCollation) {
+ switch (index) {
+ case 0: name = "TestTertiary"; if (exec) TestTertiary(/* par */); break;
+ case 1: name = "TestBase"; if (exec) TestBase(/* par */); break;
+ case 2: name = "TestSmallLarge"; if (exec) TestSmallLarge(/* par */); break;
+ case 3: name = "TestTestPlainDakutenHandakuten"; if (exec) TestPlainDakutenHandakuten(/* par */); break;
+ case 4: name = "TestKatakanaHiragana"; if (exec) TestKatakanaHiragana(/* par */); break;
+ case 5: name = "TestChooonKigoo"; if (exec) TestChooonKigoo(/* par */); break;
+ default: name = ""; break;
+ }
+ } else {
+ errln("Collator couldn't be instantiated!");
+ name = "";
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/jacoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/jacoll.h
new file mode 100644
index 00000000000..96a6ae1fd7e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/jacoll.h
@@ -0,0 +1,65 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * CollationKanaTest is a third level test class. This tests the locale
+ * specific tertiary rules. For example, the term 'A-' (/u3041/u30fc) is
+ * equivalent to 'AA' (/u3041/u3041).
+ */
+
+#ifndef _JACOLL
+#define _JACOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class CollationKanaTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationKanaTest();
+ virtual ~CollationKanaTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // performs test with strength TERIARY
+ void TestTertiary(/* char* par */);
+
+ /* Testing base letters */
+ void TestBase();
+
+ /* Testing plain, Daku-ten, Handaku-ten letters */
+ void TestPlainDakutenHandakuten();
+
+ /* Test Small, Large letters */
+ void TestSmallLarge();
+
+ /* Test Katakana, Hiragana letters */
+ void TestKatakanaHiragana();
+
+ /* Test Choo-on kigoo */
+ void TestChooonKigoo();
+
+private:
+ static const UChar testSourceCases[][MAX_TOKEN_LEN];
+ static const UChar testTargetCases[][MAX_TOKEN_LEN];
+ static const Collator::EComparisonResult results[];
+ static const UChar testBaseCases[][MAX_TOKEN_LEN];
+ static const UChar testPlainDakutenHandakutenCases[][MAX_TOKEN_LEN];
+ static const UChar testSmallLargeCases[][MAX_TOKEN_LEN];
+ static const UChar testKatakanaHiraganaCases[][MAX_TOKEN_LEN];
+ static const UChar testChooonKigooCases[][MAX_TOKEN_LEN];
+
+ Collator *myCollation;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/jamotest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/jamotest.cpp
new file mode 100644
index 00000000000..635794101d3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/jamotest.cpp
@@ -0,0 +1,553 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************
+************************************************************************
+* Date Name Description
+* 02/28/2001 aliu Creation
+* 03/01/2001 George port to HP/UX
+************************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "jamotest.h"
+#include "unicode/utypes.h"
+#include "unicode/translit.h"
+#include "cpdtrans.h"
+
+// SEP is the disambiguation separator used by Latin-Jamo and Jamo-Latin
+#define SEP "-"
+
+JamoTest::JamoTest()
+{
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ NAME_JAMO = Transliterator::createFromRules("Name-Jamo",
+ JAMO_NAMES_RULES,
+ UTRANS_FORWARD, parseError, status);
+
+ if (U_FAILURE(status)) {
+ delete NAME_JAMO;
+ NAME_JAMO = NULL;
+ }
+ status = U_ZERO_ERROR;
+ JAMO_NAME = Transliterator::createFromRules("Jamo-Name",
+ JAMO_NAMES_RULES,
+ UTRANS_REVERSE, parseError, status);
+ if (U_FAILURE(status)) {
+ delete JAMO_NAME;
+ JAMO_NAME = NULL;
+ }
+}
+
+JamoTest::~JamoTest()
+{
+ delete NAME_JAMO;
+ delete JAMO_NAME;
+}
+
+void
+JamoTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ TESTCASE(0,TestJamo);
+ TESTCASE(1,TestRealText);
+ TESTCASE(2,TestPiecemeal);
+ default: name = ""; break;
+ }
+}
+
+void
+JamoTest::TestJamo() {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* latinJamo = Transliterator::createInstance("Latin-Jamo", UTRANS_FORWARD, parseError, status);
+
+ if (latinJamo == 0 || U_FAILURE(status)) {
+ errln("FAIL: createInstance() returned 0");
+ return;
+ }
+
+ Transliterator* jamoLatin = latinJamo->createInverse(status);
+
+ if (jamoLatin == 0) {
+ delete latinJamo;
+ errln("FAIL: createInverse() returned 0");
+ return;
+ }
+
+ static const char* CASE[] = {
+ // Column 1 is the latin text L1 to be fed to Latin-Jamo
+ // to yield output J.
+
+ // Column 2 is expected value of J. J is fed to
+ // Jamo-Latin to yield output L2.
+
+ // Column 3 is expected value of L2. If the expected
+ // value of L2 is L1, then L2 is NULL.
+
+ // add tests for the update to fix problems where it didn't follow the standard
+ // see also http://www.unicode.org/cldr/data/charts/transforms/Latin-Hangul.html
+ "gach", "(Gi)(A)(Cf)", NULL,
+ "geumhui", "(Gi)(EU)(Mf)(Hi)(YI)", NULL,
+ "choe", "(Ci)(OE)", NULL,
+ "wo", "(IEUNG)(WEO)", NULL,
+ "Wonpil", "(IEUNG)(WEO)(Nf)(Pi)(I)(L)", "wonpil",
+ "GIPPEUM", "(Gi)(I)(BB)(EU)(Mf)", "gippeum",
+ "EUTTEUM", "(IEUNG)(EU)(DD)(EU)(Mf)", "eutteum",
+ "KKOTNAE", "(GGi)(O)(Tf)(Ni)(AE)", "kkotnae",
+ "gaga", "(Gi)(A)(Gi)(A)", NULL,
+ "gag-a", "(Gi)(A)(Gf)(IEUNG)(A)", NULL,
+ "gak-ka", "(Gi)(A)(Kf)(Ki)(A)", NULL,
+ "gakka", "(Gi)(A)(GGi)(A)", NULL,
+ "gakk-a", "(Gi)(A)(GGf)(IEUNG)(A)", NULL,
+ "gakkka", "(Gi)(A)(GGf)(Ki)(A)", NULL,
+ "gak-kka", "(Gi)(A)(Kf)(GGi)(A)", NULL,
+
+ "bab", "(Bi)(A)(Bf)", NULL,
+ "babb", "(Bi)(A)(Bf)(Bi)(EU)", "babbeu",
+ "babbba", "(Bi)(A)(Bf)(Bi)(EU)(Bi)(A)", "babbeuba",
+ "bagg", "(Bi)(A)(Gf)(Gi)(EU)", "baggeu",
+ "baggga", "(Bi)(A)(Gf)(Gi)(EU)(Gi)(A)", "baggeuga",
+ //"bag" SEP "gga", "(Bi)(A)(Gf)" SEP "(Gi)(EU)(Gi)(A)", "bag" SEP "geuga",
+ "kabsa", "(Ki)(A)(Bf)(Si)(A)", NULL,
+ "kabska", "(Ki)(A)(BS)(Ki)(A)", NULL,
+ "gabsbka", "(Gi)(A)(BS)(Bi)(EU)(Ki)(A)", "gabsbeuka", // not (Kf)
+ "gga", "(Gi)(EU)(Gi)(A)", "geuga",
+ "bsa", "(Bi)(EU)(Si)(A)", "beusa",
+ "agg", "(IEUNG)(A)(Gf)(Gi)(EU)", "aggeu",
+ "agga", "(IEUNG)(A)(Gf)(Gi)(A)", NULL,
+ "la", "(R)(A)", NULL,
+ "bs", "(Bi)(EU)(Sf)", "beus",
+ "kalgga", "(Ki)(A)(L)(Gi)(EU)(Gi)(A)", "kalgeuga",
+
+ // 'r' in a final position is treated like 'l'
+ "karka", "(Ki)(A)(L)(Ki)(A)", "kalka",
+ };
+
+ enum { CASE_length = sizeof(CASE) / sizeof(CASE[0]) };
+
+ int32_t i;
+ for (i=0; i<CASE_length; i+=3) {
+ UnicodeString jamo = nameToJamo(CASE[i+1]);
+ if (CASE[i+2] == NULL) {
+ expect(*latinJamo, CASE[i], jamo, *jamoLatin);
+ } else {
+ // Handle case where round-trip is expected to fail
+ expect(*latinJamo, CASE[i], jamo);
+ expect(*jamoLatin, jamo, CASE[i+2]);
+ }
+ }
+
+ delete latinJamo;
+ delete jamoLatin;
+}
+
+/**
+ * Test various step-at-a-time transformation of hangul to jamo to
+ * latin and back.
+ */
+void JamoTest::TestPiecemeal(void) {
+ UnicodeString hangul; hangul.append((UChar)0xBC0F);
+ UnicodeString jamo = nameToJamo("(Mi)(I)(Cf)");
+ UnicodeString latin("mic");
+ UnicodeString latin2("mich");
+
+ Transliterator *t = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+
+ t = Transliterator::createInstance("NFD", UTRANS_FORWARD, status); // was Hangul-Jamo
+ if (U_FAILURE(status) || t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ expect(*t, hangul, jamo);
+ delete t;
+
+ t = Transliterator::createInstance("NFC", UTRANS_FORWARD, status); // was Jamo-Hangul
+ if (U_FAILURE(status) || t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ expect(*t, jamo, hangul);
+ delete t;
+
+ t = Transliterator::createInstance("Latin-Jamo", UTRANS_FORWARD, status);
+ if (U_FAILURE(status) || t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ expect(*t, latin, jamo);
+ delete t;
+
+ t = Transliterator::createInstance("Jamo-Latin", UTRANS_FORWARD, status);
+ if (U_FAILURE(status) || t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ expect(*t, jamo, latin2);
+ delete t;
+
+ t = Transliterator::createInstance("Hangul-Latin", UTRANS_FORWARD, status);
+ if (U_FAILURE(status) || t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ expect(*t, hangul, latin2);
+ delete t;
+
+ t = Transliterator::createInstance("Latin-Hangul", UTRANS_FORWARD, status);
+ if (U_FAILURE(status) || t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ expect(*t, latin, hangul);
+ delete t;
+
+ t = Transliterator::createInstance("Hangul-Latin; Latin-Jamo", UTRANS_FORWARD, status);
+ if (U_FAILURE(status) || t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ expect(*t, hangul, jamo);
+ delete t;
+
+ t = Transliterator::createInstance("Jamo-Latin; Latin-Hangul", UTRANS_FORWARD, status);
+ if (U_FAILURE(status) || t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ expect(*t, jamo, hangul);
+ delete t;
+
+ t = Transliterator::createInstance("Hangul-Latin; Latin-Hangul", UTRANS_FORWARD, status);
+ if (U_FAILURE(status) || t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ expect(*t, hangul, hangul);
+ delete t;
+}
+
+void
+JamoTest::TestRealText() {
+ // Test text taken from the Unicode web site
+ static const char* const WHAT_IS_UNICODE[] = {
+ "\\uc720\\ub2c8\\ucf54\\ub4dc\\uc5d0", "\\ub300\\ud574", "?",
+
+ "\\uc5b4\\ub5a4", "\\ud50c\\ub7ab\\ud3fc,", "\\uc5b4\\ub5a4",
+ "\\ud504\\ub85c\\uadf8\\ub7a8,", "\\uc5b4\\ub5a4", "\\uc5b8\\uc5b4\\uc5d0\\ub3c4",
+ "\\uc0c1\\uad00\\uc5c6\\uc774", "\\uc720\\ub2c8\\ucf54\\ub4dc\\ub294", "\\ubaa8\\ub4e0",
+ "\\ubb38\\uc790\\uc5d0", "\\ub300\\ud574", "\\uace0\\uc720", "\\ubc88\\ud638\\ub97c",
+ "\\uc81c\\uacf5\\ud569\\ub2c8\\ub2e4.",
+
+ "\\uae30\\ubcf8\\uc801\\uc73c\\ub85c", "\\ucef4\\ud4e8\\ud130\\ub294",
+ "\\uc22b\\uc790\\ub9cc", "\\ucc98\\ub9ac\\ud569\\ub2c8\\ub2e4.", "\\uae00\\uc790\\ub098",
+ "\\ub2e4\\ub978", "\\ubb38\\uc790\\uc5d0\\ub3c4", "\\uc22b\\uc790\\ub97c",
+ "\\uc9c0\\uc815\\ud558\\uc5ec",
+ "\\uc800\\uc7a5\\ud569\\ub2c8\\ub2e4.", "\\uc720\\ub2c8\\ucf54\\ub4dc\\uac00",
+ "\\uac1c\\ubc1c\\ub418\\uae30", "\\uc804\\uc5d0\\ub294", "\\uc774\\ub7ec\\ud55c",
+ "\\uc22b\\uc790\\ub97c", "\\uc9c0\\uc815\\ud558\\uae30", "\\uc704\\ud574", "\\uc218\\ubc31",
+ "\\uac00\\uc9c0\\uc758", "\\ub2e4\\ub978", "\\uae30\\ud638\\ud654",
+ "\\uc2dc\\uc2a4\\ud15c\\uc744",
+ "\\uc0ac\\uc6a9\\ud588\\uc2b5\\ub2c8\\ub2e4.", "\\ub2e8\\uc77c", "\\uae30\\ud638\\ud654",
+ "\\ubc29\\ubc95\\uc73c\\ub85c\\ub294", "\\ubaa8\\ub4e0", "\\ubb38\\uc790\\ub97c",
+ "\\ud3ec\\ud568\\ud560", "\\uc218", "\\uc5c6\\uc5c8\\uc2b5\\ub2c8\\ub2e4.", "\\uc608\\ub97c",
+ "\\ub4e4\\uc5b4", "\\uc720\\ub7fd", "\\uc5f0\\ud569\\uc5d0\\uc11c\\ub9cc",
+ "\\ubcf4\\ub354\\ub77c\\ub3c4", "\\ubaa8\\ub4e0", "\\uac01", "\\ub098\\ub77c\\ubcc4",
+ "\\uc5b8\\uc5b4\\ub97c", "\\ucc98\\ub9ac\\ud558\\ub824\\uba74", "\\uc5ec\\ub7ec",
+ "\\uac1c\\uc758", "\\ub2e4\\ub978", "\\uae30\\ud638\\ud654", "\\ubc29\\ubc95\\uc774",
+ "\\ud544\\uc694\\ud569\\ub2c8\\ub2e4.", "\\uc601\\uc5b4\\uc640", "\\uac19\\uc740",
+ "\\ub2e8\\uc77c", "\\uc5b8\\uc5b4\\uc758", "\\uacbd\\uc6b0\\ub3c4",
+ "\\uacf5\\ud1b5\\uc801\\uc73c\\ub85c", "\\uc0ac\\uc6a9\\ub418\\ub294", "\\ubaa8\\ub4e0",
+ "\\uae00\\uc790,", "\\ubb38\\uc7a5", "\\ubd80\\ud638", "\\ubc0f",
+ "\\ud14c\\ud06c\\ub2c8\\uceec", "\\uae30\\ud638\\uc5d0", "\\ub9de\\ub294", "\\ub2e8\\uc77c",
+ "\\uae30\\ud638\\ud654", "\\ubc29\\ubc95\\uc744", "\\uac16\\uace0", "\\uc788\\uc9c0",
+ "\\ubabb\\ud558\\uc600\\uc2b5\\ub2c8\\ub2e4.",
+
+ "\\uc774\\ub7ec\\ud55c", "\\uae30\\ud638\\ud654", "\\uc2dc\\uc2a4\\ud15c\\uc740",
+ "\\ub610\\ud55c", "\\ub2e4\\ub978", "\\uae30\\ud638\\ud654", "\\uc2dc\\uc2a4\\ud15c\\uacfc",
+ "\\ucda9\\ub3cc\\ud569\\ub2c8\\ub2e4.", "\\uc989", "\\ub450", "\\uac00\\uc9c0",
+ "\\uae30\\ud638\\ud654", "\\ubc29\\ubc95\\uc774", "\\ub450", "\\uac1c\\uc758", "\\ub2e4\\ub978",
+ "\\ubb38\\uc790\\uc5d0", "\\ub300\\ud574", "\\uac19\\uc740", "\\ubc88\\ud638\\ub97c",
+ "\\uc0ac\\uc6a9\\ud558\\uac70\\ub098", "\\uac19\\uc740", "\\ubb38\\uc790\\uc5d0",
+ "\\ub300\\ud574", "\\ub2e4\\ub978", "\\ubc88\\ud638\\ub97c", "\\uc0ac\\uc6a9\\ud560", "\\uc218",
+ "\\uc788\\uc2b5\\ub2c8\\ub2e4.", "\\uc8fc\\uc5b4\\uc9c4", "\\ubaa8\\ub4e0",
+ "\\ucef4\\ud4e8\\ud130(\\ud2b9\\ud788", "\\uc11c\\ubc84)\\ub294", "\\uc11c\\ub85c",
+ "\\ub2e4\\ub978", "\\uc5ec\\ub7ec", "\\uac00\\uc9c0", "\\uae30\\ud638\\ud654",
+ "\\ubc29\\ubc95\\uc744", "\\uc9c0\\uc6d0\\ud574\\uc57c",
+ "\\ud569\\ub2c8\\ub2e4.", "\\uadf8\\ub7ec\\ub098,", "\\ub370\\uc774\\ud130\\ub97c",
+ "\\uc11c\\ub85c", "\\ub2e4\\ub978", "\\uae30\\ud638\\ud654", "\\ubc29\\ubc95\\uc774\\ub098",
+ "\\ud50c\\ub7ab\\ud3fc", "\\uac04\\uc5d0", "\\uc804\\ub2ec\\ud560", "\\ub54c\\ub9c8\\ub2e4",
+ "\\uadf8", "\\ub370\\uc774\\ud130\\ub294", "\\ud56d\\uc0c1", "\\uc190\\uc0c1\\uc758",
+ "\\uc704\\ud5d8\\uc744", "\\uacaa\\uac8c", "\\ub429\\ub2c8\\ub2e4.",
+
+ "\\uc720\\ub2c8\\ucf54\\ub4dc\\ub85c", "\\ubaa8\\ub4e0", "\\uac83\\uc744",
+ "\\ud574\\uacb0\\ud560", "\\uc218", "\\uc788\\uc2b5\\ub2c8\\ub2e4!",
+ "\\uc720\\ub2c8\\ucf54\\ub4dc\\ub294", "\\uc0ac\\uc6a9", "\\uc911\\uc778",
+ "\\ud50c\\ub7ab\\ud3fc,", "\\ud504\\ub85c\\uadf8\\ub7a8,", "\\uc5b8\\uc5b4\\uc5d0",
+ "\\uad00\\uacc4\\uc5c6\\uc774", "\\ubb38\\uc790\\ub9c8\\ub2e4", "\\uace0\\uc720\\ud55c",
+ "\\uc22b\\uc790\\ub97c",
+ "\\uc81c\\uacf5\\ud569\\ub2c8\\ub2e4.", "\\uc720\\ub2c8\\ucf54\\ub4dc",
+ "\\ud45c\\uc900\\uc740", // "Apple, HP, IBM, JustSystem, Microsoft, Oracle, SAP, "
+ // "Sun, Sybase, Unisys "
+ "\\ubc0f", "\\uae30\\ud0c0", "\\uc5ec\\ub7ec",
+ "\\ud68c\\uc0ac\\uc640", "\\uac19\\uc740", "\\uc5c5\\uacc4",
+ "\\uc120\\ub450\\uc8fc\\uc790\\uc5d0", "\\uc758\\ud574",
+ "\\ucc44\\ud0dd\\ub418\\uc5c8\\uc2b5\\ub2c8\\ub2e4.", "\\uc720\\ub2c8\\ucf54\\ub4dc\\ub294",
+ // "XML, Java, ECMAScript(JavaScript), LDAP, CORBA 3.0, WML "
+ "\\ub4f1\\uacfc",
+ "\\uac19\\uc774", "\\ud604\\uc7ac", "\\ub110\\ub9ac", "\\uc0ac\\uc6a9\\ub418\\ub294",
+ "\\ud45c\\uc900\\uc5d0\\uc11c", "\\ud544\\uc694\\ud558\\uba70", "\\uc774\\ub294", // "ISO/IEC",
+ "10646\\uc744", "\\uad6c\\ud604\\ud558\\ub294", "\\uacf5\\uc2dd\\uc801\\uc778",
+ "\\ubc29\\ubc95\\uc785\\ub2c8\\ub2e4.", "\\uc774\\ub294", "\\ub9ce\\uc740", "\\uc6b4\\uc601",
+ "\\uccb4\\uc81c,", "\\uc694\\uc998", "\\uc0ac\\uc6a9\\ub418\\ub294", "\\ubaa8\\ub4e0",
+ "\\ube0c\\ub77c\\uc6b0\\uc800", "\\ubc0f", "\\uae30\\ud0c0", "\\ub9ce\\uc740",
+ "\\uc81c\\ud488\\uc5d0\\uc11c",
+ "\\uc9c0\\uc6d0\\ub429\\ub2c8\\ub2e4.", "\\uc720\\ub2c8\\ucf54\\ub4dc",
+ "\\ud45c\\uc900\\uc758", "\\ubd80\\uc0c1\\uacfc", "\\uc774\\ub97c",
+ "\\uc9c0\\uc6d0\\ud558\\ub294", "\\ub3c4\\uad6c\\uc758", "\\uac00\\uc6a9\\uc131\\uc740",
+ "\\ucd5c\\uadfc", "\\uc804", "\\uc138\\uacc4\\uc5d0", "\\ubd88\\uace0", "\\uc788\\ub294",
+ "\\uae30\\uc220", "\\uacbd\\ud5a5\\uc5d0\\uc11c", "\\uac00\\uc7a5", "\\uc911\\uc694\\ud55c",
+ "\\ubd80\\ubd84\\uc744", "\\ucc28\\uc9c0\\ud558\\uace0", "\\uc788\\uc2b5\\ub2c8\\ub2e4.",
+
+ "\\uc720\\ub2c8\\ucf54\\ub4dc\\ub97c",
+ // Replaced a hyphen with a space to make the test case work with CLDR1.5
+ //"\\ud074\\ub77c\\uc774\\uc5b8\\ud2b8-\\uc11c\\ubc84", "\\ub610\\ub294",
+ "\\ud074\\ub77c\\uc774\\uc5b8\\ud2b8 \\uc11c\\ubc84", "\\ub610\\ub294",
+ // Replaced a hyphen with a space.
+ //"\\ub2e4\\uc911-\\uc5f0\\uacb0", "\\uc751\\uc6a9", "\\ud504\\ub85c\\uadf8\\ub7a8\\uacfc",
+ "\\ub2e4\\uc911 \\uc5f0\\uacb0", "\\uc751\\uc6a9", "\\ud504\\ub85c\\uadf8\\ub7a8\\uacfc",
+ "\\uc6f9", "\\uc0ac\\uc774\\ud2b8\\uc5d0", "\\ud1b5\\ud569\\ud558\\uba74",
+ "\\ub808\\uac70\\uc2dc", "\\ubb38\\uc790", "\\uc138\\ud2b8", "\\uc0ac\\uc6a9\\uc5d0",
+ "\\uc788\\uc5b4\\uc11c", "\\uc0c1\\ub2f9\\ud55c", "\\ube44\\uc6a9", "\\uc808\\uac10",
+ "\\ud6a8\\uacfc\\uac00",
+ "\\ub098\\ud0c0\\ub0a9\\ub2c8\\ub2e4.", "\\uc720\\ub2c8\\ucf54\\ub4dc\\ub97c",
+ "\\ud1b5\\ud574", "\\ub9ac\\uc5d4\\uc9c0\\ub2c8\\uc5b4\\ub9c1", "\\uc5c6\\uc774",
+ "\\ub2e4\\uc911", "\\ud50c\\ub7ab\\ud3fc,", "\\uc5b8\\uc5b4", "\\ubc0f", "\\uad6d\\uac00",
+ "\\uac04\\uc5d0", "\\ub2e8\\uc77c", "\\uc18c\\ud504\\ud2b8\\uc6e8\\uc5b4",
+ "\\ud50c\\ub7ab\\ud3fc", "\\ub610\\ub294", "\\ub2e8\\uc77c", "\\uc6f9",
+ "\\uc0ac\\uc774\\ud2b8\\ub97c", "\\ubaa9\\ud45c\\ub85c", "\\uc0bc\\uc744", "\\uc218",
+ "\\uc788\\uc2b5\\ub2c8\\ub2e4.", "\\uc774\\ub97c", "\\uc0ac\\uc6a9\\ud558\\uba74",
+ "\\ub370\\uc774\\ud130\\ub97c", "\\uc190\\uc0c1", "\\uc5c6\\uc774", "\\uc5ec\\ub7ec",
+ "\\uc2dc\\uc2a4\\ud15c\\uc744", "\\ud1b5\\ud574", "\\uc804\\uc1a1\\ud560", "\\uc218",
+ "\\uc788\\uc2b5\\ub2c8\\ub2e4.",
+
+ "\\uc720\\ub2c8\\ucf54\\ub4dc", "\\ucf58\\uc18c\\uc2dc\\uc5c4\\uc5d0", "\\ub300\\ud574",
+ "\\uc720\\ub2c8\\ucf54\\ub4dc", "\\ucf58\\uc18c\\uc2dc\\uc5c4\\uc740",
+ "\\ube44\\uc601\\ub9ac", "\\uc870\\uc9c1\\uc73c\\ub85c\\uc11c", "\\ud604\\ub300",
+ "\\uc18c\\ud504\\ud2b8\\uc6e8\\uc5b4", "\\uc81c\\ud488\\uacfc",
+ "\\ud45c\\uc900\\uc5d0\\uc11c", "\\ud14d\\uc2a4\\ud2b8\\uc758", "\\ud45c\\ud604\\uc744",
+ "\\uc9c0\\uc815\\ud558\\ub294", "\\uc720\\ub2c8\\ucf54\\ub4dc", "\\ud45c\\uc900\\uc758",
+ "\\uc0ac\\uc6a9\\uc744", "\\uac1c\\ubc1c\\ud558\\uace0", "\\ud655\\uc7a5\\ud558\\uba70",
+ "\\uc7a5\\ub824\\ud558\\uae30", "\\uc704\\ud574",
+ "\\uc138\\uc6cc\\uc84c\\uc2b5\\ub2c8\\ub2e4.", "\\ucf58\\uc18c\\uc2dc\\uc5c4",
+ "\\uba64\\ubc84\\uc27d\\uc740", "\\ucef4\\ud4e8\\ud130\\uc640", "\\uc815\\ubcf4",
+ "\\ucc98\\ub9ac", "\\uc0b0\\uc5c5\\uc5d0", "\\uc885\\uc0ac\\ud558\\uace0", "\\uc788\\ub294",
+ "\\uad11\\ubc94\\uc704\\ud55c", "\\ud68c\\uc0ac", "\\ubc0f", "\\uc870\\uc9c1\\uc758",
+ "\\ubc94\\uc704\\ub97c",
+ "\\ub098\\ud0c0\\ub0c5\\ub2c8\\ub2e4.", "\\ucf58\\uc18c\\uc2dc\\uc5c4\\uc758",
+ "\\uc7ac\\uc815\\uc740", "\\uc804\\uc801\\uc73c\\ub85c", "\\ud68c\\ube44\\uc5d0",
+ "\\uc758\\ud574", "\\ucda9\\ub2f9\\ub429\\ub2c8\\ub2e4.", "\\uc720\\ub2c8\\ucf54\\ub4dc",
+ "\\ucee8\\uc18c\\uc2dc\\uc5c4\\uc5d0\\uc11c\\uc758", "\\uba64\\ubc84\\uc27d\\uc740",
+ "\\uc804", "\\uc138\\uacc4", "\\uc5b4\\ub290", "\\uacf3\\uc5d0\\uc11c\\ub098",
+ "\\uc720\\ub2c8\\ucf54\\ub4dc", "\\ud45c\\uc900\\uc744", "\\uc9c0\\uc6d0\\ud558\\uace0",
+ "\\uadf8", "\\ud655\\uc7a5\\uacfc", "\\uad6c\\ud604\\uc744",
+ "\\uc9c0\\uc6d0\\ud558\\uace0\\uc790\\ud558\\ub294", "\\uc870\\uc9c1\\uacfc",
+ "\\uac1c\\uc778\\uc5d0\\uac8c", "\\uac1c\\ubc29\\ub418\\uc5b4",
+ "\\uc788\\uc2b5\\ub2c8\\ub2e4.",
+
+ "\\ub354", "\\uc790\\uc138\\ud55c", "\\ub0b4\\uc6a9\\uc740", "\\uc6a9\\uc5b4\\uc9d1,",
+ "\\uc608\\uc81c", "\\uc720\\ub2c8\\ucf54\\ub4dc", "\\uc0ac\\uc6a9", "\\uac00\\ub2a5",
+ "\\uc81c\\ud488,", "\\uae30\\uc220", "\\uc815\\ubcf4", "\\ubc0f", "\\uae30\\ud0c0",
+ "\\uc720\\uc6a9\\ud55c", "\\uc815\\ubcf4\\ub97c",
+ "\\ucc38\\uc870\\ud558\\uc2ed\\uc2dc\\uc624."
+ };
+
+ enum { WHAT_IS_UNICODE_length = sizeof(WHAT_IS_UNICODE) / sizeof(WHAT_IS_UNICODE[0]) };
+
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* latinJamo = Transliterator::createInstance("Latin-Jamo", UTRANS_FORWARD, parseError, status);
+ Transliterator* jamoHangul = Transliterator::createInstance("NFC(NFD)", UTRANS_FORWARD, parseError, status);
+ if (latinJamo == 0 || jamoHangul == 0 || U_FAILURE(status)) {
+ delete latinJamo;
+ delete jamoHangul;
+ errln("FAIL: createInstance returned NULL");
+ return;
+ }
+ Transliterator* jamoLatin = latinJamo->createInverse(status);
+ Transliterator* hangulJamo = jamoHangul->createInverse(status);
+ if (jamoLatin == 0 || hangulJamo == 0) {
+ errln("FAIL: createInverse returned NULL");
+ delete latinJamo;
+ delete jamoLatin;
+ delete jamoHangul;
+ delete hangulJamo;
+ return;
+ }
+
+ Transliterator* tarray[4] =
+ { hangulJamo, jamoLatin, latinJamo, jamoHangul };
+ CompoundTransliterator rt(tarray, 4);
+
+ UnicodeString buf;
+ int32_t total = 0;
+ int32_t errors = 0;
+ int32_t i;
+ for (i=0; i < WHAT_IS_UNICODE_length; ++i) {
+ ++total;
+ UnicodeString hangul = WHAT_IS_UNICODE[i];
+ hangul = hangul.unescape(); // Parse backslash-u escapes
+ UnicodeString hangulX = hangul;
+ rt.transliterate(hangulX);
+ if (hangul != hangulX) {
+ ++errors;
+ UnicodeString jamo = hangul; hangulJamo->transliterate(jamo);
+ UnicodeString latin = jamo; jamoLatin->transliterate(latin);
+ UnicodeString jamo2 = latin; latinJamo->transliterate(jamo2);
+ UnicodeString hangul2 = jamo2; jamoHangul->transliterate(hangul2);
+
+ buf.remove(0);
+ buf.append("FAIL: ");
+ if (hangul2 != hangulX) {
+ buf.append((UnicodeString)"(Weird: " + hangulX + " != " + hangul2 + ")");
+ }
+ // The Hangul-Jamo conversion is not usually the
+ // bug here, so we hide it from display.
+ // Uncomment lines to see the Hangul.
+ buf.append(//hangul + " => " +
+ jamoToName(jamo) + " => " +
+ latin + " => " + jamoToName(jamo2)
+ //+ " => " + hangul2
+ );
+ errln(prettify(buf));
+ }
+ }
+ if (errors != 0) {
+ errln((UnicodeString)"Test word failures: " + errors + " out of " + total);
+ } else {
+ logln((UnicodeString)"All " + total + " test words passed");
+ }
+
+ delete latinJamo;
+ delete jamoLatin;
+ delete jamoHangul;
+ delete hangulJamo;
+}
+
+// Override TransliteratorTest
+void
+JamoTest::expectAux(const UnicodeString& tag,
+ const UnicodeString& summary, UBool pass,
+ const UnicodeString& expectedResult) {
+ UnicodeString jsum = jamoToName(summary);
+ UnicodeString jexp = jamoToName(expectedResult);
+ TransliteratorTest::expectAux(tag, jsum, pass, jexp);
+}
+
+const char* JamoTest::JAMO_NAMES_RULES =
+ "'(Gi)' <> \\u1100;"
+ "'(GGi)' <> \\u1101;"
+ "'(Ni)' <> \\u1102;"
+ "'(Di)' <> \\u1103;"
+ "'(DD)' <> \\u1104;"
+ "'(R)' <> \\u1105;"
+ "'(Mi)' <> \\u1106;"
+ "'(Bi)' <> \\u1107;"
+ "'(BB)' <> \\u1108;"
+ "'(Si)' <> \\u1109;"
+ "'(SSi)' <> \\u110A;"
+ "'(IEUNG)' <> \\u110B;"
+ "'(Ji)' <> \\u110C;"
+ "'(JJ)' <> \\u110D;"
+ "'(Ci)' <> \\u110E;"
+ "'(Ki)' <> \\u110F;"
+ "'(Ti)' <> \\u1110;"
+ "'(Pi)' <> \\u1111;"
+ "'(Hi)' <> \\u1112;"
+
+ "'(A)' <> \\u1161;"
+ "'(AE)' <> \\u1162;"
+ "'(YA)' <> \\u1163;"
+ "'(YAE)' <> \\u1164;"
+ "'(EO)' <> \\u1165;"
+ "'(E)' <> \\u1166;"
+ "'(YEO)' <> \\u1167;"
+ "'(YE)' <> \\u1168;"
+ "'(O)' <> \\u1169;"
+ "'(WA)' <> \\u116A;"
+ "'(WAE)' <> \\u116B;"
+ "'(OE)' <> \\u116C;"
+ "'(YO)' <> \\u116D;"
+ "'(U)' <> \\u116E;"
+ "'(WEO)' <> \\u116F;"
+ "'(WE)' <> \\u1170;"
+ "'(WI)' <> \\u1171;"
+ "'(YU)' <> \\u1172;"
+ "'(EU)' <> \\u1173;"
+ "'(YI)' <> \\u1174;"
+ "'(I)' <> \\u1175;"
+
+ "'(Gf)' <> \\u11A8;"
+ "'(GGf)' <> \\u11A9;"
+ "'(GS)' <> \\u11AA;"
+ "'(Nf)' <> \\u11AB;"
+ "'(NJ)' <> \\u11AC;"
+ "'(NH)' <> \\u11AD;"
+ "'(Df)' <> \\u11AE;"
+ "'(L)' <> \\u11AF;"
+ "'(LG)' <> \\u11B0;"
+ "'(LM)' <> \\u11B1;"
+ "'(LB)' <> \\u11B2;"
+ "'(LS)' <> \\u11B3;"
+ "'(LT)' <> \\u11B4;"
+ "'(LP)' <> \\u11B5;"
+ "'(LH)' <> \\u11B6;"
+ "'(Mf)' <> \\u11B7;"
+ "'(Bf)' <> \\u11B8;"
+ "'(BS)' <> \\u11B9;"
+ "'(Sf)' <> \\u11BA;"
+ "'(SSf)' <> \\u11BB;"
+ "'(NG)' <> \\u11BC;"
+ "'(Jf)' <> \\u11BD;"
+ "'(Cf)' <> \\u11BE;"
+ "'(Kf)' <> \\u11BF;"
+ "'(Tf)' <> \\u11C0;"
+ "'(Pf)' <> \\u11C1;"
+ "'(Hf)' <> \\u11C2;";
+
+/**
+ * Convert short names to actual jamo. E.g., "x(LG)y" returns
+ * "x\u11B0y". See JAMO_NAMES for table of names.
+ */
+UnicodeString
+JamoTest::nameToJamo(const UnicodeString& input) {
+ if (NAME_JAMO == 0) {
+ errln("Failed to create NAME_JAMO");
+ return input; /* failure! */
+ }
+ UnicodeString result(input);
+ NAME_JAMO->transliterate(result);
+ return result;
+}
+
+/**
+ * Convert jamo to short names. E.g., "x\u11B0y" returns
+ * "x(LG)y". See JAMO_NAMES for table of names.
+ */
+UnicodeString
+JamoTest::jamoToName(const UnicodeString& input) {
+ if (NAME_JAMO == 0) {
+ errln("Failed to create NAME_JAMO");
+ return input; /* failure! */
+ }
+ UnicodeString result(input);
+ JAMO_NAME->transliterate(result);
+ return result;
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/jamotest.h b/Build/source/libs/icu/icu-xetex/test/intltest/jamotest.h
new file mode 100644
index 00000000000..f6dbfd7c216
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/jamotest.h
@@ -0,0 +1,60 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************
+************************************************************************
+* Date Name Description
+* 02/28/2001 aliu Creation
+* 03/01/2001 George port to HP/UX
+************************************************************************/
+
+#ifndef JAMOTEST_H
+#define JAMOTEST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "transtst.h"
+
+/**
+ * @test
+ * @summary Test of Latin-Jamo and Jamo-Latin rules
+ */
+class JamoTest : public TransliteratorTest {
+public:
+ JamoTest();
+ virtual ~JamoTest();
+private:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name,
+ char* par=NULL);
+
+ void TestJamo(void);
+
+ void TestRealText(void);
+
+ void TestPiecemeal(void);
+
+ //======================================================================
+ // Support methods
+ //======================================================================
+
+ // Override TransliteratorTest
+ virtual void expectAux(const UnicodeString& tag,
+ const UnicodeString& summary, UBool pass,
+ const UnicodeString& expectedResult);
+
+ // Methods to convert Jamo to/from readable short names,
+ // e.g. (Gi) <> U+1100
+ static const char* JAMO_NAMES_RULES;
+ Transliterator *JAMO_NAME;
+ Transliterator *NAME_JAMO;
+ UnicodeString nameToJamo(const UnicodeString& input);
+ UnicodeString jamoToName(const UnicodeString& input);
+};
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/lcukocol.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/lcukocol.cpp
new file mode 100644
index 00000000000..f48ebd957f6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/lcukocol.cpp
@@ -0,0 +1,88 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#ifndef _COLL
+#include "unicode/coll.h"
+#endif
+
+#ifndef _TBLCOLL
+#include "unicode/tblcoll.h"
+#endif
+
+#ifndef _UNISTR
+#include "unicode/unistr.h"
+#endif
+
+#ifndef _SORTKEY
+#include "unicode/sortkey.h"
+#endif
+
+#include "lcukocol.h"
+
+#include "sfwdchit.h"
+
+LotusCollationKoreanTest::LotusCollationKoreanTest()
+: myCollation(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation = Collator::createInstance("ko_kr", status);
+ if(U_SUCCESS(status)) {
+ myCollation->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ } else {
+ errln("Couldn't instantiate the collator with %s", u_errorName(status));
+ delete myCollation;
+ myCollation = 0;
+ }
+
+}
+
+LotusCollationKoreanTest::~LotusCollationKoreanTest()
+{
+ delete myCollation;
+}
+
+const UChar LotusCollationKoreanTest::testSourceCases[][LotusCollationKoreanTest::MAX_TOKEN_LEN] = {
+ {0xac00, 0}
+
+};
+
+const UChar LotusCollationKoreanTest::testTargetCases[][LotusCollationKoreanTest::MAX_TOKEN_LEN] = {
+ {0xac01, 0}
+};
+
+const Collator::EComparisonResult LotusCollationKoreanTest::results[] = {
+ Collator::LESS
+};
+
+void LotusCollationKoreanTest::TestTertiary(/* char* par */)
+{
+ int32_t i = 0;
+ myCollation->setStrength(Collator::TERTIARY);
+
+ for (i = 0; i < 1; i++) {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+
+void LotusCollationKoreanTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite LotusCollationKoreanTest: ");
+ if(myCollation) {
+ switch (index) {
+ case 0: name = "TestTertiary"; if (exec) TestTertiary(/* par */); break;
+ default: name = ""; break;
+ }
+ } else {
+ errln("Class collator not instantiated");
+ name = "";
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/lcukocol.h b/Build/source/libs/icu/icu-xetex/test/intltest/lcukocol.h
new file mode 100644
index 00000000000..c690c5b65e6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/lcukocol.h
@@ -0,0 +1,40 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#ifndef LOTUSCOLLATIONKOREANTEST_H
+#define LOTUSCOLLATIONKOREANTEST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class LotusCollationKoreanTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ LotusCollationKoreanTest();
+ virtual ~LotusCollationKoreanTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // performs test with strength TERIARY
+ void TestTertiary(/* char* par */);
+
+private:
+ static const UChar testSourceCases[][MAX_TOKEN_LEN];
+ static const UChar testTargetCases[][MAX_TOKEN_LEN];
+ static const Collator::EComparisonResult results[];
+
+ Collator *myCollation;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/loctest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/loctest.cpp
new file mode 100644
index 00000000000..1ce08214ade
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/loctest.cpp
@@ -0,0 +1,2136 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "loctest.h"
+#include "unicode/decimfmt.h"
+#include "unicode/ucurr.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/brkiter.h"
+#include "unicode/coll.h"
+#include "cstring.h"
+#include <stdio.h>
+
+static const char* const rawData[33][8] = {
+
+ // language code
+ { "en", "fr", "ca", "el", "no", "it", "xx", "zh" },
+ // script code
+ { "", "", "", "", "", "", "", "Hans" },
+ // country code
+ { "US", "FR", "ES", "GR", "NO", "", "YY", "CN" },
+ // variant code
+ { "", "", "", "", "NY", "", "", "" },
+ // full name
+ { "en_US", "fr_FR", "ca_ES", "el_GR", "no_NO_NY", "it", "xx_YY", "zh_Hans_CN" },
+ // ISO-3 language
+ { "eng", "fra", "cat", "ell", "nor", "ita", "", "zho" },
+ // ISO-3 country
+ { "USA", "FRA", "ESP", "GRC", "NOR", "", "", "CHN" },
+ // LCID
+ { "409", "40c", "403", "408", "814", "10", "0", "804" },
+
+ // display langage (English)
+ { "English", "French", "Catalan", "Greek", "Norwegian", "Italian", "xx", "Chinese" },
+ // display script (English)
+ { "", "", "", "", "", "", "", "Simplified Han" },
+ // display country (English)
+ { "United States", "France", "Spain", "Greece", "Norway", "", "YY", "China" },
+ // display variant (English)
+ { "", "", "", "", "NY", "", "", ""},
+ // display name (English)
+ // Updated no_NO_NY English display name for new pattern-based algorithm
+ // (part of Euro support).
+ { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway, NY)", "Italian", "xx (YY)", "Chinese (Simplified Han, China)" },
+
+ // display langage (French)
+ { "anglais", "fran\\u00E7ais", "catalan", "grec", "norv\\u00E9gien", "italien", "xx", "chinois" },
+ // display script (French)
+ { "", "", "", "", "", "", "", "id\\u00E9ogrammes han (variante simplifi\\u00E9e)" },
+ // display country (French)
+ { "\\u00C9tats-Unis", "France", "Espagne", "Gr\\u00E8ce", "Norv\\u00E8ge", "", "YY", "Chine" },
+ // display variant (French)
+ { "", "", "", "", "NY", "", "", "" },
+ // display name (French)
+ //{ "anglais (Etats-Unis)", "francais (France)", "catalan (Espagne)", "grec (Grece)", "norvegien (Norvege,Nynorsk)", "italien", "xx (YY)" },
+ { "anglais (\\u00C9tats-Unis)", "fran\\u00E7ais (France)", "catalan (Espagne)", "grec (Gr\\u00E8ce)", "norv\\u00E9gien (Norv\\u00E8ge, NY)", "italien", "xx (YY)", "chinois (id\\u00E9ogrammes han (variante simplifi\\u00E9e), Chine)" }, // STILL not right
+
+
+ /* display language (Catalan) */
+ { "angl\\u00E8s", "franc\\u00E8s", "catal\\u00E0", "grec", "noruec", "itali\\u00E0", "", "xin\\u00E9s" },
+ /* display script (Catalan) */
+ { "", "", "", "", "", "", "", "Hans" },
+ /* display country (Catalan) */
+ { "Estats Units", "Fran\\u00E7a", "Espanya", "Gr\\u00E8cia", "Noruega", "", "", "Xina" },
+ /* display variant (Catalan) */
+ { "", "", "", "", "NY", "", "" },
+ /* display name (Catalan) */
+ { "angl\\u00E8s (Estats Units)", "franc\\u00E8s (Fran\\u00E7a)", "catal\\u00E0 (Espanya)", "grec (Gr\\u00E8cia)", "noruec (Noruega, NY)", "itali\\u00E0", "", "xin\\u00E9s (Hans, Xina)" },
+
+ // display langage (Greek)[actual values listed below]
+ { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac",
+ "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac",
+ "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac",
+ "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac",
+ "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac",
+ "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
+ "",
+ "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC"
+ },
+ // display script (Greek)
+ { "", "", "", "", "", "", "", "\\u039a\\u03b9\\u03bd\\u03b5\\u03b6\\u03b9\\u03ba\\u03cc \\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf" },
+ // display country (Greek)[actual values listed below]
+ { "\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2",
+ "\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1",
+ "\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1",
+ "\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1",
+ "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1",
+ "",
+ "",
+ "\\u039A\\u03AF\\u03BD\\u03B1"
+ },
+ // display variant (Greek)
+ { "", "", "", "", "NY", "", "" },
+ // display name (Greek)[actual values listed below]
+ { "\\u0391\\u03b3\\u03b3\\u03bb\\u03b9\\u03ba\\u03ac (\\u0397\\u03BD\\u03C9\\u03BC\\u03AD\\u03BD\\u03B5\\u03C2 \\u03A0\\u03BF\\u03BB\\u03B9\\u03C4\\u03B5\\u03AF\\u03B5\\u03C2)",
+ "\\u0393\\u03b1\\u03bb\\u03bb\\u03b9\\u03ba\\u03ac (\\u0393\\u03b1\\u03bb\\u03bb\\u03af\\u03b1)",
+ "\\u039a\\u03b1\\u03c4\\u03b1\\u03bb\\u03b1\\u03bd\\u03b9\\u03ba\\u03ac (\\u0399\\u03c3\\u03c0\\u03b1\\u03bd\\u03af\\u03b1)",
+ "\\u0395\\u03bb\\u03bb\\u03b7\\u03bd\\u03b9\\u03ba\\u03ac (\\u0395\\u03bb\\u03bb\\u03ac\\u03b4\\u03b1)",
+ "\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03b9\\u03ba\\u03ac (\\u039d\\u03bf\\u03c1\\u03b2\\u03b7\\u03b3\\u03af\\u03b1, NY)",
+ "\\u0399\\u03c4\\u03b1\\u03bb\\u03b9\\u03ba\\u03ac",
+ "",
+ "\\u039A\\u03B9\\u03BD\\u03B5\\u03B6\\u03B9\\u03BA\\u03AC (\\u039a\\u03b9\\u03bd\\u03b5\\u03b6\\u03b9\\u03ba\\u03cc \\u0391\\u03c0\\u03bb\\u03bf\\u03c0\\u03bf\\u03b9\\u03b7\\u03bc\\u03ad\\u03bd\\u03bf, \\u039A\\u03AF\\u03BD\\u03B1)"
+ },
+
+ // display langage (<root>)
+ { "English", "French", "Catalan", "Greek", "Norwegian", "Italian", "xx", "" },
+ // display script (<root>)
+ { "", "", "", "", "", "", "", ""},
+ // display country (<root>)
+ { "United States", "France", "Spain", "Greece", "Norway", "", "YY", "" },
+ // display variant (<root>)
+ { "", "", "", "", "Nynorsk", "", "", ""},
+ // display name (<root>)
+ //{ "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,Nynorsk)", "Italian", "xx (YY)" },
+ { "English (United States)", "French (France)", "Catalan (Spain)", "Greek (Greece)", "Norwegian (Norway,NY)", "Italian", "xx (YY)", "" }
+};
+
+
+/*
+ Usage:
+ test_assert( Test (should be TRUE) )
+
+ Example:
+ test_assert(i==3);
+
+ the macro is ugly but makes the tests pretty.
+*/
+
+#define test_assert(test) \
+ { \
+ if(!(test)) \
+ errln("FAIL: " #test " was not true. In " __FILE__ " on line %d", __LINE__ ); \
+ else \
+ logln("PASS: asserted " #test); \
+ }
+
+/*
+ Usage:
+ test_assert_print( Test (should be TRUE), printable )
+
+ Example:
+ test_assert(i==3, toString(i));
+
+ the macro is ugly but makes the tests pretty.
+*/
+
+#define test_assert_print(test,print) \
+ { \
+ if(!(test)) \
+ errln("FAIL: " #test " was not true. " + UnicodeString(print) ); \
+ else \
+ logln("PASS: asserted " #test "-> " + UnicodeString(print)); \
+ }
+
+
+#define test_dumpLocale(l) { logln(#l " = " + UnicodeString(l.getName(), "")); }
+
+LocaleTest::LocaleTest()
+: dataTable(NULL)
+{
+ setUpDataTable();
+}
+
+LocaleTest::~LocaleTest()
+{
+ if (dataTable != 0) {
+ for (int32_t i = 0; i < 33; i++) {
+ delete []dataTable[i];
+ }
+ delete []dataTable;
+ dataTable = 0;
+ }
+}
+
+void LocaleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ switch (index) {
+ TESTCASE(0, TestBasicGetters);
+ TESTCASE(1, TestSimpleResourceInfo);
+ TESTCASE(2, TestDisplayNames);
+ TESTCASE(3, TestSimpleObjectStuff);
+ TESTCASE(4, TestPOSIXParsing);
+ TESTCASE(5, TestGetAvailableLocales);
+ TESTCASE(6, TestDataDirectory);
+ TESTCASE(7, TestISO3Fallback);
+ TESTCASE(8, TestGetLangsAndCountries);
+ TESTCASE(9, TestSimpleDisplayNames);
+ TESTCASE(10, TestUninstalledISO3Names);
+ TESTCASE(11, TestAtypicalLocales);
+#if !UCONFIG_NO_FORMATTING
+ TESTCASE(12, TestThaiCurrencyFormat);
+ TESTCASE(13, TestEuroSupport);
+#endif
+ TESTCASE(14, TestToString);
+#if !UCONFIG_NO_FORMATTING
+ TESTCASE(15, Test4139940);
+ TESTCASE(16, Test4143951);
+#endif
+ TESTCASE(17, Test4147315);
+ TESTCASE(18, Test4147317);
+ TESTCASE(19, Test4147552);
+ TESTCASE(20, TestVariantParsing);
+#if !UCONFIG_NO_FORMATTING
+ TESTCASE(21, Test4105828);
+#endif
+ TESTCASE(22, TestSetIsBogus);
+ TESTCASE(23, TestParallelAPIValues);
+ TESTCASE(24, TestKeywordVariants);
+ TESTCASE(25, TestKeywordVariantParsing);
+ TESTCASE(26, TestGetBaseName);
+ TESTCASE(27, TestGetLocale);
+ TESTCASE(28, TestVariantWithOutCountry);
+ TESTCASE(29, TestCanonicalization);
+
+ // keep the last index in sync with the condition in default:
+
+ default:
+ if (index <= 28) { // keep this in sync with the last index!
+ name = "(test omitted by !UCONFIG_NO_FORMATTING)";
+ } else {
+ name = "";
+ }
+ break; //needed to end loop
+ }
+}
+
+void LocaleTest::TestBasicGetters() {
+ UnicodeString temp;
+
+ int32_t i;
+ for (i = 0; i <= MAX_LOCALES; i++) {
+ Locale testLocale("");
+ if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
+ testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
+ }
+ else {
+ testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
+ }
+ logln("Testing " + (UnicodeString)testLocale.getName() + "...");
+
+ if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
+ errln(" Language code mismatch: " + temp + " versus "
+ + dataTable[LANG][i]);
+ if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
+ errln(" Script code mismatch: " + temp + " versus "
+ + dataTable[SCRIPT][i]);
+ if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
+ errln(" Country code mismatch: " + temp + " versus "
+ + dataTable[CTRY][i]);
+ if ( (temp=testLocale.getVariant()) != (dataTable[VAR][i]))
+ errln(" Variant code mismatch: " + temp + " versus "
+ + dataTable[VAR][i]);
+ if ( (temp=testLocale.getName()) != (dataTable[NAME][i]))
+ errln(" Locale name mismatch: " + temp + " versus "
+ + dataTable[NAME][i]);
+ }
+
+ logln("Same thing without variant codes...");
+ for (i = 0; i <= MAX_LOCALES; i++) {
+ Locale testLocale("");
+ if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
+ testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i]);
+ }
+ else {
+ testLocale = Locale(rawData[LANG][i], rawData[CTRY][i]);
+ }
+ logln("Testing " + (temp=testLocale.getName()) + "...");
+
+ if ( (temp=testLocale.getLanguage()) != (dataTable[LANG][i]))
+ errln("Language code mismatch: " + temp + " versus "
+ + dataTable[LANG][i]);
+ if ( (temp=testLocale.getScript()) != (dataTable[SCRIPT][i]))
+ errln("Script code mismatch: " + temp + " versus "
+ + dataTable[SCRIPT][i]);
+ if ( (temp=testLocale.getCountry()) != (dataTable[CTRY][i]))
+ errln("Country code mismatch: " + temp + " versus "
+ + dataTable[CTRY][i]);
+ if (testLocale.getVariant()[0] != 0)
+ errln("Variant code mismatch: something versus \"\"");
+ }
+
+ logln("Testing long language names and getters");
+ Locale test8 = Locale::createFromName("x-klingon-latn-zx.utf32be@special");
+
+ temp = test8.getLanguage();
+ if (temp != UnicodeString("x-klingon") )
+ errln("Language code mismatch: " + temp + " versus \"x-klingon\"");
+
+ temp = test8.getScript();
+ if (temp != UnicodeString("Latn") )
+ errln("Script code mismatch: " + temp + " versus \"Latn\"");
+
+ temp = test8.getCountry();
+ if (temp != UnicodeString("ZX") )
+ errln("Country code mismatch: " + temp + " versus \"ZX\"");
+
+ temp = test8.getVariant();
+ //if (temp != UnicodeString("SPECIAL") )
+ // errln("Variant code mismatch: " + temp + " versus \"SPECIAL\"");
+ // As of 3.0, the "@special" will *not* be parsed by uloc_getName()
+ if (temp != UnicodeString("") )
+ errln("Variant code mismatch: " + temp + " versus \"\"");
+
+ if (Locale::getDefault() != Locale::createFromName(NULL))
+ errln("Locale::getDefault() == Locale::createFromName(NULL)");
+
+ /*----------*/
+ // NOTE: There used to be a special test for locale names that had language or
+ // country codes that were longer than two letters. The new version of Locale
+ // doesn't support anything that isn't an officially recognized language or
+ // country code, so we no longer support this feature.
+
+ Locale bogusLang("THISISABOGUSLANGUAGE"); // Jitterbug 2864: language code too long
+ if(!bogusLang.isBogus()) {
+ errln("Locale(\"THISISABOGUSLANGUAGE\").isBogus()==FALSE");
+ }
+
+ bogusLang=Locale("eo");
+ if( bogusLang.isBogus() ||
+ strcmp(bogusLang.getLanguage(), "eo")!=0 ||
+ *bogusLang.getCountry()!=0 ||
+ *bogusLang.getVariant()!=0 ||
+ strcmp(bogusLang.getName(), "eo")!=0
+ ) {
+ errln("assignment to bogus Locale does not unbogus it or sets bad data");
+ }
+
+ Locale a("eo_DE@currency=DEM");
+ Locale *pb=a.clone();
+ if(pb==&a || *pb!=a) {
+ errln("Locale.clone() failed");
+ }
+ delete pb;
+}
+
+void LocaleTest::TestParallelAPIValues() {
+ logln("Test synchronization between C and C++ API");
+ if (strcmp(Locale::getChinese().getName(), ULOC_CHINESE) != 0) {
+ errln("Differences for ULOC_CHINESE Locale");
+ }
+ if (strcmp(Locale::getEnglish().getName(), ULOC_ENGLISH) != 0) {
+ errln("Differences for ULOC_ENGLISH Locale");
+ }
+ if (strcmp(Locale::getFrench().getName(), ULOC_FRENCH) != 0) {
+ errln("Differences for ULOC_FRENCH Locale");
+ }
+ if (strcmp(Locale::getGerman().getName(), ULOC_GERMAN) != 0) {
+ errln("Differences for ULOC_GERMAN Locale");
+ }
+ if (strcmp(Locale::getItalian().getName(), ULOC_ITALIAN) != 0) {
+ errln("Differences for ULOC_ITALIAN Locale");
+ }
+ if (strcmp(Locale::getJapanese().getName(), ULOC_JAPANESE) != 0) {
+ errln("Differences for ULOC_JAPANESE Locale");
+ }
+ if (strcmp(Locale::getKorean().getName(), ULOC_KOREAN) != 0) {
+ errln("Differences for ULOC_KOREAN Locale");
+ }
+ if (strcmp(Locale::getSimplifiedChinese().getName(), ULOC_SIMPLIFIED_CHINESE) != 0) {
+ errln("Differences for ULOC_SIMPLIFIED_CHINESE Locale");
+ }
+ if (strcmp(Locale::getTraditionalChinese().getName(), ULOC_TRADITIONAL_CHINESE) != 0) {
+ errln("Differences for ULOC_TRADITIONAL_CHINESE Locale");
+ }
+
+
+ if (strcmp(Locale::getCanada().getName(), ULOC_CANADA) != 0) {
+ errln("Differences for ULOC_CANADA Locale");
+ }
+ if (strcmp(Locale::getCanadaFrench().getName(), ULOC_CANADA_FRENCH) != 0) {
+ errln("Differences for ULOC_CANADA_FRENCH Locale");
+ }
+ if (strcmp(Locale::getChina().getName(), ULOC_CHINA) != 0) {
+ errln("Differences for ULOC_CHINA Locale");
+ }
+ if (strcmp(Locale::getPRC().getName(), ULOC_PRC) != 0) {
+ errln("Differences for ULOC_PRC Locale");
+ }
+ if (strcmp(Locale::getFrance().getName(), ULOC_FRANCE) != 0) {
+ errln("Differences for ULOC_FRANCE Locale");
+ }
+ if (strcmp(Locale::getGermany().getName(), ULOC_GERMANY) != 0) {
+ errln("Differences for ULOC_GERMANY Locale");
+ }
+ if (strcmp(Locale::getItaly().getName(), ULOC_ITALY) != 0) {
+ errln("Differences for ULOC_ITALY Locale");
+ }
+ if (strcmp(Locale::getJapan().getName(), ULOC_JAPAN) != 0) {
+ errln("Differences for ULOC_JAPAN Locale");
+ }
+ if (strcmp(Locale::getKorea().getName(), ULOC_KOREA) != 0) {
+ errln("Differences for ULOC_KOREA Locale");
+ }
+ if (strcmp(Locale::getTaiwan().getName(), ULOC_TAIWAN) != 0) {
+ errln("Differences for ULOC_TAIWAN Locale");
+ }
+ if (strcmp(Locale::getUK().getName(), ULOC_UK) != 0) {
+ errln("Differences for ULOC_UK Locale");
+ }
+ if (strcmp(Locale::getUS().getName(), ULOC_US) != 0) {
+ errln("Differences for ULOC_US Locale");
+ }
+}
+
+
+void LocaleTest::TestSimpleResourceInfo() {
+ UnicodeString temp;
+ char temp2[20];
+ UErrorCode err = U_ZERO_ERROR;
+ int32_t i = 0;
+
+ for (i = 0; i <= MAX_LOCALES; i++) {
+ Locale testLocale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
+ logln("Testing " + (temp=testLocale.getName()) + "...");
+
+ if ( (temp=testLocale.getISO3Language()) != (dataTable[LANG3][i]))
+ errln(" ISO-3 language code mismatch: " + temp
+ + " versus " + dataTable[LANG3][i]);
+ if ( (temp=testLocale.getISO3Country()) != (dataTable[CTRY3][i]))
+ errln(" ISO-3 country code mismatch: " + temp
+ + " versus " + dataTable[CTRY3][i]);
+
+ sprintf(temp2, "%x", (int)testLocale.getLCID());
+ if (UnicodeString(temp2) != dataTable[LCID][i])
+ errln((UnicodeString)" LCID mismatch: " + temp2 + " versus "
+ + dataTable[LCID][i]);
+
+ if(U_FAILURE(err))
+ {
+ errln((UnicodeString)"Some error on number " + i + u_errorName(err));
+ }
+ err = U_ZERO_ERROR;
+ }
+
+ Locale locale("en");
+ if(strcmp(locale.getName(), "en") != 0||
+ strcmp(locale.getLanguage(), "en") != 0) {
+ errln("construction of Locale(en) failed\n");
+ }
+ /*-----*/
+
+}
+
+/*
+ * Jitterbug 2439 -- markus 20030425
+ *
+ * The lookup of display names must not fall back through the default
+ * locale because that yields useless results.
+ */
+void
+LocaleTest::TestDisplayNames()
+{
+ Locale english("en", "US");
+ Locale french("fr", "FR");
+ Locale croatian("ca", "ES");
+ Locale greek("el", "GR");
+
+ logln(" In locale = en_US...");
+ doTestDisplayNames(english, DLANG_EN);
+ logln(" In locale = fr_FR...");
+ doTestDisplayNames(french, DLANG_FR);
+ logln(" In locale = ca_ES...");
+ doTestDisplayNames(croatian, DLANG_CA);
+ logln(" In locale = el_GR...");
+ doTestDisplayNames(greek, DLANG_EL);
+
+ UnicodeString s;
+ UErrorCode status = U_ZERO_ERROR;
+
+#if !UCONFIG_NO_FORMATTING
+ DecimalFormatSymbols symb(status);
+ /* Check to see if ICU supports this locale */
+ if (symb.getLocale(ULOC_VALID_LOCALE, status) != Locale("root")) {
+ /* test that the default locale has a display name for its own language */
+ Locale().getDisplayLanguage(Locale(), s);
+ if(s.length()<=3 && s.charAt(0)<=0x7f) {
+ /* check <=3 to reject getting the language code as a display name */
+ errln("unable to get a display string for the language of the default locale\n");
+ }
+
+ /*
+ * API coverage improvements: call
+ * Locale::getDisplayLanguage(UnicodeString &) and
+ * Locale::getDisplayCountry(UnicodeString &)
+ */
+ s.remove();
+ Locale().getDisplayLanguage(s);
+ if(s.length()<=3 && s.charAt(0)<=0x7f) {
+ errln("unable to get a display string for the language of the default locale [2]\n");
+ }
+ }
+ else {
+ logln("Default locale %s is unsupported by ICU\n", Locale().getName());
+ }
+ s.remove();
+#endif
+
+ french.getDisplayCountry(s);
+ if(s.isEmpty()) {
+ errln("unable to get any default-locale display string for the country of fr_FR\n");
+ }
+ s.remove();
+ Locale("zh", "Hant").getDisplayScript(s);
+ if(s.isEmpty()) {
+ errln("unable to get any default-locale display string for the country of zh_Hant\n");
+ }
+}
+
+void LocaleTest::TestSimpleObjectStuff() {
+ Locale test1("aa", "AA");
+ Locale test2("aa", "AA");
+ Locale test3(test1);
+ Locale test4("zz", "ZZ");
+ Locale test5("aa", "AA", "");
+ Locale test6("aa", "AA", "ANTARES");
+ Locale test7("aa", "AA", "JUPITER");
+ Locale test8 = Locale::createFromName("aa-aa-jupiTER"); // was "aa-aa.utf8@jupiter" but in 3.0 getName won't normalize that
+
+ // now list them all for debugging usage.
+ test_dumpLocale(test1);
+ test_dumpLocale(test2);
+ test_dumpLocale(test3);
+ test_dumpLocale(test4);
+ test_dumpLocale(test5);
+ test_dumpLocale(test6);
+ test_dumpLocale(test7);
+ test_dumpLocale(test8);
+
+ // Make sure things compare to themselves!
+ test_assert(test1 == test1);
+ test_assert(test2 == test2);
+ test_assert(test3 == test3);
+ test_assert(test4 == test4);
+ test_assert(test5 == test5);
+ test_assert(test6 == test6);
+ test_assert(test7 == test7);
+ test_assert(test8 == test8);
+
+ // make sure things are not equal to themselves.
+ test_assert(!(test1 != test1));
+ test_assert(!(test2 != test2));
+ test_assert(!(test3 != test3));
+ test_assert(!(test4 != test4));
+ test_assert(!(test5 != test5));
+ test_assert(!(test6 != test6));
+ test_assert(!(test7 != test7));
+ test_assert(!(test8 != test8));
+
+ // make sure things that are equal to each other don't show up as unequal.
+ test_assert(!(test1 != test2));
+ test_assert(!(test2 != test1));
+ test_assert(!(test1 != test3));
+ test_assert(!(test2 != test3));
+ test_assert(test5 == test1);
+ test_assert(test6 != test2);
+ test_assert(test6 != test5);
+
+ test_assert(test6 != test7);
+
+ // test for things that shouldn't compare equal.
+ test_assert(!(test1 == test4));
+ test_assert(!(test2 == test4));
+ test_assert(!(test3 == test4));
+
+ test_assert(test7 == test8);
+
+ // test for hash codes to be the same.
+ int32_t hash1 = test1.hashCode();
+ int32_t hash2 = test2.hashCode();
+ int32_t hash3 = test3.hashCode();
+
+ test_assert(hash1 == hash2);
+ test_assert(hash1 == hash3);
+ test_assert(hash2 == hash3);
+
+ // test that the assignment operator works.
+ test4 = test1;
+ logln("test4=test1;");
+ test_dumpLocale(test4);
+ test_assert(test4 == test4);
+
+ test_assert(!(test1 != test4));
+ test_assert(!(test2 != test4));
+ test_assert(!(test3 != test4));
+ test_assert(test1 == test4);
+ test_assert(test4 == test1);
+
+ // test assignments with a variant
+ logln("test7 = test6");
+ test7 = test6;
+ test_dumpLocale(test7);
+ test_assert(test7 == test7);
+ test_assert(test7 == test6);
+ test_assert(test7 != test5);
+
+ logln("test6 = test1");
+ test6=test1;
+ test_dumpLocale(test6);
+ test_assert(test6 != test7);
+ test_assert(test6 == test1);
+ test_assert(test6 == test6);
+}
+
+// A class which exposes constructors that are implemented in terms of the POSIX parsing code.
+class POSIXLocale : public Locale
+{
+public:
+ POSIXLocale(const UnicodeString& l)
+ :Locale()
+ {
+ char *ch;
+ ch = new char[l.length() + 1];
+ ch[l.extract(0, 0x7fffffff, ch, "")] = 0;
+ setFromPOSIXID(ch);
+ delete [] ch;
+ }
+ POSIXLocale(const char *l)
+ :Locale()
+ {
+ setFromPOSIXID(l);
+ }
+};
+
+void LocaleTest::TestPOSIXParsing()
+{
+ POSIXLocale test1("ab_AB");
+ POSIXLocale test2(UnicodeString("ab_AB"));
+ Locale test3("ab","AB");
+
+ POSIXLocale test4("ab_AB_Antares");
+ POSIXLocale test5(UnicodeString("ab_AB_Antares"));
+ Locale test6("ab", "AB", "Antares");
+
+ test_dumpLocale(test1);
+ test_dumpLocale(test2);
+ test_dumpLocale(test3);
+ test_dumpLocale(test4);
+ test_dumpLocale(test5);
+ test_dumpLocale(test6);
+
+ test_assert(test1 == test1);
+
+ test_assert(test1 == test2);
+ test_assert(test2 == test3);
+ test_assert(test3 == test1);
+
+ test_assert(test4 == test5);
+ test_assert(test5 == test6);
+ test_assert(test6 == test4);
+
+ test_assert(test1 != test4);
+ test_assert(test5 != test3);
+ test_assert(test5 != test2);
+
+ int32_t hash1 = test1.hashCode();
+ int32_t hash2 = test2.hashCode();
+ int32_t hash3 = test3.hashCode();
+
+ test_assert(hash1 == hash2);
+ test_assert(hash2 == hash3);
+ test_assert(hash3 == hash1);
+}
+
+void LocaleTest::TestGetAvailableLocales()
+{
+ int32_t locCount = 0;
+ const Locale* locList = Locale::getAvailableLocales(locCount);
+
+ if (locCount == 0)
+ errln("getAvailableLocales() returned an empty list!");
+ else {
+ logln(UnicodeString("Number of locales returned = ") + locCount);
+ UnicodeString temp;
+ for(int32_t i = 0; i < locCount; ++i)
+ logln(locList[i].getName());
+ }
+ // I have no idea how to test this function...
+}
+
+// This test isn't applicable anymore - getISO3Language is
+// independent of the data directory
+void LocaleTest::TestDataDirectory()
+{
+/*
+ char oldDirectory[80];
+ const char* temp;
+ UErrorCode err = U_ZERO_ERROR;
+ UnicodeString testValue;
+
+ temp = Locale::getDataDirectory();
+ strcpy(oldDirectory, temp);
+ logln(UnicodeString("oldDirectory = ") + oldDirectory);
+
+ Locale test(Locale::US);
+ test.getISO3Language(testValue);
+ logln("first fetch of language retrieved " + testValue);
+ if (testValue != "eng")
+ errln("Initial check of ISO3 language failed: expected \"eng\", got \"" + testValue + "\"");
+
+ {
+ char *path;
+ path=IntlTest::getTestDirectory();
+ Locale::setDataDirectory( path );
+ }
+
+ test.getISO3Language(testValue);
+ logln("second fetch of language retrieved " + testValue);
+ if (testValue != "xxx")
+ errln("setDataDirectory() failed: expected \"xxx\", got \"" + testValue + "\"");
+
+ Locale::setDataDirectory(oldDirectory);
+ test.getISO3Language(testValue);
+ logln("third fetch of language retrieved " + testValue);
+ if (testValue != "eng")
+ errln("get/setDataDirectory() failed: expected \"eng\", got \"" + testValue + "\"");
+*/
+}
+
+//===========================================================
+
+void LocaleTest::doTestDisplayNames(Locale& displayLocale, int32_t compareIndex) {
+ UnicodeString temp;
+
+ for (int32_t i = 0; i <= MAX_LOCALES; i++) {
+ Locale testLocale("");
+ if (rawData[SCRIPT][i] && rawData[SCRIPT][i][0] != 0) {
+ testLocale = Locale(rawData[LANG][i], rawData[SCRIPT][i], rawData[CTRY][i], rawData[VAR][i]);
+ }
+ else {
+ testLocale = Locale(rawData[LANG][i], rawData[CTRY][i], rawData[VAR][i]);
+ }
+ logln(" Testing " + (temp=testLocale.getName()) + "...");
+
+ UnicodeString testLang;
+ UnicodeString testScript;
+ UnicodeString testCtry;
+ UnicodeString testVar;
+ UnicodeString testName;
+
+ testLocale.getDisplayLanguage(displayLocale, testLang);
+ testLocale.getDisplayScript(displayLocale, testScript);
+ testLocale.getDisplayCountry(displayLocale, testCtry);
+ testLocale.getDisplayVariant(displayLocale, testVar);
+ testLocale.getDisplayName(displayLocale, testName);
+
+ UnicodeString expectedLang;
+ UnicodeString expectedScript;
+ UnicodeString expectedCtry;
+ UnicodeString expectedVar;
+ UnicodeString expectedName;
+
+ expectedLang = dataTable[compareIndex][i];
+ if (expectedLang.length() == 0)
+ expectedLang = dataTable[DLANG_EN][i];
+
+ expectedScript = dataTable[compareIndex + 1][i];
+ if (expectedScript.length() == 0)
+ expectedScript = dataTable[DSCRIPT_EN][i];
+
+ expectedCtry = dataTable[compareIndex + 2][i];
+ if (expectedCtry.length() == 0)
+ expectedCtry = dataTable[DCTRY_EN][i];
+
+ expectedVar = dataTable[compareIndex + 3][i];
+ if (expectedVar.length() == 0)
+ expectedVar = dataTable[DVAR_EN][i];
+
+ expectedName = dataTable[compareIndex + 4][i];
+ if (expectedName.length() == 0)
+ expectedName = dataTable[DNAME_EN][i];
+
+ if (testLang != expectedLang)
+ errln("Display language (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testLang + " expected " + expectedLang);
+ if (testScript != expectedScript)
+ errln("Display script (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testScript + " expected " + expectedScript);
+ if (testCtry != expectedCtry)
+ errln("Display country (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testCtry + " expected " + expectedCtry);
+ if (testVar != expectedVar)
+ errln("Display variant (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testVar + " expected " + expectedVar);
+ if (testName != expectedName)
+ errln("Display name (" + UnicodeString(displayLocale.getName()) + ") of (" + UnicodeString(testLocale.getName()) + ") got " + testName + " expected " + expectedName);
+ }
+}
+
+//---------------------------------------------------
+// table of valid data
+//---------------------------------------------------
+
+
+
+void LocaleTest::setUpDataTable()
+{
+ if (dataTable == 0) {
+ dataTable = new UnicodeString*[33];
+
+ for (int32_t i = 0; i < 33; i++) {
+ dataTable[i] = new UnicodeString[8];
+ for (int32_t j = 0; j < 8; j++) {
+ dataTable[i][j] = CharsToUnicodeString(rawData[i][j]);
+ }
+ }
+ }
+}
+
+// ====================
+
+
+/**
+ * @bug 4011756 4011380
+ */
+void
+LocaleTest::TestISO3Fallback()
+{
+ Locale test("xx", "YY");
+
+ const char * result;
+
+ result = test.getISO3Language();
+
+ // Conform to C API usage
+
+ if (!result || (result[0] != 0))
+ errln("getISO3Language() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
+
+ result = test.getISO3Country();
+
+ if (!result || (result[0] != 0))
+ errln("getISO3Country() on xx_YY returned " + UnicodeString(result) + " instead of \"\"");
+}
+
+/**
+ * @bug 4106155 4118587
+ */
+void
+LocaleTest::TestGetLangsAndCountries()
+{
+ // It didn't seem right to just do an exhaustive test of everything here, so I check
+ // for the following things:
+ // 1) Does each list have the right total number of entries?
+ // 2) Does each list contain certain language and country codes we think are important
+ // (the G7 countries, plus a couple others)?
+ // 3) Does each list have every entry formatted correctly? (i.e., two characters,
+ // all lower case for the language codes, all upper case for the country codes)
+ // 4) Is each list in sorted order?
+ int32_t testCount = 0;
+ const char * const * test = Locale::getISOLanguages();
+ const char spotCheck1[ ][4] = { "en", "es", "fr", "de", "it",
+ "ja", "ko", "zh", "th", "he",
+ "id", "iu", "ug", "yi", "za" };
+
+ int32_t i;
+
+ for(testCount = 0;test[testCount];testCount++)
+ ;
+
+ /* TODO: Change this test to be more like the cloctst version? */
+ if (testCount != 489)
+ errln("Expected getISOLanguages() to return 489 languages; it returned %d", testCount);
+ else {
+ for (i = 0; i < 15; i++) {
+ int32_t j;
+ for (j = 0; j < testCount; j++)
+ if (uprv_strcmp(test[j],spotCheck1[i])== 0)
+ break;
+ if (j == testCount || (uprv_strcmp(test[j],spotCheck1[i])!=0))
+ errln("Couldn't find " + (UnicodeString)spotCheck1[i] + " in language list.");
+ }
+ }
+ for (i = 0; i < testCount; i++) {
+ UnicodeString testee(test[i],"");
+ UnicodeString lc(test[i],"");
+ if (testee != lc.toLower())
+ errln(lc + " is not all lower case.");
+ if ( (testee.length() != 2) && (testee.length() != 3))
+ errln(testee + " is not two or three characters long.");
+ if (i > 0 && testee.compare(test[i - 1]) <= 0)
+ errln(testee + " appears in an out-of-order position in the list.");
+ }
+
+ test = Locale::getISOCountries();
+ UnicodeString spotCheck2 [] = { "US", "CA", "GB", "FR", "DE",
+ "IT", "JP", "KR", "CN", "TW",
+ "TH" };
+ int32_t spot2Len = 11;
+ for(testCount=0;test[testCount];testCount++)
+ ;
+
+ if (testCount != 246){
+ errln("Expected getISOCountries to return 240 countries; it returned %d", testCount);
+ }else {
+ for (i = 0; i < spot2Len; i++) {
+ int32_t j;
+ for (j = 0; j < testCount; j++)
+ {
+ UnicodeString testee(test[j],"");
+
+ if (testee == spotCheck2[i])
+ break;
+ }
+ UnicodeString testee(test[j],"");
+ if (j == testCount || testee != spotCheck2[i])
+ errln("Couldn't find " + spotCheck2[i] + " in country list.");
+ }
+ }
+ for (i = 0; i < testCount; i++) {
+ UnicodeString testee(test[i],"");
+ UnicodeString uc(test[i],"");
+ if (testee != uc.toUpper())
+ errln(testee + " is not all upper case.");
+ if (testee.length() != 2)
+ errln(testee + " is not two characters long.");
+ if (i > 0 && testee.compare(test[i - 1]) <= 0)
+ errln(testee + " appears in an out-of-order position in the list.");
+ }
+}
+
+/**
+ * @bug 4118587
+ */
+void
+LocaleTest::TestSimpleDisplayNames()
+{
+ // This test is different from TestDisplayNames because TestDisplayNames checks
+ // fallback behavior, combination of language and country names to form locale
+ // names, and other stuff like that. This test just checks specific language
+ // and country codes to make sure we have the correct names for them.
+ char languageCodes[] [4] = { "he", "id", "iu", "ug", "yi", "za" };
+ UnicodeString languageNames [] = { "Hebrew", "Indonesian", "Inuktitut", "Uighur", "Yiddish",
+ "Zhuang" };
+
+ for (int32_t i = 0; i < 6; i++) {
+ UnicodeString test;
+ Locale l(languageCodes[i], "", "");
+ l.getDisplayLanguage(Locale::getUS(), test);
+ if (test != languageNames[i])
+ errln("Got wrong display name for " + UnicodeString(languageCodes[i]) + ": Expected \"" +
+ languageNames[i] + "\", got \"" + test + "\".");
+ }
+}
+
+/**
+ * @bug 4118595
+ */
+void
+LocaleTest::TestUninstalledISO3Names()
+{
+ // This test checks to make sure getISO3Language and getISO3Country work right
+ // even for locales that are not installed.
+ const char iso2Languages [][4] = { "am", "ba", "fy", "mr", "rn",
+ "ss", "tw", "zu" };
+ const char iso3Languages [][5] = { "amh", "bak", "fry", "mar", "run",
+ "ssw", "twi", "zul" };
+
+ int32_t i;
+
+ for (i = 0; i < 8; i++) {
+ UErrorCode err = U_ZERO_ERROR;
+
+ UnicodeString test;
+ Locale l(iso2Languages[i], "", "");
+ test = l.getISO3Language();
+ if((test != iso3Languages[i]) || U_FAILURE(err))
+ errln("Got wrong ISO3 code for " + UnicodeString(iso2Languages[i]) + ": Expected \"" +
+ iso3Languages[i] + "\", got \"" + test + "\"." + UnicodeString(u_errorName(err)));
+ }
+
+ char iso2Countries [][4] = { "AF", "BW", "KZ", "MO", "MN",
+ "SB", "TC", "ZW" };
+ char iso3Countries [][4] = { "AFG", "BWA", "KAZ", "MAC", "MNG",
+ "SLB", "TCA", "ZWE" };
+
+ for (i = 0; i < 8; i++) {
+ UErrorCode err = U_ZERO_ERROR;
+ Locale l("", iso2Countries[i], "");
+ UnicodeString test(l.getISO3Country(), "");
+ if (test != iso3Countries[i])
+ errln("Got wrong ISO3 code for " + UnicodeString(iso2Countries[i]) + ": Expected \"" +
+ UnicodeString(iso3Countries[i]) + "\", got \"" + test + "\"." + u_errorName(err));
+ }
+}
+
+/**
+ * @bug 4092475
+ * I could not reproduce this bug. I'm pretty convinced it was fixed with the
+ * big locale-data reorg of 10/28/97. The lookup logic for language and country
+ * display names was also changed at that time in that check-in. --rtg 3/20/98
+ */
+void
+LocaleTest::TestAtypicalLocales()
+{
+ Locale localesToTest [] = { Locale("de", "CA"),
+ Locale("ja", "ZA"),
+ Locale("ru", "MX"),
+ Locale("en", "FR"),
+ Locale("es", "DE"),
+ Locale("", "HR"),
+ Locale("", "SE"),
+ Locale("", "DO"),
+ Locale("", "BE") };
+
+ UnicodeString englishDisplayNames [] = { "German (Canada)",
+ "Japanese (South Africa)",
+ "Russian (Mexico)",
+ "English (France)",
+ "Spanish (Germany)",
+ "Croatia",
+ "Sweden",
+ "Dominican Republic",
+ "Belgium" };
+ UnicodeString frenchDisplayNames []= { "allemand (Canada)",
+ "japonais (Afrique du Sud)",
+ "russe (Mexique)",
+ "anglais (France)",
+ "espagnol (Allemagne)",
+ "Croatie",
+ CharsToUnicodeString("Su\\u00E8de"),
+ CharsToUnicodeString("R\\u00E9publique dominicaine"),
+ "Belgique" };
+ UnicodeString spanishDisplayNames [] = {
+ CharsToUnicodeString("alem\\u00E1n (Canad\\u00E1)"),
+ CharsToUnicodeString("japon\\u00E9s (Sud\\u00E1frica)"),
+ CharsToUnicodeString("ruso (M\\u00E9xico)"),
+ CharsToUnicodeString("ingl\\u00E9s (Francia)"),
+ CharsToUnicodeString("espa\\u00F1ol (Alemania)"),
+ "Croacia",
+ "Suecia",
+ CharsToUnicodeString("Rep\\u00FAblica Dominicana"),
+ CharsToUnicodeString("B\\u00E9lgica") };
+ // De-Anglicizing root required the change from
+ // English display names to ISO Codes - ram 2003/09/26
+ UnicodeString invDisplayNames [] = { "German (Canada)",
+ "Japanese (South Africa)",
+ "Russian (Mexico)",
+ "English (France)",
+ "Spanish (Germany)",
+ "Croatia",
+ "Sweden",
+ "Dominican Republic",
+ "Belgium" };
+
+ int32_t i;
+ UErrorCode status = U_ZERO_ERROR;
+ Locale saveLocale;
+ Locale::setDefault(Locale::getUS(), status);
+ for (i = 0; i < 9; ++i) {
+ UnicodeString name;
+ localesToTest[i].getDisplayName(Locale::getUS(), name);
+ logln(name);
+ if (name != englishDisplayNames[i])
+ {
+ errln("Lookup in English failed: expected \"" + englishDisplayNames[i]
+ + "\", got \"" + name + "\"");
+ logln("Locale name was-> " + (name=localesToTest[i].getName()));
+ }
+ }
+
+ for (i = 0; i < 9; i++) {
+ UnicodeString name;
+ localesToTest[i].getDisplayName(Locale("es", "ES"), name);
+ logln(name);
+ if (name != spanishDisplayNames[i])
+ errln("Lookup in Spanish failed: expected \"" + spanishDisplayNames[i]
+ + "\", got \"" + name + "\"");
+ }
+
+ for (i = 0; i < 9; i++) {
+ UnicodeString name;
+ localesToTest[i].getDisplayName(Locale::getFrance(), name);
+ logln(name);
+ if (name != frenchDisplayNames[i])
+ errln("Lookup in French failed: expected \"" + frenchDisplayNames[i]
+ + "\", got \"" + name + "\"");
+ }
+
+ for (i = 0; i < 9; i++) {
+ UnicodeString name;
+ localesToTest[i].getDisplayName(Locale("inv", "IN"), name);
+ logln(name + " Locale fallback to be, and data fallback to root");
+ if (name != invDisplayNames[i])
+ errln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
+ + "\", got \"" + prettify(name) + "\"");
+ localesToTest[i].getDisplayName(Locale("inv", "BD"), name);
+ logln(name + " Data fallback to root");
+ if (name != invDisplayNames[i])
+ errln("Lookup in INV failed: expected \"" + prettify(invDisplayNames[i])
+ + "\", got \"" + prettify(name )+ "\"");
+ }
+ Locale::setDefault(saveLocale, status);
+}
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * @bug 4135752
+ * This would be better tested by the LocaleDataTest. Will move it when I
+ * get the LocaleDataTest working again.
+ */
+void
+LocaleTest::TestThaiCurrencyFormat()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *thaiCurrency = (DecimalFormat*)NumberFormat::createCurrencyInstance(
+ Locale("th", "TH"), status);
+ UChar posPrefix = 0x0e3f;
+ UnicodeString temp;
+
+ if(U_FAILURE(status) || !thaiCurrency)
+ {
+ errln("Couldn't get th_TH currency -> " + UnicodeString(u_errorName(status)));
+ return;
+ }
+ if (thaiCurrency->getPositivePrefix(temp) != UnicodeString(&posPrefix, 1, 1))
+ errln("Thai currency prefix wrong: expected 0x0e3f, got \"" +
+ thaiCurrency->getPositivePrefix(temp) + "\"");
+ if (thaiCurrency->getPositiveSuffix(temp) != "")
+ errln("Thai currency suffix wrong: expected \"\", got \"" +
+ thaiCurrency->getPositiveSuffix(temp) + "\"");
+
+ delete thaiCurrency;
+}
+
+/**
+ * @bug 4122371
+ * Confirm that Euro support works. This test is pretty rudimentary; all it does
+ * is check that any locales with the EURO variant format a number using the
+ * Euro currency symbol.
+ *
+ * ASSUME: All locales encode the Euro character "\u20AC".
+ * If this is changed to use the single-character Euro symbol, this
+ * test must be updated.
+ *
+ */
+void
+LocaleTest::TestEuroSupport()
+{
+ UChar euro = 0x20ac;
+ const UnicodeString EURO_CURRENCY(&euro, 1, 1); // Look for this UnicodeString in formatted Euro currency
+ const char* localeArr[] = {
+ "ca_ES",
+ "de_AT",
+ "de_DE",
+ "de_LU",
+ "el_GR",
+ "en_BE",
+ "en_IE",
+ "en_GB_EURO",
+ "en_US_EURO",
+ "es_ES",
+ "eu_ES",
+ "fi_FI",
+ "fr_BE",
+ "fr_FR",
+ "fr_LU",
+ "ga_IE",
+ "gl_ES",
+ "it_IT",
+ "nl_BE",
+ "nl_NL",
+ "pt_PT",
+ NULL
+ };
+ const char** locales = localeArr;
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UnicodeString temp;
+
+ for (;*locales!=NULL;locales++) {
+ Locale loc (*locales);
+ UnicodeString temp;
+ NumberFormat *nf = NumberFormat::createCurrencyInstance(loc, status);
+ UnicodeString pos;
+
+ if (U_FAILURE(status)) {
+ dataerrln("Error calling NumberFormat::createCurrencyInstance(%s)", *locales);
+ continue;
+ }
+
+ nf->format(271828.182845, pos);
+ UnicodeString neg;
+ nf->format(-271828.182845, neg);
+ if (pos.indexOf(EURO_CURRENCY) >= 0 &&
+ neg.indexOf(EURO_CURRENCY) >= 0) {
+ logln("Ok: " + (temp=loc.getName()) +
+ ": " + pos + " / " + neg);
+ }
+ else {
+ errln("Fail: " + (temp=loc.getName()) +
+ " formats without " + EURO_CURRENCY +
+ ": " + pos + " / " + neg +
+ "\n*** THIS FAILURE MAY ONLY MEAN THAT LOCALE DATA HAS CHANGED ***");
+ }
+
+ delete nf;
+ }
+
+ UnicodeString dollarStr("USD", ""), euroStr("EUR", ""), genericStr((UChar)0x00a4), resultStr;
+ UChar tmp[4];
+ status = U_ZERO_ERROR;
+
+ ucurr_forLocale("en_US", tmp, 4, &status);
+ resultStr.setTo(tmp);
+ if (dollarStr != resultStr) {
+ errln("Fail: en_US didn't return USD");
+ }
+ ucurr_forLocale("en_US_EURO", tmp, 4, &status);
+ resultStr.setTo(tmp);
+ if (euroStr != resultStr) {
+ errln("Fail: en_US_EURO didn't return EUR");
+ }
+ ucurr_forLocale("en_GB_EURO", tmp, 4, &status);
+ resultStr.setTo(tmp);
+ if (euroStr != resultStr) {
+ errln("Fail: en_GB_EURO didn't return EUR");
+ }
+ ucurr_forLocale("en_US_PREEURO", tmp, 4, &status);
+ resultStr.setTo(tmp);
+ if (dollarStr != resultStr) {
+ errln("Fail: en_US_PREEURO didn't fallback to en_US");
+ }
+ ucurr_forLocale("en_US_Q", tmp, 4, &status);
+ resultStr.setTo(tmp);
+ if (dollarStr != resultStr) {
+ errln("Fail: en_US_Q didn't fallback to en_US");
+ }
+ int32_t invalidLen = ucurr_forLocale("en_QQ", tmp, 4, &status);
+ if (invalidLen || U_SUCCESS(status)) {
+ errln("Fail: en_QQ didn't return NULL");
+ }
+}
+
+#endif
+
+/**
+ * @bug 4139504
+ * toString() doesn't work with language_VARIANT.
+ */
+void
+LocaleTest::TestToString() {
+ Locale DATA [] = {
+ Locale("xx", "", ""),
+ Locale("", "YY", ""),
+ Locale("", "", "ZZ"),
+ Locale("xx", "YY", ""),
+ Locale("xx", "", "ZZ"),
+ Locale("", "YY", "ZZ"),
+ Locale("xx", "YY", "ZZ"),
+ };
+
+ const char DATA_S [][20] = {
+ "xx",
+ "_YY",
+ "__ZZ",
+ "xx_YY",
+ "xx__ZZ",
+ "_YY_ZZ",
+ "xx_YY_ZZ",
+ };
+
+ for (int32_t i=0; i < 7; ++i) {
+ const char *name;
+ name = DATA[i].getName();
+
+ if (strcmp(name, DATA_S[i]) != 0)
+ {
+ errln("Fail: Locale.getName(), got:" + UnicodeString(name) + ", expected: " + DATA_S[i]);
+ }
+ else
+ logln("Pass: Locale.getName(), got:" + UnicodeString(name) );
+ }
+}
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * @bug 4139940
+ * Couldn't reproduce this bug -- probably was fixed earlier.
+ *
+ * ORIGINAL BUG REPORT:
+ * -- basically, hungarian for monday shouldn't have an \u00f4
+ * (o circumflex)in it instead it should be an o with 2 inclined
+ * (right) lines over it..
+ *
+ * You may wonder -- why do all this -- why not just add a line to
+ * LocaleData? Well, I could see by inspection that the locale file had the
+ * right character in it, so I wanted to check the rest of the pipeline -- a
+ * very remote possibility, but I wanted to be sure. The other possibility
+ * is that something is wrong with the font mapping subsystem, but we can't
+ * test that here.
+ */
+void
+LocaleTest::Test4139940()
+{
+ Locale mylocale("hu", "", "");
+ UDate mydate = date(98,3,13); // A Monday
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat df_full("EEEE", mylocale, status);
+ if(U_FAILURE(status)){
+ errln(UnicodeString("Could not create SimpleDateFormat object for locale hu. Error: " )+ UnicodeString(u_errorName(status)));
+ return;
+ }
+ UnicodeString str;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ df_full.format(mydate, str, pos);
+ // Make sure that o circumflex (\u00F4) is NOT there, and
+ // o double acute (\u0151) IS.
+ UChar ocf = 0x00f4;
+ UChar oda = 0x0151;
+ if (str.indexOf(oda) < 0 || str.indexOf(ocf) >= 0) {
+ errln("Fail: Monday in Hungarian is wrong - oda's index is %d and ocf's is %d",
+ str.indexOf(oda), str.indexOf(ocf));
+ logln(UnicodeString("String is: ") + str );
+ }
+}
+
+UDate
+LocaleTest::date(int32_t y, int32_t m, int32_t d, int32_t hr, int32_t min, int32_t sec)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(status);
+ if (cal == 0)
+ return 0.0;
+ cal->clear();
+ cal->set(1900 + y, m, d, hr, min, sec); // Add 1900 to follow java.util.Date protocol
+ UDate dt = cal->getTime(status);
+ if (U_FAILURE(status))
+ return 0.0;
+
+ delete cal;
+ return dt;
+}
+
+/**
+ * @bug 4143951
+ * Russian first day of week should be Monday. Confirmed.
+ */
+void
+LocaleTest::Test4143951()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(Locale("ru", "", ""), status);
+ if(U_SUCCESS(status)) {
+ if (cal->getFirstDayOfWeek(status) != UCAL_MONDAY) {
+ errln("Fail: First day of week in Russia should be Monday");
+ }
+ }
+ delete cal;
+}
+
+#endif
+
+/**
+ * @bug 4147315
+ * java.util.Locale.getISO3Country() works wrong for non ISO-3166 codes.
+ * Should throw an exception for unknown locales
+ */
+void
+LocaleTest::Test4147315()
+{
+ UnicodeString temp;
+ // Try with codes that are the wrong length but happen to match text
+ // at a valid offset in the mapping table
+ Locale locale("aaa", "CCC");
+
+ const char *result = locale.getISO3Country();
+
+ // Change to conform to C api usage
+ if((result==NULL)||(result[0] != 0))
+ errln("ERROR: getISO3Country() returns: " + UnicodeString(result,"") +
+ " for locale '" + (temp=locale.getName()) + "' rather than exception" );
+}
+
+/**
+ * @bug 4147317
+ * java.util.Locale.getISO3Language() works wrong for non ISO-3166 codes.
+ * Should throw an exception for unknown locales
+ */
+void
+LocaleTest::Test4147317()
+{
+ UnicodeString temp;
+ // Try with codes that are the wrong length but happen to match text
+ // at a valid offset in the mapping table
+ Locale locale("aaa", "CCC");
+
+ const char *result = locale.getISO3Language();
+
+ // Change to conform to C api usage
+ if((result==NULL)||(result[0] != 0))
+ errln("ERROR: getISO3Language() returns: " + UnicodeString(result,"") +
+ " for locale '" + (temp=locale.getName()) + "' rather than exception" );
+}
+
+/*
+ * @bug 4147552
+ */
+void
+LocaleTest::Test4147552()
+{
+ Locale locales [] = { Locale("no", "NO"),
+ Locale("no", "NO", "B"),
+ Locale("no", "NO", "NY")
+ };
+
+ UnicodeString edn("Norwegian (Norway, B)");
+ UnicodeString englishDisplayNames [] = {
+ "Norwegian (Norway)",
+ edn,
+ // "Norwegian (Norway,B)",
+ //"Norwegian (Norway,NY)"
+ "Norwegian (Norway, NY)"
+ };
+ UnicodeString ndn("norsk (Norge, B");
+ UnicodeString norwegianDisplayNames [] = {
+ "norsk (Norge)",
+ "norsk (Norge, B)",
+ //ndn,
+ "norsk (Noreg, NY)"
+ //"Norsk (Noreg, Nynorsk)"
+ };
+ UErrorCode status = U_ZERO_ERROR;
+
+ Locale saveLocale;
+ Locale::setDefault(Locale::getEnglish(), status);
+ for (int32_t i = 0; i < 3; ++i) {
+ Locale loc = locales[i];
+ UnicodeString temp;
+ if (loc.getDisplayName(temp) != englishDisplayNames[i])
+ errln("English display-name mismatch: expected " +
+ englishDisplayNames[i] + ", got " + loc.getDisplayName(temp));
+ if (loc.getDisplayName(loc, temp) != norwegianDisplayNames[i])
+ errln("Norwegian display-name mismatch: expected " +
+ norwegianDisplayNames[i] + ", got " +
+ loc.getDisplayName(loc, temp));
+ }
+ Locale::setDefault(saveLocale, status);
+}
+
+void
+LocaleTest::TestVariantParsing()
+{
+ Locale en_US_custom("en", "US", "De Anza_Cupertino_California_United States_Earth");
+
+ UnicodeString dispName("English (United States, DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH)");
+ UnicodeString dispVar("DE ANZA_CUPERTINO_CALIFORNIA_UNITED STATES_EARTH");
+
+ UnicodeString got;
+
+ en_US_custom.getDisplayVariant(Locale::getUS(), got);
+ if(got != dispVar) {
+ errln("FAIL: getDisplayVariant()");
+ errln("Wanted: " + dispVar);
+ errln("Got : " + got);
+ }
+
+ en_US_custom.getDisplayName(Locale::getUS(), got);
+ if(got != dispName) {
+ errln("FAIL: getDisplayName()");
+ errln("Wanted: " + dispName);
+ errln("Got : " + got);
+ }
+
+ Locale shortVariant("fr", "FR", "foo");
+ shortVariant.getDisplayVariant(got);
+
+ if(got != "FOO") {
+ errln("FAIL: getDisplayVariant()");
+ errln("Wanted: foo");
+ errln("Got : " + got);
+ }
+
+ Locale bogusVariant("fr", "FR", "_foo");
+ bogusVariant.getDisplayVariant(got);
+
+ if(got != "FOO") {
+ errln("FAIL: getDisplayVariant()");
+ errln("Wanted: foo");
+ errln("Got : " + got);
+ }
+
+ Locale bogusVariant2("fr", "FR", "foo_");
+ bogusVariant2.getDisplayVariant(got);
+
+ if(got != "FOO") {
+ errln("FAIL: getDisplayVariant()");
+ errln("Wanted: foo");
+ errln("Got : " + got);
+ }
+
+ Locale bogusVariant3("fr", "FR", "_foo_");
+ bogusVariant3.getDisplayVariant(got);
+
+ if(got != "FOO") {
+ errln("FAIL: getDisplayVariant()");
+ errln("Wanted: foo");
+ errln("Got : " + got);
+ }
+}
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * @bug 4105828
+ * Currency symbol in zh is wrong. We will test this at the NumberFormat
+ * end to test the whole pipe.
+ */
+void
+LocaleTest::Test4105828()
+{
+ Locale LOC [] = { Locale::getChinese(), Locale("zh", "CN", ""),
+ Locale("zh", "TW", ""), Locale("zh", "HK", "") };
+ UErrorCode status = U_ZERO_ERROR;
+ for (int32_t i = 0; i < 4; ++i) {
+ NumberFormat *fmt = NumberFormat::createPercentInstance(LOC[i], status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create NumberFormat");
+ return;
+ }
+ UnicodeString result;
+ FieldPosition pos(0);
+ fmt->format((int32_t)1, result, pos);
+ UnicodeString temp;
+ if(result != "100%") {
+ errln(UnicodeString("Percent for ") + LOC[i].getDisplayName(temp) + " should be 100%, got " + result);
+ }
+ delete fmt;
+ }
+}
+
+#endif
+
+// Tests setBogus and isBogus APIs for Locale
+// Jitterbug 1735
+void
+LocaleTest::TestSetIsBogus() {
+ Locale l("en_US");
+ l.setToBogus();
+ if(l.isBogus() != TRUE) {
+ errln("After setting bogus, didn't return TRUE");
+ }
+ l = "en_US"; // This should reset bogus
+ if(l.isBogus() != FALSE) {
+ errln("After resetting bogus, didn't return FALSE");
+ }
+}
+
+
+void
+LocaleTest::TestKeywordVariants(void) {
+ static const struct {
+ const char *localeID;
+ const char *expectedLocaleID;
+ //const char *expectedLocaleIDNoKeywords;
+ //const char *expectedCanonicalID;
+ const char *expectedKeywords[10];
+ int32_t numKeywords;
+ UErrorCode expectedStatus;
+ } testCases[] = {
+ {
+ "de_DE@ currency = euro; C o ll A t i o n = Phonebook ; C alen dar = buddhist ",
+ "de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
+ //"de_DE",
+ //"de_DE@calendar=buddhist;collation=Phonebook;currency=euro",
+ {"calendar", "collation", "currency"},
+ 3,
+ U_ZERO_ERROR
+ },
+ {
+ "de_DE@euro",
+ "de_DE@euro",
+ //"de_DE",
+ //"de_DE@currency=EUR",
+ {"","","","","","",""},
+ 0,
+ U_INVALID_FORMAT_ERROR /* must have '=' after '@' */
+ }
+ };
+ UErrorCode status = U_ZERO_ERROR;
+
+ int32_t i = 0, j = 0;
+ const char *result = NULL;
+ StringEnumeration *keywords;
+ int32_t keyCount = 0;
+ const char *keyword = NULL;
+ const UnicodeString *keywordString;
+ int32_t keywordLen = 0;
+
+ for(i = 0; i < (int32_t)(sizeof(testCases)/sizeof(testCases[0])); i++) {
+ status = U_ZERO_ERROR;
+ Locale l(testCases[i].localeID);
+ keywords = l.createKeywords(status);
+
+ if(status != testCases[i].expectedStatus) {
+ err("Expected to get status %s. Got %s instead\n",
+ u_errorName(testCases[i].expectedStatus), u_errorName(status));
+ }
+ status = U_ZERO_ERROR;
+ if(keywords) {
+ if((keyCount = keywords->count(status)) != testCases[i].numKeywords) {
+ err("Expected to get %i keywords, got %i\n", testCases[i].numKeywords, keyCount);
+ }
+ if(keyCount) {
+ for(j = 0;;) {
+ if((j&1)==0) {
+ if((keyword = keywords->next(&keywordLen, status)) == NULL) {
+ break;
+ }
+ if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
+ err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
+ }
+ } else {
+ if((keywordString = keywords->snext(status)) == NULL) {
+ break;
+ }
+ if(*keywordString != UnicodeString(testCases[i].expectedKeywords[j], "")) {
+ err("Expected to get keyword UnicodeString %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
+ }
+ }
+ j++;
+
+ if(j == keyCount / 2) {
+ // replace keywords with a clone of itself
+ StringEnumeration *k2 = keywords->clone();
+ if(k2 == NULL || keyCount != k2->count(status)) {
+ errln("KeywordEnumeration.clone() failed");
+ } else {
+ delete keywords;
+ keywords = k2;
+ }
+ }
+ }
+ keywords->reset(status); // Make sure that reset works.
+ for(j = 0;;) {
+ if((keyword = keywords->next(&keywordLen, status)) == NULL) {
+ break;
+ }
+ if(strcmp(keyword, testCases[i].expectedKeywords[j]) != 0) {
+ err("Expected to get keyword value %s, got %s\n", testCases[i].expectedKeywords[j], keyword);
+ }
+ j++;
+ }
+ }
+ delete keywords;
+ }
+ result = l.getName();
+ if(uprv_strcmp(testCases[i].expectedLocaleID, result) != 0) {
+ err("Expected to get \"%s\" from \"%s\". Got \"%s\" instead\n",
+ testCases[i].expectedLocaleID, testCases[i].localeID, result);
+ }
+
+ }
+
+}
+
+void
+LocaleTest::TestKeywordVariantParsing(void) {
+ static const struct {
+ const char *localeID;
+ const char *keyword;
+ const char *expectedValue;
+ } testCases[] = {
+ { "de_DE@ C o ll A t i o n = Phonebook ", "collation", "Phonebook" },
+ { "de_DE", "collation", ""},
+ { "de_DE@collation= PHONEBOOK", "collation", "PHONEBOOK" },
+ { "de_DE@ currency = euro ; CoLLaTion = PHONEBOOk ", "collation", "PHONEBOOk" },
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ int32_t i = 0;
+ int32_t resultLen = 0;
+ char buffer[256];
+
+ for(i = 0; i < (int32_t)(sizeof(testCases)/sizeof(testCases[0])); i++) {
+ *buffer = 0;
+ Locale l(testCases[i].localeID);
+ resultLen = l.getKeywordValue(testCases[i].keyword, buffer, 256, status);
+ if(uprv_strcmp(testCases[i].expectedValue, buffer) != 0) {
+ err("Expected to extract \"%s\" from \"%s\" for keyword \"%s\". Got \"%s\" instead\n",
+ testCases[i].expectedValue, testCases[i].localeID, testCases[i].keyword, buffer);
+ }
+ }
+}
+
+void
+LocaleTest::TestGetBaseName(void) {
+ static const struct {
+ const char *localeID;
+ const char *baseName;
+ } testCases[] = {
+ { "de_DE@ C o ll A t i o n = Phonebook ", "de_DE" },
+ { "de@currency = euro; CoLLaTion = PHONEBOOk", "de" },
+ { "ja@calendar = buddhist", "ja" }
+ };
+
+ int32_t i = 0;
+
+ for(i = 0; i < (int32_t)(sizeof(testCases)/sizeof(testCases[0])); i++) {
+ Locale loc(testCases[i].localeID);
+ if(strcmp(testCases[i].baseName, loc.getBaseName())) {
+ errln("For locale \"%s\" expected baseName \"%s\", but got \"%s\"",
+ testCases[i].localeID, testCases[i].baseName, loc.getBaseName());
+ return;
+ }
+ }
+}
+
+/**
+ * Compare two locale IDs. If they are equal, return 0. If `string'
+ * starts with `prefix' plus an additional element, that is, string ==
+ * prefix + '_' + x, then return 1. Otherwise return a value < 0.
+ */
+static UBool _loccmp(const char* string, const char* prefix) {
+ int32_t slen = (int32_t)strlen(string),
+ plen = (int32_t)strlen(prefix);
+ int32_t c = uprv_strncmp(string, prefix, plen);
+ /* 'root' is "less than" everything */
+ if (uprv_strcmp(prefix, "root") == 0) {
+ return (uprv_strcmp(string, "root") == 0) ? 0 : 1;
+ }
+ if (c) return -1; /* mismatch */
+ if (slen == plen) return 0;
+ if (string[plen] == '_') return 1;
+ return -2; /* false match, e.g. "en_USX" cmp "en_US" */
+}
+
+/**
+ * Check the relationship between requested locales, and report problems.
+ * The caller specifies the expected relationships between requested
+ * and valid (expReqValid) and between valid and actual (expValidActual).
+ * Possible values are:
+ * "gt" strictly greater than, e.g., en_US > en
+ * "ge" greater or equal, e.g., en >= en
+ * "eq" equal, e.g., en == en
+ */
+void LocaleTest::_checklocs(const char* label,
+ const char* req,
+ const Locale& validLoc,
+ const Locale& actualLoc,
+ const char* expReqValid,
+ const char* expValidActual) {
+ const char* valid = validLoc.getName();
+ const char* actual = actualLoc.getName();
+ int32_t reqValid = _loccmp(req, valid);
+ int32_t validActual = _loccmp(valid, actual);
+ if (((0 == uprv_strcmp(expReqValid, "gt") && reqValid > 0) ||
+ (0 == uprv_strcmp(expReqValid, "ge") && reqValid >= 0) ||
+ (0 == uprv_strcmp(expReqValid, "eq") && reqValid == 0)) &&
+ ((0 == uprv_strcmp(expValidActual, "gt") && validActual > 0) ||
+ (0 == uprv_strcmp(expValidActual, "ge") && validActual >= 0) ||
+ (0 == uprv_strcmp(expValidActual, "eq") && validActual == 0))) {
+ logln("%s; req=%s, valid=%s, actual=%s",
+ label, req, valid, actual);
+ } else {
+ errln("FAIL: %s; req=%s, valid=%s, actual=%s. Require (R %s V) and (V %s A)",
+ label, req, valid, actual,
+ expReqValid, expValidActual);
+ }
+}
+
+void LocaleTest::TestGetLocale(void) {
+#if !UCONFIG_NO_SERVICE
+ UErrorCode ec = U_ZERO_ERROR;
+ const char *req;
+ Locale valid, actual, reqLoc;
+
+ // Calendar
+#if !UCONFIG_NO_FORMATTING
+ req = "en_US_BROOKLYN";
+ Calendar* cal = Calendar::createInstance(Locale::createFromName(req), ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Calendar::createInstance failed");
+ } else {
+ valid = cal->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = cal->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Calendar::getLocale() failed");
+ } else {
+ _checklocs("Calendar", req, valid, actual);
+ }
+ /* Make sure that it fails correctly */
+ ec = U_FILE_ACCESS_ERROR;
+ if (cal->getLocale(ULOC_VALID_LOCALE, ec).getName()[0] != 0) {
+ errln("FAIL: Calendar::getLocale() failed to fail correctly. It should have returned \"\"");
+ }
+ ec = U_ZERO_ERROR;
+ }
+ delete cal;
+#endif
+
+ // DecimalFormat, DecimalFormatSymbols
+#if !UCONFIG_NO_FORMATTING
+ req = "fr_FR_NICE";
+ DecimalFormat* dec = (DecimalFormat*)
+ NumberFormat::createInstance(Locale::createFromName(req), ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: NumberFormat::createInstance failed");
+ } else {
+ if (dec->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ errln("FAIL: NumberFormat::createInstance does not return a DecimalFormat");
+ return;
+ }
+ valid = dec->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = dec->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: DecimalFormat::getLocale() failed");
+ } else {
+ _checklocs("DecimalFormat", req, valid, actual);
+ }
+
+ const DecimalFormatSymbols* sym = dec->getDecimalFormatSymbols();
+ if (sym == NULL) {
+ errln("FAIL: getDecimalFormatSymbols returned NULL");
+ return;
+ }
+ valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: DecimalFormatSymbols::getLocale() failed");
+ } else {
+ _checklocs("DecimalFormatSymbols", req, valid, actual);
+ }
+ }
+ delete dec;
+#endif
+
+ // DateFormat, DateFormatSymbols
+#if !UCONFIG_NO_FORMATTING
+ req = "de_CH_LUCERNE";
+ SimpleDateFormat* dat = (SimpleDateFormat*)
+ DateFormat::createDateInstance(DateFormat::kDefault,
+ Locale::createFromName(req));
+ if (dat == 0){
+ dataerrln("Error calling DateFormat::createDateInstance()");
+ } else {
+ if (dat->getDynamicClassID() != SimpleDateFormat::getStaticClassID()) {
+ errln("FAIL: NumberFormat::createInstance does not return a DecimalFormat");
+ return;
+ }
+ valid = dat->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = dat->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: SimpleDateFormat::getLocale() failed");
+ } else {
+ _checklocs("SimpleDateFormat", req, valid, actual);
+ }
+
+ const DateFormatSymbols* sym = dat->getDateFormatSymbols();
+ if (sym == NULL) {
+ errln("FAIL: getDateFormatSymbols returned NULL");
+ return;
+ }
+ valid = sym->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = sym->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: DateFormatSymbols::getLocale() failed");
+ } else {
+ _checklocs("DateFormatSymbols", req, valid, actual);
+ }
+ }
+ delete dat;
+#endif
+
+ // BreakIterator
+#if !UCONFIG_NO_BREAK_ITERATION
+ req = "es_ES_BARCELONA";
+ reqLoc = Locale::createFromName(req);
+ BreakIterator* brk = BreakIterator::createWordInstance(reqLoc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::createWordInstance failed");
+ } else {
+ valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::getLocale() failed");
+ } else {
+ _checklocs("BreakIterator", req, valid, actual);
+ }
+
+ // After registering something, the behavior should be different
+ URegistryKey key = BreakIterator::registerInstance(brk, reqLoc, UBRK_WORD, ec);
+ brk = 0; // registerInstance adopts
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::registerInstance() failed");
+ } else {
+ brk = BreakIterator::createWordInstance(reqLoc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::createWordInstance failed");
+ } else {
+ valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::getLocale() failed");
+ } else {
+ // N.B.: now expect valid==actual==req
+ _checklocs("BreakIterator(registered)",
+ req, valid, actual, "eq", "eq");
+ }
+ }
+ // No matter what, unregister
+ BreakIterator::unregister(key, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::unregister() failed");
+ }
+ delete brk;
+ brk = 0;
+ }
+
+ // After unregistering, should behave normally again
+ brk = BreakIterator::createWordInstance(reqLoc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::createWordInstance failed");
+ } else {
+ valid = brk->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = brk->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: BreakIterator::getLocale() failed");
+ } else {
+ _checklocs("BreakIterator(unregistered)", req, valid, actual);
+ }
+ }
+ }
+ delete brk;
+#endif
+
+ // Collator
+#if !UCONFIG_NO_COLLATION
+ req = "hi_IN_BHOPAL";
+ reqLoc = Locale::createFromName(req);
+ Collator* coll = Collator::createInstance(reqLoc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::createInstance failed");
+ } else {
+ valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::getLocale() failed");
+ } else {
+ _checklocs("Collator", req, valid, actual);
+ }
+
+ // After registering something, the behavior should be different
+ URegistryKey key = Collator::registerInstance(coll, reqLoc, ec);
+ coll = 0; // registerInstance adopts
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::registerInstance() failed");
+ } else {
+ coll = Collator::createInstance(reqLoc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::createWordInstance failed");
+ } else {
+ valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::getLocale() failed");
+ } else {
+ // N.B.: now expect valid==actual==req
+ _checklocs("Collator(registered)",
+ req, valid, actual, "eq", "eq");
+ }
+ }
+ // No matter what, unregister
+ Collator::unregister(key, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::unregister() failed");
+ }
+ delete coll;
+ coll = 0;
+ }
+
+ // After unregistering, should behave normally again
+ coll = Collator::createInstance(reqLoc, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::createInstance failed");
+ } else {
+ valid = coll->getLocale(ULOC_VALID_LOCALE, ec);
+ actual = coll->getLocale(ULOC_ACTUAL_LOCALE, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Collator::getLocale() failed");
+ } else {
+ _checklocs("Collator(unregistered)", req, valid, actual);
+ }
+ }
+ }
+ delete coll;
+#endif
+#endif
+}
+
+void LocaleTest::TestVariantWithOutCountry(void) {
+ Locale loc("en","","POSIX");
+ if (0 != strcmp(loc.getVariant(), "POSIX")) {
+ errln("FAIL: en__POSIX didn't get parsed correctly");
+ }
+ Locale loc2("en","","FOUR");
+ if (0 != strcmp(loc2.getVariant(), "FOUR")) {
+ errln("FAIL: en__FOUR didn't get parsed correctly");
+ }
+ Locale loc3("en","Latn","","FOUR");
+ if (0 != strcmp(loc3.getVariant(), "FOUR")) {
+ errln("FAIL: en_Latn__FOUR didn't get parsed correctly");
+ }
+ Locale loc4("","Latn","","FOUR");
+ if (0 != strcmp(loc4.getVariant(), "FOUR")) {
+ errln("FAIL: _Latn__FOUR didn't get parsed correctly");
+ }
+ Locale loc5("","Latn","US","FOUR");
+ if (0 != strcmp(loc5.getVariant(), "FOUR")) {
+ errln("FAIL: _Latn_US_FOUR didn't get parsed correctly");
+ }
+}
+
+static Locale _canonicalize(int32_t selector, /* 0==createFromName, 1==createCanonical, 2==Locale ct */
+ const char* localeID) {
+ switch (selector) {
+ case 0:
+ return Locale::createFromName(localeID);
+ case 1:
+ return Locale::createCanonical(localeID);
+ case 2:
+ return Locale(localeID);
+ default:
+ return Locale("");
+ }
+}
+
+void LocaleTest::TestCanonicalization(void)
+{
+ static const struct {
+ const char *localeID; /* input */
+ const char *getNameID; /* expected getName() result */
+ const char *canonicalID; /* expected canonicalize() result */
+ } testCases[] = {
+ { "ca_ES_PREEURO-with-extra-stuff-that really doesn't make any sense-unless-you're trying to increase code coverage",
+ "ca_ES_PREEURO_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE",
+ "ca_ES_PREEURO_WITH_EXTRA_STUFF_THAT REALLY DOESN'T MAKE ANY SENSE_UNLESS_YOU'RE TRYING TO INCREASE CODE COVERAGE"},
+ { "ca_ES_PREEURO", "ca_ES_PREEURO", "ca_ES@currency=ESP" },
+ { "de_AT_PREEURO", "de_AT_PREEURO", "de_AT@currency=ATS" },
+ { "de_DE_PREEURO", "de_DE_PREEURO", "de_DE@currency=DEM" },
+ { "de_LU_PREEURO", "de_LU_PREEURO", "de_LU@currency=LUF" },
+ { "el_GR_PREEURO", "el_GR_PREEURO", "el_GR@currency=GRD" },
+ { "en_BE_PREEURO", "en_BE_PREEURO", "en_BE@currency=BEF" },
+ { "en_IE_PREEURO", "en_IE_PREEURO", "en_IE@currency=IEP" },
+ { "es_ES_PREEURO", "es_ES_PREEURO", "es_ES@currency=ESP" },
+ { "eu_ES_PREEURO", "eu_ES_PREEURO", "eu_ES@currency=ESP" },
+ { "fi_FI_PREEURO", "fi_FI_PREEURO", "fi_FI@currency=FIM" },
+ { "fr_BE_PREEURO", "fr_BE_PREEURO", "fr_BE@currency=BEF" },
+ { "fr_FR_PREEURO", "fr_FR_PREEURO", "fr_FR@currency=FRF" },
+ { "fr_LU_PREEURO", "fr_LU_PREEURO", "fr_LU@currency=LUF" },
+ { "ga_IE_PREEURO", "ga_IE_PREEURO", "ga_IE@currency=IEP" },
+ { "gl_ES_PREEURO", "gl_ES_PREEURO", "gl_ES@currency=ESP" },
+ { "it_IT_PREEURO", "it_IT_PREEURO", "it_IT@currency=ITL" },
+ { "nl_BE_PREEURO", "nl_BE_PREEURO", "nl_BE@currency=BEF" },
+ { "nl_NL_PREEURO", "nl_NL_PREEURO", "nl_NL@currency=NLG" },
+ { "pt_PT_PREEURO", "pt_PT_PREEURO", "pt_PT@currency=PTE" },
+ { "de__PHONEBOOK", "de__PHONEBOOK", "de@collation=phonebook" },
+ { "en_GB_EURO", "en_GB_EURO", "en_GB@currency=EUR" },
+ { "en_GB@EURO", "en_GB@EURO", "en_GB@currency=EUR" }, /* POSIX ID */
+ { "es__TRADITIONAL", "es__TRADITIONAL", "es@collation=traditional" },
+ { "hi__DIRECT", "hi__DIRECT", "hi@collation=direct" },
+ { "ja_JP_TRADITIONAL", "ja_JP_TRADITIONAL", "ja_JP@calendar=japanese" },
+ { "th_TH_TRADITIONAL", "th_TH_TRADITIONAL", "th_TH@calendar=buddhist" },
+ { "zh_TW_STROKE", "zh_TW_STROKE", "zh_Hant_TW@collation=stroke" },
+ { "zh__PINYIN", "zh__PINYIN", "zh@collation=pinyin" },
+ { "zh@collation=pinyin", "zh@collation=pinyin", "zh@collation=pinyin" },
+ { "zh_CN@collation=pinyin", "zh_CN@collation=pinyin", "zh_CN@collation=pinyin" },
+ { "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin", "zh_CN_CA@collation=pinyin" },
+ { "en_US_POSIX", "en_US_POSIX", "en_US_POSIX" },
+ { "hy_AM_REVISED", "hy_AM_REVISED", "hy_AM_REVISED" },
+ { "no_NO_NY", "no_NO_NY", "no_NO_NY" /* not: "nn_NO" [alan ICU3.0] */ },
+ { "no@ny", "no@ny", "no__NY" /* not: "nn" [alan ICU3.0] */ }, /* POSIX ID */
+ { "no-no.utf32@B", "no_NO.utf32@B", "no_NO_B" /* not: "nb_NO_B" [alan ICU3.0] */ }, /* POSIX ID */
+ { "qz-qz@Euro", "qz_QZ@Euro", "qz_QZ@currency=EUR" }, /* qz-qz uses private use iso codes */
+ // NOTE: uloc_getName() works on en-BOONT, but Locale() parser considers it BOGUS
+ // TODO: unify this behavior
+ { "en-BOONT", "BOGUS", "en__BOONT" }, /* registered name */
+ { "de-1901", "de_1901", "de__1901" }, /* registered name */
+ { "de-1906", "de_1906", "de__1906" }, /* registered name */
+ { "sr-SP-Cyrl", "sr_SP_CYRL", "sr_Cyrl_CS" }, /* .NET name */
+ { "sr-SP-Latn", "sr_SP_LATN", "sr_Latn_CS" }, /* .NET name */
+ { "sr_YU_CYRILLIC", "sr_YU_CYRILLIC", "sr_Cyrl_CS" }, /* Linux name */
+ { "uz-UZ-Cyrl", "uz_UZ_CYRL", "uz_Cyrl_UZ" }, /* .NET name */
+ { "uz-UZ-Latn", "uz_UZ_LATN", "uz_Latn_UZ" }, /* .NET name */
+ { "zh-CHS", "zh_CHS", "zh_Hans" }, /* .NET name */
+ { "zh-CHT", "zh_CHT", "zh_Hant" }, /* .NET name This may change back to zh_Hant */
+
+ /* posix behavior that used to be performed by getName */
+ { "mr.utf8", "mr.utf8", "mr" },
+ { "de-tv.koi8r", "de_TV.koi8r", "de_TV" },
+ { "x-piglatin_ML.MBE", "x-piglatin_ML.MBE", "x-piglatin_ML" },
+ { "i-cherokee_US.utf7", "i-cherokee_US.utf7", "i-cherokee_US" },
+ { "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA.gb-18030", "x-filfli_MT_FILFLA" },
+ { "no-no-ny.utf8@B", "no_NO_NY.utf8@B", "no_NO_NY_B" /* not: "nn_NO" [alan ICU3.0] */ }, /* @ ignored unless variant is empty */
+
+ /* fleshing out canonicalization */
+ /* trim space and sort keywords, ';' is separator so not present at end in canonical form */
+ { "en_Hant_IL_VALLEY_GIRL@ currency = EUR; calendar = Japanese ;", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR" },
+ /* already-canonical ids are not changed */
+ { "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR", "en_Hant_IL_VALLEY_GIRL@calendar=Japanese;currency=EUR" },
+ /* PRE_EURO and EURO conversions don't affect other keywords */
+ { "es_ES_PREEURO@CALendar=Japanese", "es_ES_PREEURO@calendar=Japanese", "es_ES@calendar=Japanese;currency=ESP" },
+ { "es_ES_EURO@SHOUT=zipeedeedoodah", "es_ES_EURO@shout=zipeedeedoodah", "es_ES@currency=EUR;shout=zipeedeedoodah" },
+ /* currency keyword overrides PRE_EURO and EURO currency */
+ { "es_ES_PREEURO@currency=EUR", "es_ES_PREEURO@currency=EUR", "es_ES@currency=EUR" },
+ { "es_ES_EURO@currency=ESP", "es_ES_EURO@currency=ESP", "es_ES@currency=ESP" },
+ /* norwegian is just too weird, if we handle things in their full generality */
+ { "no-Hant-GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$", "no_Hant_GB_NY@currency=$$$" /* not: "nn_Hant_GB@currency=$$$" [alan ICU3.0] */ },
+
+ /* test cases reflecting internal resource bundle usage */
+ { "root@kw=foo", "root@kw=foo", "root@kw=foo" },
+ { "@calendar=gregorian", "@calendar=gregorian", "@calendar=gregorian" },
+ { "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese", "ja_JP@calendar=Japanese" }
+ };
+
+ static const char* label[] = { "createFromName", "createCanonical", "Locale" };
+
+ int32_t i, j;
+
+ for (i=0; i < (int)(sizeof(testCases)/sizeof(testCases[0])); i++) {
+ for (j=0; j<3; ++j) {
+ const char* expected = (j==1) ? testCases[i].canonicalID : testCases[i].getNameID;
+ Locale loc = _canonicalize(j, testCases[i].localeID);
+ const char* getName = loc.isBogus() ? "BOGUS" : loc.getName();
+ if(uprv_strcmp(expected, getName) != 0) {
+ errln("FAIL: %s(%s).getName() => \"%s\", expected \"%s\"",
+ label[j], testCases[i].localeID, getName, expected);
+ } else {
+ logln("Ok: %s(%s) => \"%s\"",
+ label[j], testCases[i].localeID, getName);
+ }
+ }
+ }
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/loctest.h b/Build/source/libs/icu/icu-xetex/test/intltest/loctest.h
new file mode 100644
index 00000000000..c01d15ecb25
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/loctest.h
@@ -0,0 +1,167 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2004, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "intltest.h"
+#include "unicode/locid.h"
+
+/**
+ * Tests for the Locale class
+ **/
+class LocaleTest: public IntlTest {
+public:
+ LocaleTest();
+ virtual ~LocaleTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ /**
+ * Test methods to set and get data fields
+ **/
+ void TestBasicGetters(void);
+ /**
+ * Test methods to set and get data fields
+ **/
+ void TestParallelAPIValues(void);
+ /**
+ * Use Locale to access Resource file data and compare against expected values
+ **/
+ void TestSimpleResourceInfo(void);
+ /**
+ * Use Locale to access Resource file display names and compare against expected values
+ **/
+ void TestDisplayNames(void);
+ /**
+ * Test methods for basic object behaviour
+ **/
+ void TestSimpleObjectStuff(void);
+ /**
+ * Test methods for POSIX parsing behavior
+ **/
+ void TestPOSIXParsing(void);
+ /**
+ * Test Locale::getAvailableLocales
+ **/
+ void TestGetAvailableLocales(void);
+ /**
+ * Test methods to set and access a custom data directory
+ **/
+ void TestDataDirectory(void);
+
+ void TestISO3Fallback(void);
+ void TestGetLangsAndCountries(void);
+ void TestSimpleDisplayNames(void);
+ void TestUninstalledISO3Names(void);
+ void TestAtypicalLocales(void);
+#if !UCONFIG_NO_FORMATTING
+ void TestThaiCurrencyFormat(void);
+ void TestEuroSupport(void);
+#endif
+ void TestToString(void);
+#if !UCONFIG_NO_FORMATTING
+ void Test4139940(void);
+ void Test4143951(void);
+#endif
+ void Test4147315(void);
+ void Test4147317(void);
+ void Test4147552(void);
+
+ void TestVariantParsing(void);
+
+ /* Test getting keyword enumeratin */
+ void TestKeywordVariants(void);
+
+ /* Test getting keyword values */
+ void TestKeywordVariantParsing(void);
+
+ /* Test getting the locale base name */
+ void TestGetBaseName(void);
+
+#if !UCONFIG_NO_FORMATTING
+ void Test4105828(void) ;
+#endif
+
+ void TestSetIsBogus(void);
+
+ void TestGetLocale(void);
+
+ void TestVariantWithOutCountry(void);
+
+ void TestCanonicalization(void);
+
+#if !UCONFIG_NO_FORMATTING
+ static UDate date(int32_t y, int32_t m, int32_t d, int32_t hr = 0, int32_t min = 0, int32_t sec = 0);
+#endif
+
+private:
+ void _checklocs(const char* label,
+ const char* req,
+ const Locale& validLoc,
+ const Locale& actualLoc,
+ const char* expReqValid="gt",
+ const char* expValidActual="ge");
+
+ /**
+ * routine to perform subtests, used by TestDisplayNames
+ **/
+ void doTestDisplayNames(Locale& inLocale, int32_t compareIndex);
+ /**
+ * additional intialization for datatables storing expected values
+ **/
+ void setUpDataTable(void);
+
+ UnicodeString** dataTable;
+
+ enum {
+ ENGLISH = 0,
+ FRENCH = 1,
+ CROATIAN = 2,
+ GREEK = 3,
+ NORWEGIAN = 4,
+ ITALIAN = 5,
+ XX = 6,
+ CHINESE = 7,
+ MAX_LOCALES = 7
+ };
+
+ enum {
+ LANG = 0,
+ SCRIPT,
+ CTRY,
+ VAR,
+ NAME,
+ LANG3,
+ CTRY3,
+ LCID,
+ DLANG_EN,
+ DSCRIPT_EN,
+ DCTRY_EN,
+ DVAR_EN,
+ DNAME_EN,
+ DLANG_FR,
+ DSCRIPT_FR,
+ DCTRY_FR,
+ DVAR_FR,
+ DNAME_FR,
+ DLANG_CA,
+ DSCRIPT_CA,
+ DCTRY_CA,
+ DVAR_CA,
+ DNAME_CA,
+ DLANG_EL,
+ DSCRIPT_EL,
+ DCTRY_EL,
+ DVAR_EL,
+ DNAME_EL,
+ DLANG_NO,
+ DSCRIPT_NO,
+ DCTRY_NO,
+ DVAR_NO,
+ DNAME_NO
+ };
+};
+
+
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/miscdtfm.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/miscdtfm.cpp
new file mode 100644
index 00000000000..36b9357a96b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/miscdtfm.cpp
@@ -0,0 +1,378 @@
+/***********************************************************************
+ * Copyright (c) 1997-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "miscdtfm.h"
+
+#include "unicode/format.h"
+#include "unicode/decimfmt.h"
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/locid.h"
+#include "unicode/msgfmt.h"
+#include "unicode/numfmt.h"
+#include "unicode/choicfmt.h"
+#include "unicode/gregocal.h"
+
+// *****************************************************************************
+// class DateFormatMiscTests
+// *****************************************************************************
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
+
+void
+DateFormatMiscTests::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite DateFormatMiscTests");
+ switch (index) {
+ CASE(0, test4097450)
+ CASE(1, test4099975)
+ CASE(2, test4117335)
+
+ default: name = ""; break;
+ }
+}
+
+UBool
+DateFormatMiscTests::failure(UErrorCode status, const char* msg)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * @bug 4097450
+ */
+void
+DateFormatMiscTests::test4097450()
+{
+ //
+ // Date parse requiring 4 digit year.
+ //
+ UnicodeString dstring [] = {
+ UnicodeString("97"),
+ UnicodeString("1997"),
+ UnicodeString("97"),
+ UnicodeString("1997"),
+ UnicodeString("01"),
+ UnicodeString("2001"),
+ UnicodeString("01"),
+ UnicodeString("2001"),
+ UnicodeString("1"),
+ UnicodeString("1"),
+ UnicodeString("11"),
+ UnicodeString("11"),
+ UnicodeString("111"),
+ UnicodeString("111")
+ };
+
+ UnicodeString dformat [] = {
+ UnicodeString("yy"),
+ UnicodeString("yy"),
+ UnicodeString("yyyy"),
+ UnicodeString("yyyy"),
+ UnicodeString("yy"),
+ UnicodeString("yy"),
+ UnicodeString("yyyy"),
+ UnicodeString("yyyy"),
+ UnicodeString("yy"),
+ UnicodeString("yyyy"),
+ UnicodeString("yy"),
+ UnicodeString("yyyy"),
+ UnicodeString("yy"),
+ UnicodeString("yyyy")
+ };
+
+/* UBool dresult [] = {
+ TRUE,
+ FALSE,
+ FALSE,
+ TRUE,
+ TRUE,
+ FALSE,
+ FALSE,
+ TRUE,
+ FALSE,
+ FALSE,
+ TRUE,
+ FALSE,
+ FALSE,
+ FALSE
+ };*/
+
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *formatter;
+ SimpleDateFormat *resultFormatter = new SimpleDateFormat((UnicodeString)"yyyy", status);
+ failure(status, "new SimpleDateFormat");
+
+ logln("Format\tSource\tResult");
+ logln("-------\t-------\t-------");
+ for (int i = 0; i < 14/*dstring.length*/; i++)
+ {
+ log(dformat[i] + "\t" + dstring[i] + "\t");
+ formatter = new SimpleDateFormat(dformat[i], status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ //try {
+ UnicodeString str;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ logln(resultFormatter->format(formatter->parse(dstring[i], status), str, pos));
+ failure(status, "resultFormatter->format");
+ //if ( !dresult[i] ) System.out.print(" <-- error!");
+ /*}
+ catch (ParseException exception) {
+ //if ( dresult[i] ) System.out.print(" <-- error!");
+ System.out.print("exception --> " + exception);
+ }*/
+ delete formatter;
+ logln();
+ }
+
+ delete resultFormatter;
+}
+
+/*
+ * @bug 4099975
+ */
+void
+DateFormatMiscTests::test4099975()
+{
+ /**
+ * Test Constructor SimpleDateFormat::SimpleDateFormat (const UnicodeString & pattern,
+ * const DateFormatSymbols & formatData, UErrorCode & status )
+ * The DateFormatSymbols object is NOT adopted; Modifying the original DateFormatSymbols
+ * should not change the SimpleDateFormat's behavior.
+ */
+ UDate d = Calendar::getNow();
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormatSymbols* symbols = new DateFormatSymbols(Locale::getUS(), status);
+ if(failure(status, "new DateFormatSymbols")) return;
+ SimpleDateFormat *df = new SimpleDateFormat(UnicodeString("E hh:mm"), *symbols, status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ UnicodeString format0;
+ format0 = df->format(d, format0);
+ UnicodeString localizedPattern0;
+ localizedPattern0 = df->toLocalizedPattern(localizedPattern0, status);
+ failure(status, "df->toLocalizedPattern");
+ symbols->setLocalPatternChars(UnicodeString("abcdefghijklmonpqr")); // change value of field
+ UnicodeString format1;
+ format1 = df->format(d, format1);
+ if (format0 != format1) {
+ errln(UnicodeString("Formats are different. format0: ") + format0
+ + UnicodeString("; format1: ") + format1);
+ }
+ UnicodeString localizedPattern1;
+ localizedPattern1 = df->toLocalizedPattern(localizedPattern1, status);
+ failure(status, "df->toLocalizedPattern");
+ if (localizedPattern0 != localizedPattern1) {
+ errln(UnicodeString("Pattern has been changed. localizedPattern0: ") + localizedPattern0
+ + UnicodeString("; localizedPattern1: ") + localizedPattern1);
+ }
+ delete symbols;
+ delete df;
+ }
+ /*
+ * Test void SimpleDateFormat::setDateFormatSymbols ( const DateFormatSymbols & newFormatSymbols )
+ * Modifying the original DateFormatSymbols should not change the SimpleDateFormat's behavior.
+ */
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormatSymbols* symbols = new DateFormatSymbols(Locale::getUS(), status);
+ if(failure(status, "new DateFormatSymbols")) return;
+ SimpleDateFormat *df = new SimpleDateFormat(UnicodeString("E hh:mm"), status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ df->setDateFormatSymbols(*symbols);
+ UnicodeString format0;
+ format0 = df->format(d, format0);
+ UnicodeString localizedPattern0;
+ localizedPattern0 = df->toLocalizedPattern(localizedPattern0, status);
+ failure(status, "df->toLocalizedPattern");
+ symbols->setLocalPatternChars(UnicodeString("abcdefghijklmonpqr")); // change value of field
+ UnicodeString format1;
+ format1 = df->format(d, format1);
+ if (format0 != format1) {
+ errln(UnicodeString("Formats are different. format0: ") + format0
+ + UnicodeString("; format1: ") + format1);
+ }
+ UnicodeString localizedPattern1;
+ localizedPattern1 = df->toLocalizedPattern(localizedPattern1, status);
+ failure(status, "df->toLocalizedPattern");
+ if (localizedPattern0 != localizedPattern1) {
+ errln(UnicodeString("Pattern has been changed. localizedPattern0: ") + localizedPattern0
+ + UnicodeString("; localizedPattern1: ") + localizedPattern1);
+ }
+ delete symbols;
+ delete df;
+
+ }
+ //Test the pointer version of the constructor (and the adoptDateFormatSymbols method)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormatSymbols* symbols = new DateFormatSymbols(Locale::getUS(), status);
+ if(failure(status, "new DateFormatSymbols")) return;
+ SimpleDateFormat *df = new SimpleDateFormat(UnicodeString("E hh:mm"), symbols, status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ UnicodeString format0;
+ format0 = df->format(d, format0);
+ UnicodeString localizedPattern0;
+ localizedPattern0 = df->toLocalizedPattern(localizedPattern0, status);
+ failure(status, "df->toLocalizedPattern");
+ symbols->setLocalPatternChars(UnicodeString("abcdefghijklmonpqr")); // change value of field
+ UnicodeString format1;
+ format1 = df->format(d, format1);
+ if (format0 != format1) {
+ errln(UnicodeString("Formats are different. format0: ") + format0
+ + UnicodeString("; format1: ") + format1);
+ }
+ UnicodeString localizedPattern1;
+ localizedPattern1 = df->toLocalizedPattern(localizedPattern1, status);
+ failure(status, "df->toLocalizedPattern");
+ if (localizedPattern0 == localizedPattern1) {
+ errln(UnicodeString("Pattern should have been changed. localizedPattern0: ") + localizedPattern0
+ + UnicodeString("; localizedPattern1: ") + localizedPattern1);
+ }
+ //delete symbols; the caller is no longer responsible for deleting the symbols
+ delete df;
+ }
+ //
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormatSymbols* symbols = new DateFormatSymbols(Locale::getUS(), status);
+ failure(status, "new DateFormatSymbols");
+ SimpleDateFormat *df = new SimpleDateFormat(UnicodeString("E hh:mm"), status);
+ if(failure(status, "new SimpleDateFormat")) return;
+ df-> adoptDateFormatSymbols(symbols);
+ UnicodeString format0;
+ format0 = df->format(d, format0);
+ UnicodeString localizedPattern0;
+ localizedPattern0 = df->toLocalizedPattern(localizedPattern0, status);
+ failure(status, "df->toLocalizedPattern");
+ symbols->setLocalPatternChars(UnicodeString("abcdefghijklmonpqr")); // change value of field
+ UnicodeString format1;
+ format1 = df->format(d, format1);
+ if (format0 != format1) {
+ errln(UnicodeString("Formats are different. format0: ") + format0
+ + UnicodeString("; format1: ") + format1);
+ }
+ UnicodeString localizedPattern1;
+ localizedPattern1 = df->toLocalizedPattern(localizedPattern1, status);
+ failure(status, "df->toLocalizedPattern");
+ if (localizedPattern0 == localizedPattern1) {
+ errln(UnicodeString("Pattern should have been changed. localizedPattern0: ") + localizedPattern0
+ + UnicodeString("; localizedPattern1: ") + localizedPattern1);
+ }
+ //delete symbols; the caller is no longer responsible for deleting the symbols
+ delete df;
+ }
+}
+
+/*
+ * @test @(#)bug4117335.java 1.1 3/5/98
+ *
+ * @bug 4117335
+ */
+void
+DateFormatMiscTests::test4117335()
+{
+ //UnicodeString bc = "\u7d00\u5143\u524d";
+ UChar bcC [] = {
+ 0x7D00,
+ 0x5143,
+ 0x524D
+ };
+ UnicodeString bc(bcC, 3, 3);
+
+ //UnicodeString ad = "\u897f\u66a6";
+ UChar adC [] = {
+ 0x897F,
+ 0x66A6
+ };
+ UnicodeString ad(adC, 2, 2);
+
+ //UnicodeString jstLong = "\u65e5\u672c\u6a19\u6e96\u6642";
+ UChar jstLongC [] = {
+ 0x65e5,
+ 0x672c,
+ 0x6a19,
+ 0x6e96,
+ 0x6642
+ };
+ UChar jdtLongC [] = {0x65E5, 0x672C, 0x590F, 0x6642, 0x9593};
+
+ UnicodeString jstLong(jstLongC, 5, 5);
+
+ UnicodeString jstShort = "JST";
+
+ UnicodeString tzID = "Asia/Tokyo";
+
+ UnicodeString jdtLong(jdtLongC, 5, 5);
+
+ UnicodeString jdtShort = "JDT";
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormatSymbols *symbols = new DateFormatSymbols(Locale::getJapan(), status);
+ if(U_FAILURE(status)) {
+ errln("Failure creating DateFormatSymbols, %s", u_errorName(status));
+ delete symbols;
+ return;
+ }
+ failure(status, "new DateFormatSymbols");
+ int32_t eraCount = 0;
+ const UnicodeString *eras = symbols->getEras(eraCount);
+
+ logln(UnicodeString("BC = ") + eras[0]);
+ if (eras[0] != bc) {
+ errln("*** Should have been " + bc);
+ //throw new Exception("Error in BC");
+ }
+
+ logln(UnicodeString("AD = ") + eras[1]);
+ if (eras[1] != ad) {
+ errln("*** Should have been " + ad);
+ //throw new Exception("Error in AD");
+ }
+
+ int32_t rowCount, colCount;
+ const UnicodeString **zones = symbols->getZoneStrings(rowCount, colCount);
+ //don't hard code the index .. compute it.
+ int32_t index = -1;
+ for (int32_t i = 0; i < rowCount; ++i) {
+ if (tzID == (zones[i][0])) {
+ index = i;
+ break;
+ }
+ }
+ logln(UnicodeString("Long zone name = ") + zones[index][1]);
+ if (zones[index][1] != jstLong) {
+ errln("*** Should have been " + prettify(jstLong)+ " but it is: " + prettify(zones[index][1]));
+ //throw new Exception("Error in long TZ name");
+ }
+ logln(UnicodeString("Short zone name = ") + zones[index][2]);
+ if (zones[index][2] != jstShort) {
+ errln("*** Should have been " + prettify(jstShort) + " but it is: " + prettify(zones[index][2]));
+ //throw new Exception("Error in short TZ name");
+ }
+ logln(UnicodeString("Long zone name = ") + zones[index][3]);
+ if (zones[index][3] != jdtLong) {
+ errln("*** Should have been " + prettify(jstLong) + " but it is: " + prettify(zones[index][3]));
+ //throw new Exception("Error in long TZ name");
+ }
+ logln(UnicodeString("SHORT zone name = ") + zones[index][4]);
+ if (zones[index][4] != jdtShort) {
+ errln("*** Should have been " + prettify(jstShort)+ " but it is: " + prettify(zones[index][4]));
+ //throw new Exception("Error in short TZ name");
+ }
+ delete symbols;
+
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/miscdtfm.h b/Build/source/libs/icu/icu-xetex/test/intltest/miscdtfm.h
new file mode 100644
index 00000000000..992e89a71aa
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/miscdtfm.h
@@ -0,0 +1,37 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _DATEFORMATMISCTEST_
+#define _DATEFORMATMISCTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+/**
+ * Performs miscellaneous tests for DateFormat, SimpleDateFormat, DateFormatSymbols
+ **/
+class DateFormatMiscTests : public IntlTest {
+
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+
+ void test4097450(void);
+ void test4099975(void);
+ void test4117335(void);
+
+protected:
+ UBool failure(UErrorCode status, const char* msg);
+
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _DATEFORMATMISCTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/mnkytst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/mnkytst.cpp
new file mode 100644
index 00000000000..ce26669a91a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/mnkytst.cpp
@@ -0,0 +1,269 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/unistr.h"
+#include "unicode/sortkey.h"
+#include "mnkytst.h"
+#include "sfwdchit.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#ifndef MIN
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#endif
+
+#ifndef MAX
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#endif
+
+CollationMonkeyTest::CollationMonkeyTest()
+: source("-abcdefghijklmnopqrstuvwxyz#&^$@", ""),
+ myCollator(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ myCollator = Collator::createInstance("en_US", status);
+}
+
+CollationMonkeyTest::~CollationMonkeyTest()
+{
+ delete myCollator;
+}
+
+
+void
+CollationMonkeyTest::report(UnicodeString& s, UnicodeString& t, int32_t result, int32_t revResult)
+{
+ if (revResult != -result)
+ {
+ UnicodeString msg;
+
+ msg += s;
+ msg += " and ";
+ msg += t;
+ msg += " round trip comparison failed";
+ msg += (UnicodeString) " (result " + result + ", reverse Result " + revResult + ")";
+
+ errln(msg);
+ }
+}
+
+int32_t
+CollationMonkeyTest::checkValue(int32_t value)
+{
+ if (value < 0)
+ {
+ return -value;
+ }
+
+ return value;
+}
+
+void CollationMonkeyTest::TestCollationKey(/* char* par */)
+{
+ if(source.length() == 0) {
+ errln(UNICODE_STRING("CollationMonkeyTest::TestCollationKey(): source is empty - ICU_DATA not set or data missing?", 92));
+ return;
+ }
+
+ srand( (unsigned)time( NULL ) );
+ int32_t s = checkValue(rand() % source.length());
+ int32_t t = checkValue(rand() % source.length());
+ int32_t slen = checkValue((rand() - source.length()) % source.length());
+ int32_t tlen = checkValue((rand() - source.length()) % source.length());
+ UnicodeString subs, subt;
+
+ source.extract(MIN(s, slen), MAX(s, slen), subs);
+ source.extract(MIN(t, tlen), MAX(t, tlen), subt);
+
+ CollationKey collationKey1, collationKey2;
+ UErrorCode status1 = U_ZERO_ERROR, status2= U_ZERO_ERROR;
+
+ myCollator->setStrength(Collator::TERTIARY);
+ myCollator->getCollationKey(subs, collationKey1, status1);
+ myCollator->getCollationKey(subt, collationKey2, status2);
+ int32_t result = collationKey1.compareTo(collationKey2); // Tertiary
+ int32_t revResult = collationKey2.compareTo(collationKey1); // Tertiary
+ report( subs, subt, result, revResult);
+
+ myCollator->setStrength(Collator::SECONDARY);
+ myCollator->getCollationKey(subs, collationKey1, status1);
+ myCollator->getCollationKey(subt, collationKey2, status2);
+ result = collationKey1.compareTo(collationKey2); // Secondary
+ revResult = collationKey2.compareTo(collationKey1); // Secondary
+ report( subs, subt, result, revResult);
+
+ myCollator->setStrength(Collator::PRIMARY);
+ myCollator->getCollationKey(subs, collationKey1, status1);
+ myCollator->getCollationKey(subt, collationKey2, status2);
+ result = collationKey1.compareTo(collationKey2); // Primary
+ revResult = collationKey2.compareTo(collationKey1); // Primary
+ report(subs, subt, result, revResult);
+
+ UnicodeString msg;
+ UnicodeString addOne(subs);
+ addOne += (UChar32)0xE000;
+
+ myCollator->getCollationKey(subs, collationKey1, status1);
+ myCollator->getCollationKey(addOne, collationKey2, status2);
+ result = collationKey1.compareTo(collationKey2);
+ if (result != -1)
+ {
+ msg += "CollationKey(";
+ msg += subs;
+ msg += ") .LT. CollationKey(";
+ msg += addOne;
+ msg += ") Failed.";
+ errln(msg);
+ }
+
+ msg.remove();
+ result = collationKey2.compareTo(collationKey1);
+ if (result != 1)
+ {
+ msg += "CollationKey(";
+ msg += addOne;
+ msg += ") .GT. CollationKey(";
+ msg += subs;
+ msg += ") Failed.";
+ errln(msg);
+ }
+}
+
+void
+CollationMonkeyTest::TestCompare(/* char* par */)
+{
+ if(source.length() == 0) {
+ errln(UNICODE_STRING("CollationMonkeyTest::TestCompare(): source is empty - ICU_DATA not set or data missing?", 87));
+ return;
+ }
+
+ /* Seed the random-number generator with current time so that
+ * the numbers will be different every time we run.
+ */
+ srand( (unsigned)time( NULL ) );
+ int32_t s = checkValue(rand() % source.length());
+ int32_t t = checkValue(rand() % source.length());
+ int32_t slen = checkValue((rand() - source.length()) % source.length());
+ int32_t tlen = checkValue((rand() - source.length()) % source.length());
+ UnicodeString subs, subt;
+
+ source.extract(MIN(s, slen), MAX(s, slen), subs);
+ source.extract(MIN(t, tlen), MAX(t, tlen), subt);
+
+ myCollator->setStrength(Collator::TERTIARY);
+ int32_t result = myCollator->compare(subs, subt); // Tertiary
+ int32_t revResult = myCollator->compare(subt, subs); // Tertiary
+ report(subs, subt, result, revResult);
+
+ myCollator->setStrength(Collator::SECONDARY);
+ result = myCollator->compare(subs, subt); // Secondary
+ revResult = myCollator->compare(subt, subs); // Secondary
+ report(subs, subt, result, revResult);
+
+ myCollator->setStrength(Collator::PRIMARY);
+ result = myCollator->compare(subs, subt); // Primary
+ revResult = myCollator->compare(subt, subs); // Primary
+ report(subs, subt, result, revResult);
+
+ UnicodeString msg;
+ UnicodeString addOne(subs);
+ addOne += (UChar32)0xE000;
+
+ result = myCollator->compare(subs, addOne);
+ if (result != -1)
+ {
+ msg += "Test : ";
+ msg += subs;
+ msg += " .LT. ";
+ msg += addOne;
+ msg += " Failed.";
+ errln(msg);
+ }
+
+ msg.remove();
+ result = myCollator->compare(addOne, subs);
+ if (result != 1)
+ {
+ msg += "Test : ";
+ msg += addOne;
+ msg += " .GT. ";
+ msg += subs;
+ msg += " Failed.";
+ errln(msg);
+ }
+}
+void CollationMonkeyTest::TestRules(/* char* par */){
+ UChar testSourceCases[][10] = {
+ {0x0061, 0x0062, 0x007a, 0},
+ {0x0061, 0x0062, 0x007a, 0},
+ };
+
+ UChar testTargetCases[][10] = {
+ {0x0061, 0x0062, 0x00e4, 0},
+ {0x0061, 0x0062, 0x0061, 0x0308, 0},
+ };
+
+ int i=0;
+ logln("Demo Test 1 : Create a new table collation with rules \"& z < 0x00e4\"");
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *col = Collator::createInstance("en_US", status);
+ const UnicodeString baseRules = ((RuleBasedCollator*)col)->getRules();
+ UnicodeString newRules(" & z < ");
+ newRules.append((UChar)0x00e4);
+ newRules.insert(0, baseRules);
+ RuleBasedCollator *myCollation = new RuleBasedCollator(newRules, status);
+ if (U_FAILURE(status)) {
+ errln( "Demo Test 1 Table Collation object creation failed.");
+ return;
+ }
+ for(i=0; i<2; i++){
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], Collator::LESS);
+ }
+ delete myCollation;
+
+ logln("Demo Test 2 : Create a new table collation with rules \"& z < a 0x0308\"");
+ newRules.remove();
+ newRules.append(" & z < a");
+ newRules.append((UChar)0x0308);
+ newRules.insert(0, baseRules);
+ myCollation = new RuleBasedCollator(newRules, status);
+ if (U_FAILURE(status)) {
+ errln( "Demo Test 1 Table Collation object creation failed.");
+ return;
+ }
+ for(i=0; i<2; i++){
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], Collator::LESS);
+ }
+ delete myCollation;
+ delete col;
+
+}
+
+void CollationMonkeyTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CollationMonkeyTest: ");
+ if(myCollator) {
+ switch (index) {
+ case 0: name = "TestCompare"; if (exec) TestCompare(/* par */); break;
+ case 1: name = "TestCollationKey"; if (exec) TestCollationKey(/* par */); break;
+ case 2: name = "TestRules"; if (exec) TestRules(/* par */); break;
+ default: name = ""; break;
+ }
+ } else {
+ errln("Class collator not instantiated");
+ name = "";
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/mnkytst.h b/Build/source/libs/icu/icu-xetex/test/intltest/mnkytst.h
new file mode 100644
index 00000000000..e13c497cb20
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/mnkytst.h
@@ -0,0 +1,54 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * CollationMonkeyTest is a third level test class. This tests the random
+ * substrings of the default test strings to verify if the compare and
+ * sort key algorithm works correctly. For example, any string is always
+ * less than the string itself appended with any character.
+ */
+
+#ifndef _MNKYTST
+#define _MNKYTST
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class CollationMonkeyTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationMonkeyTest();
+ virtual ~CollationMonkeyTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // utility function used in tests, returns absolute value
+ int32_t checkValue(int32_t value);
+
+ // perform monkey tests using Collator::compare
+ void TestCompare(/* char* par */);
+
+ // perform monkey tests using CollationKey::compareTo
+ void TestCollationKey(/* char* par */);
+
+ void TestRules(/* char* par */);
+
+private:
+ void report(UnicodeString& s, UnicodeString& t, int32_t result, int32_t revResult);
+
+ const UnicodeString source;
+
+ Collator *myCollator;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/msfmrgts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/msfmrgts.cpp
new file mode 100644
index 00000000000..97465a09be7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/msfmrgts.cpp
@@ -0,0 +1,966 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "msfmrgts.h"
+
+#include "unicode/format.h"
+#include "unicode/decimfmt.h"
+#include "unicode/locid.h"
+#include "unicode/msgfmt.h"
+#include "unicode/numfmt.h"
+#include "unicode/choicfmt.h"
+#include "unicode/gregocal.h"
+#include "putilimp.h"
+
+// *****************************************************************************
+// class MessageFormatRegressionTest
+// *****************************************************************************
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
+
+void
+MessageFormatRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite MessageFormatRegressionTest");
+ switch (index) {
+ CASE(0,Test4074764)
+ CASE(1,Test4058973)
+ CASE(2,Test4031438)
+ CASE(3,Test4052223)
+ CASE(4,Test4104976)
+ CASE(5,Test4106659)
+ CASE(6,Test4106660)
+ CASE(7,Test4111739)
+ CASE(8,Test4114743)
+ CASE(9,Test4116444)
+ CASE(10,Test4114739)
+ CASE(11,Test4113018)
+ CASE(12,Test4106661)
+ CASE(13,Test4094906)
+ CASE(14,Test4118592)
+ CASE(15,Test4118594)
+ CASE(16,Test4105380)
+ CASE(17,Test4120552)
+ CASE(18,Test4142938)
+ CASE(19,TestChoicePatternQuote)
+ CASE(20,Test4112104)
+
+ default: name = ""; break;
+ }
+}
+
+UBool
+MessageFormatRegressionTest::failure(UErrorCode status, const char* msg)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* @bug 4074764
+ * Null exception when formatting pattern with MessageFormat
+ * with no parameters.
+ */
+void MessageFormatRegressionTest::Test4074764() {
+ UnicodeString pattern [] = {
+ "Message without param",
+ "Message with param:{0}",
+ "Longer Message with param {0}"
+ };
+ //difference between the two param strings are that
+ //in the first one, the param position is within the
+ //length of the string without param while it is not so
+ //in the other case.
+
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *messageFormatter = new MessageFormat("", status);
+
+ failure(status, "couldn't create MessageFormat");
+
+ //try {
+ //Apply pattern with param and print the result
+ messageFormatter->applyPattern(pattern[1], status);
+ failure(status, "messageFormat->applyPattern");
+ //Object[] params = {new UnicodeString("BUG"), new Date()};
+ Formattable params [] = {
+ Formattable(UnicodeString("BUG")),
+ Formattable(0, Formattable::kIsDate)
+ };
+ UnicodeString tempBuffer;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ tempBuffer = messageFormatter->format(params, 2, tempBuffer, pos, status);
+ if( tempBuffer != "Message with param:BUG" || failure(status, "messageFormat->format"))
+ errln("MessageFormat with one param test failed.");
+ logln("Formatted with one extra param : " + tempBuffer);
+
+ //Apply pattern without param and print the result
+ messageFormatter->applyPattern(pattern[0], status);
+ failure(status, "messageFormatter->applyPattern");
+
+ // {sfb} how much does this apply in C++?
+ // do we want to verify that the Formattable* array is not NULL,
+ // or is that the user's responsibility?
+ // additionally, what should be the item count?
+ // for bug testing purposes, assume that something was set to
+ // NULL by mistake, and that the length should be non-zero
+
+ //tempBuffer = messageFormatter->format(NULL, 1, tempBuffer, FieldPosition(FieldPosition::DONT_CARE), status);
+ tempBuffer.remove();
+ tempBuffer = messageFormatter->format(NULL, 0, tempBuffer, pos, status);
+
+ if( tempBuffer != "Message without param" || failure(status, "messageFormat->format"))
+ errln("MessageFormat with no param test failed.");
+ logln("Formatted with no params : " + tempBuffer);
+
+ tempBuffer.remove();
+ tempBuffer = messageFormatter->format(params, 2, tempBuffer, pos, status);
+ if (tempBuffer != "Message without param" || failure(status, "messageFormat->format"))
+ errln("Formatted with arguments > subsitution failed. result = " + tempBuffer);
+ logln("Formatted with extra params : " + tempBuffer);
+ //This statement gives an exception while formatting...
+ //If we use pattern[1] for the message with param,
+ //we get an NullPointerException in MessageFormat.java(617)
+ //If we use pattern[2] for the message with param,
+ //we get an StringArrayIndexOutOfBoundsException in MessageFormat.java(614)
+ //Both are due to maxOffset not being reset to -1
+ //in applyPattern() when the pattern does not
+ //contain any param.
+ /*} catch (Exception foo) {
+ errln("Exception when formatting with no params.");
+ }*/
+
+ delete messageFormatter;
+}
+
+/* @bug 4058973
+ * MessageFormat.toPattern has weird rounding behavior.
+ */
+void MessageFormatRegressionTest::Test4058973()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *fmt = new MessageFormat("{0,choice,0#no files|1#one file|1< {0,number,integer} files}", status);
+ failure(status, "new MessageFormat");
+
+ UnicodeString pat;
+ pat = fmt->toPattern(pat);
+ UnicodeString exp("{0,choice,0.0#no files|1.0#one file|1.0< {0,number,integer} files}");
+ if (pat != exp) {
+ errln("MessageFormat.toPattern failed");
+ errln("Exp: " + exp);
+ errln("Got: " + pat);
+ }
+
+ delete fmt;
+}
+/* @bug 4031438
+ * More robust message formats.
+ */
+void MessageFormatRegressionTest::Test4031438()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ UnicodeString pattern1("Impossible {1} has occurred -- status code is {0} and message is {2}.");
+ UnicodeString pattern2("Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'.");
+
+ MessageFormat *messageFormatter = new MessageFormat("", status);
+ failure(status, "new MessageFormat");
+
+ //try {
+ logln("Apply with pattern : " + pattern1);
+ messageFormatter->applyPattern(pattern1, status);
+ failure(status, "messageFormat->applyPattern");
+ //Object[] params = {new Integer(7)};
+ Formattable params []= {
+ Formattable((int32_t)7)
+ };
+ UnicodeString tempBuffer;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status);
+ if(tempBuffer != "Impossible {1} has occurred -- status code is 7 and message is {2}." || failure(status, "MessageFormat::format"))
+ errln("Tests arguments < substitution failed");
+ logln("Formatted with 7 : " + tempBuffer);
+ ParsePosition pp(0);
+ int32_t count = 0;
+ Formattable *objs = messageFormatter->parse(tempBuffer, pp, count);
+ //if(objs[7/*params.length*/] != NULL)
+ // errln("Parse failed with more than expected arguments");
+
+ NumberFormat *fmt = 0;
+ UnicodeString temp, temp1;
+
+ for (int i = 0; i < count; i++) {
+
+ // convert to string if not already
+ Formattable obj = objs[i];
+ temp.remove();
+ if(obj.getType() == Formattable::kString)
+ temp = obj.getString(temp);
+ else {
+ fmt = NumberFormat::createInstance(status);
+ switch (obj.getType()) {
+ case Formattable::kLong: fmt->format(obj.getLong(), temp); break;
+ case Formattable::kInt64: fmt->format(obj.getInt64(), temp); break;
+ case Formattable::kDouble: fmt->format(obj.getDouble(), temp); break;
+ default: break;
+ }
+ }
+
+ // convert to string if not already
+ Formattable obj1 = params[i];
+ temp1.remove();
+ if(obj1.getType() == Formattable::kString)
+ temp1 = obj1.getString(temp1);
+ else {
+ fmt = NumberFormat::createInstance(status);
+ switch (obj1.getType()) {
+ case Formattable::kLong: fmt->format(obj1.getLong(), temp1); break;
+ case Formattable::kInt64: fmt->format(obj1.getInt64(), temp1); break;
+ case Formattable::kDouble: fmt->format(obj1.getDouble(), temp1); break;
+ default: break;
+ }
+ }
+
+ //if (objs[i] != NULL && objs[i].getString(temp1) != params[i].getString(temp2)) {
+ if (temp != temp1) {
+ errln("Parse failed on object " + objs[i].getString(temp1) + " at index : " + i);
+ }
+ }
+
+ delete fmt;
+ delete [] objs;
+
+ // {sfb} does this apply? no way to really pass a null Formattable,
+ // only a null array
+
+ /*tempBuffer = messageFormatter->format(null, tempBuffer, FieldPosition(FieldPosition::DONT_CARE), status);
+ if (tempBuffer != "Impossible {1} has occurred -- status code is {0} and message is {2}." || failure(status, "messageFormat->format"))
+ errln("Tests with no arguments failed");
+ logln("Formatted with null : " + tempBuffer);*/
+ logln("Apply with pattern : " + pattern2);
+ messageFormatter->applyPattern(pattern2, status);
+ failure(status, "messageFormatter->applyPattern");
+ tempBuffer.remove();
+ tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status);
+ if (tempBuffer != "Double ' Quotes 7 test and quoted {1} test plus other {2} stuff.")
+ errln("quote format test (w/ params) failed.");
+ logln("Formatted with params : " + tempBuffer);
+
+ /*tempBuffer = messageFormatter->format(null);
+ if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus other {2} stuff."))
+ errln("quote format test (w/ null) failed.");
+ logln("Formatted with null : " + tempBuffer);
+ logln("toPattern : " + messageFormatter.toPattern());*/
+ /*} catch (Exception foo) {
+ errln("Exception when formatting in bug 4031438. "+foo.getMessage());
+ }*/
+ delete messageFormatter;
+}
+
+void MessageFormatRegressionTest::Test4052223()
+{
+
+ ParsePosition pos(0);
+ if (pos.getErrorIndex() != -1) {
+ errln("ParsePosition.getErrorIndex initialization failed.");
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *fmt = new MessageFormat("There are {0} apples growing on the {1} tree.", status);
+ failure(status, "new MessageFormat");
+ UnicodeString str("There is one apple growing on the peach tree.");
+
+ int32_t count = 0;
+ fmt->parse(str, pos, count);
+
+ logln(UnicodeString("unparsable string , should fail at ") + pos.getErrorIndex());
+ if (pos.getErrorIndex() == -1)
+ errln("Bug 4052223 failed : parsing string " + str);
+ pos.setErrorIndex(4);
+ if (pos.getErrorIndex() != 4)
+ errln(UnicodeString("setErrorIndex failed, got ") + pos.getErrorIndex() + " instead of 4");
+
+ ChoiceFormat *f = new ChoiceFormat(
+ "-1#are negative|0#are no or fraction|1#is one|1.0<is 1+|2#are two|2<are more than 2.", status);
+ failure(status, "new ChoiceFormat");
+ pos.setIndex(0);
+ pos.setErrorIndex(-1);
+ Formattable obj;
+ f->parse("are negative", obj, pos);
+ if (pos.getErrorIndex() != -1 && obj.getDouble() == -1.0)
+ errln(UnicodeString("Parse with \"are negative\" failed, at ") + pos.getErrorIndex());
+ pos.setIndex(0);
+ pos.setErrorIndex(-1);
+ f->parse("are no or fraction ", obj, pos);
+ if (pos.getErrorIndex() != -1 && obj.getDouble() == 0.0)
+ errln(UnicodeString("Parse with \"are no or fraction\" failed, at ") + pos.getErrorIndex());
+ pos.setIndex(0);
+ pos.setErrorIndex(-1);
+ f->parse("go postal", obj, pos);
+ if (pos.getErrorIndex() == -1 && ! uprv_isNaN(obj.getDouble()))
+ errln(UnicodeString("Parse with \"go postal\" failed, at ") + pos.getErrorIndex());
+
+ delete fmt;
+ delete f;
+}
+/* @bug 4104976
+ * ChoiceFormat.equals(null) throws NullPointerException
+ */
+
+// {sfb} not really applicable in C++?? (kind of silly)
+
+void MessageFormatRegressionTest::Test4104976()
+{
+ double limits [] = {1, 20};
+ UnicodeString formats [] = {
+ UnicodeString("xyz"),
+ UnicodeString("abc")
+ };
+ int32_t formats_length = (int32_t)(sizeof(formats)/sizeof(formats[0]));
+ UErrorCode status = U_ZERO_ERROR;
+ ChoiceFormat *cf = new ChoiceFormat(limits, formats, formats_length);
+ failure(status, "new ChoiceFormat");
+ //try {
+ log("Compares to null is always false, returned : ");
+ logln(cf == NULL ? "TRUE" : "FALSE");
+ /*} catch (Exception foo) {
+ errln("ChoiceFormat.equals(null) throws exception.");
+ }*/
+
+ delete cf;
+}
+
+/* @bug 4106659
+ * ChoiceFormat.ctor(double[], String[]) doesn't check
+ * whether lengths of input arrays are equal.
+ */
+
+// {sfb} again, not really applicable in C++
+
+void MessageFormatRegressionTest::Test4106659()
+{
+ /*
+ double limits [] = {
+ 1, 2, 3
+ };
+ UnicodeString formats [] = {
+ "one", "two"
+ };
+ ChoiceFormat *cf = NULL;
+ //try {
+ // cf = new ChoiceFormat(limits, formats, 3);
+ //} catch (Exception foo) {
+ // logln("ChoiceFormat constructor should check for the array lengths");
+ // cf = null;
+ //}
+ //if (cf != null)
+ // errln(cf->format(5));
+ //
+ delete cf;
+ */
+}
+
+/* @bug 4106660
+ * ChoiceFormat.ctor(double[], String[]) allows unordered double array.
+ * This is not a bug, added javadoc to emphasize the use of limit
+ * array must be in ascending order.
+ */
+void MessageFormatRegressionTest::Test4106660()
+{
+ double limits [] = {3, 1, 2};
+ UnicodeString formats [] = {
+ UnicodeString("Three"),
+ UnicodeString("One"),
+ UnicodeString("Two")
+ };
+ ChoiceFormat *cf = new ChoiceFormat(limits, formats, 3);
+ double d = 5.0;
+ UnicodeString str;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ str = cf->format(d, str, pos);
+ if (str != "Two")
+ errln( (UnicodeString) "format(" + d + ") = " + str);
+
+ delete cf;
+}
+
+/* @bug 4111739
+ * MessageFormat is incorrectly serialized/deserialized.
+ */
+
+// {sfb} doesn't apply in C++
+
+void MessageFormatRegressionTest::Test4111739()
+{
+ /*MessageFormat format1 = null;
+ MessageFormat format2 = null;
+ ObjectOutputStream ostream = null;
+ ByteArrayOutputStream baos = null;
+ ObjectInputStream istream = null;
+
+ try {
+ baos = new ByteArrayOutputStream();
+ ostream = new ObjectOutputStream(baos);
+ } catch(IOException e) {
+ errln("Unexpected exception : " + e.getMessage());
+ return;
+ }
+
+ try {
+ format1 = new MessageFormat("pattern{0}");
+ ostream.writeObject(format1);
+ ostream.flush();
+
+ byte bytes[] = baos.toByteArray();
+
+ istream = new ObjectInputStream(new ByteArrayInputStream(bytes));
+ format2 = (MessageFormat)istream.readObject();
+ } catch(Exception e) {
+ errln("Unexpected exception : " + e.getMessage());
+ }
+
+ if (!format1.equals(format2)) {
+ errln("MessageFormats before and after serialization are not" +
+ " equal\nformat1 = " + format1 + "(" + format1.toPattern() + ")\nformat2 = " +
+ format2 + "(" + format2.toPattern() + ")");
+ } else {
+ logln("Serialization for MessageFormat is OK.");
+ }*/
+}
+/* @bug 4114743
+ * MessageFormat.applyPattern allows illegal patterns.
+ */
+void MessageFormatRegressionTest::Test4114743()
+{
+ UnicodeString originalPattern("initial pattern");
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *mf = new MessageFormat(originalPattern, status);
+ failure(status, "new MessageFormat");
+ //try {
+ UnicodeString illegalPattern("ab { '}' de");
+ mf->applyPattern(illegalPattern, status);
+ if( ! U_FAILURE(status))
+ errln("illegal pattern: \"" + illegalPattern + "\"");
+ /*} catch (IllegalArgumentException foo) {
+ if (!originalPattern.equals(mf.toPattern()))
+ errln("pattern after: \"" + mf.toPattern() + "\"");
+ }*/
+ delete mf;
+}
+
+/* @bug 4116444
+ * MessageFormat.parse has different behavior in case of null.
+ */
+void MessageFormatRegressionTest::Test4116444()
+{
+ UnicodeString patterns [] = {
+ (UnicodeString)"",
+ (UnicodeString)"one",
+ (UnicodeString) "{0,date,short}"
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *mf = new MessageFormat("", status);
+ failure(status, "new MessageFormat");
+
+ for (int i = 0; i < 3; i++) {
+ UnicodeString pattern = patterns[i];
+ mf->applyPattern(pattern, status);
+ failure(status, "mf->applyPattern");
+
+ //try {
+ int32_t count = 0;
+ ParsePosition pp(0);
+ Formattable *array = mf->parse(UnicodeString(""), pp, count);
+ logln("pattern: \"" + pattern + "\"");
+ log(" parsedObjects: ");
+ if (array != NULL) {
+ log("{");
+ for (int j = 0; j < count; j++) {
+ //if (array[j] != null)
+ UnicodeString dummy;
+ err("\"" + array[j].getString(dummy) + "\"");
+ //else
+ // log("null");
+ if (j < count- 1)
+ log(",");
+ }
+ log("}") ;
+ delete[] array;
+ } else {
+ log("null");
+ }
+ logln("");
+ /*} catch (Exception e) {
+ errln("pattern: \"" + pattern + "\"");
+ errln(" Exception: " + e.getMessage());
+ }*/
+ }
+
+ delete mf;
+}
+/* @bug 4114739 (FIX and add javadoc)
+ * MessageFormat.format has undocumented behavior about empty format objects.
+ */
+
+// {sfb} doesn't apply in C++?
+void MessageFormatRegressionTest::Test4114739()
+{
+
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *mf = new MessageFormat("<{0}>", status);
+ failure(status, "new MessageFormat");
+
+ Formattable *objs1 = NULL;
+ //Formattable objs2 [] = {};
+ //Formattable *objs3 [] = {NULL};
+ //try {
+ UnicodeString pat;
+ UnicodeString res;
+ logln("pattern: \"" + mf->toPattern(pat) + "\"");
+ log("format(null) : ");
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ logln("\"" + mf->format(objs1, 0, res, pos, status) + "\"");
+ failure(status, "mf->format");
+ /*log("format({}) : ");
+ logln("\"" + mf->format(objs2, 0, res, FieldPosition(FieldPosition::DONT_CARE), status) + "\"");
+ failure(status, "mf->format");
+ log("format({null}) :");
+ logln("\"" + mf->format(objs3, 0, res, FieldPosition(FieldPosition::DONT_CARE), status) + "\"");
+ failure(status, "mf->format");*/
+ /*} catch (Exception e) {
+ errln("Exception thrown for null argument tests.");
+ }*/
+
+ delete mf;
+}
+
+/* @bug 4113018
+ * MessageFormat.applyPattern works wrong with illegal patterns.
+ */
+void MessageFormatRegressionTest::Test4113018()
+{
+ UnicodeString originalPattern("initial pattern");
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *mf = new MessageFormat(originalPattern, status);
+ failure(status, "new messageFormat");
+ UnicodeString illegalPattern("format: {0, xxxYYY}");
+ UnicodeString pat;
+ logln("pattern before: \"" + mf->toPattern(pat) + "\"");
+ logln("illegal pattern: \"" + illegalPattern + "\"");
+ //try {
+ mf->applyPattern(illegalPattern, status);
+ if( ! U_FAILURE(status))
+ errln("Should have thrown IllegalArgumentException for pattern : " + illegalPattern);
+ /*} catch (IllegalArgumentException e) {
+ if (!originalPattern.equals(mf.toPattern()))
+ errln("pattern after: \"" + mf.toPattern() + "\"");
+ }*/
+ delete mf;
+}
+
+/* @bug 4106661
+ * ChoiceFormat is silent about the pattern usage in javadoc.
+ */
+void MessageFormatRegressionTest::Test4106661()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ ChoiceFormat *fmt = new ChoiceFormat(
+ "-1#are negative| 0#are no or fraction | 1#is one |1.0<is 1+ |2#are two |2<are more than 2.", status);
+ failure(status, "new ChoiceFormat");
+ UnicodeString pat;
+ logln("Formatter Pattern : " + fmt->toPattern(pat));
+
+ FieldPosition bogus(FieldPosition::DONT_CARE);
+ UnicodeString str;
+
+ // Will this work for -inf?
+ logln("Format with -INF : " + fmt->format(Formattable(-uprv_getInfinity()), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 0 : " + fmt->format(Formattable((int32_t)0), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 0.9 : " + fmt->format(Formattable(0.9), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 1.0 : " + fmt->format(Formattable(1.0), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 1.5 : " + fmt->format(Formattable(1.5), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 2 : " + fmt->format(Formattable((int32_t)2), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 2.1 : " + fmt->format(Formattable(2.1), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with NaN : " + fmt->format(Formattable(uprv_getNaN()), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with +INF : " + fmt->format(Formattable(uprv_getInfinity()), str, bogus, status));
+ failure(status, "fmt->format");
+
+ delete fmt;
+}
+
+/* @bug 4094906
+ * ChoiceFormat should accept \u221E as eq. to INF.
+ */
+void MessageFormatRegressionTest::Test4094906()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern("-");
+ pattern += (UChar) 0x221E;
+ pattern += "<are negative|0.0<are no or fraction|1.0#is one|1.0<is 1+|";
+ pattern += (UChar) 0x221E;
+ pattern += "<are many.";
+
+ ChoiceFormat *fmt = new ChoiceFormat(pattern, status);
+ failure(status, "new ChoiceFormat");
+ UnicodeString pat;
+ if (fmt->toPattern(pat) != pattern) {
+ errln( (UnicodeString) "Formatter Pattern : " + pat);
+ errln( (UnicodeString) "Expected Pattern : " + pattern);
+ }
+ FieldPosition bogus(FieldPosition::DONT_CARE);
+ UnicodeString str;
+
+ // Will this work for -inf?
+ logln("Format with -INF : " + fmt->format(Formattable(-uprv_getInfinity()), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 0 : " + fmt->format(Formattable((int32_t)0), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 0.9 : " + fmt->format(Formattable(0.9), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 1.0 : " + fmt->format(Formattable(1.0), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 1.5 : " + fmt->format(Formattable(1.5), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 2 : " + fmt->format(Formattable((int32_t)2), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with 2.1 : " + fmt->format(Formattable(2.1), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with NaN : " + fmt->format(Formattable(uprv_getNaN()), str, bogus, status));
+ failure(status, "fmt->format");
+ str.remove();
+ logln("Format with +INF : " + fmt->format(Formattable(uprv_getInfinity()), str, bogus, status));
+ failure(status, "fmt->format");
+
+ delete fmt;
+}
+
+/* @bug 4118592
+ * MessageFormat.parse fails with ChoiceFormat.
+ */
+void MessageFormatRegressionTest::Test4118592()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *mf = new MessageFormat("", status);
+ failure(status, "new messageFormat");
+ UnicodeString pattern("{0,choice,1#YES|2#NO}");
+ UnicodeString prefix("");
+ Formattable *objs = 0;
+
+ for (int i = 0; i < 5; i++) {
+ UnicodeString formatted;
+ formatted = prefix + "YES";
+ mf->applyPattern(prefix + pattern, status);
+ failure(status, "mf->applyPattern");
+ prefix += "x";
+ //Object[] objs = mf.parse(formatted, new ParsePosition(0));
+ int32_t count = 0;
+ ParsePosition pp(0);
+ objs = mf->parse(formatted, pp, count);
+ UnicodeString pat;
+ logln(UnicodeString("") + i + ". pattern :\"" + mf->toPattern(pat) + "\"");
+ log(" \"" + formatted + "\" parsed as ");
+ if (objs == NULL)
+ logln(" null");
+ else {
+ UnicodeString temp;
+ if(objs[0].getType() == Formattable::kString)
+ logln((UnicodeString)" " + objs[0].getString(temp));
+ else
+ logln((UnicodeString)" " + (objs[0].getType() == Formattable::kLong ? objs[0].getLong() : objs[0].getDouble()));
+ delete[] objs;
+
+ }
+ }
+
+ delete mf;
+}
+/* @bug 4118594
+ * MessageFormat.parse fails for some patterns.
+ */
+void MessageFormatRegressionTest::Test4118594()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *mf = new MessageFormat("{0}, {0}, {0}", status);
+ failure(status, "new MessageFormat");
+ UnicodeString forParsing("x, y, z");
+ //Object[] objs = mf.parse(forParsing, new ParsePosition(0));
+ int32_t count = 0;
+ ParsePosition pp(0);
+ Formattable *objs = mf->parse(forParsing, pp, count);
+ UnicodeString pat;
+ logln("pattern: \"" + mf->toPattern(pat) + "\"");
+ logln("text for parsing: \"" + forParsing + "\"");
+ UnicodeString str;
+ if (objs[0].getString(str) != "z")
+ errln("argument0: \"" + objs[0].getString(str) + "\"");
+ mf->applyPattern("{0,number,#.##}, {0,number,#.#}", status);
+ failure(status, "mf->applyPattern");
+ //Object[] oldobjs = {new Double(3.1415)};
+ Formattable oldobjs [] = {Formattable(3.1415)};
+ UnicodeString result;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ result = mf->format( oldobjs, 1, result, pos, status );
+ failure(status, "mf->format");
+ pat.remove();
+ logln("pattern: \"" + mf->toPattern(pat) + "\"");
+ logln("text for parsing: \"" + result + "\"");
+ // result now equals "3.14, 3.1"
+ if (result != "3.14, 3.1")
+ errln("result = " + result);
+ //Object[] newobjs = mf.parse(result, new ParsePosition(0));
+ int32_t count1 = 0;
+ pp.setIndex(0);
+ Formattable *newobjs = mf->parse(result, pp, count1);
+ // newobjs now equals {new Double(3.1)}
+ if (newobjs == NULL) {
+ dataerrln("Error calling MessageFormat::parse");
+ } else {
+ if (newobjs[0].getDouble() != 3.1)
+ errln( UnicodeString("newobjs[0] = ") + newobjs[0].getDouble());
+ }
+
+ delete [] objs;
+ delete [] newobjs;
+ delete mf;
+}
+/* @bug 4105380
+ * When using ChoiceFormat, MessageFormat is not good for I18n.
+ */
+void MessageFormatRegressionTest::Test4105380()
+{
+ UnicodeString patternText1("The disk \"{1}\" contains {0}.");
+ UnicodeString patternText2("There are {0} on the disk \"{1}\"");
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *form1 = new MessageFormat(patternText1, status);
+ failure(status, "new MessageFormat");
+ MessageFormat *form2 = new MessageFormat(patternText2, status);
+ failure(status, "new MessageFormat");
+ double filelimits [] = {0,1,2};
+ UnicodeString filepart [] = {
+ (UnicodeString)"no files",
+ (UnicodeString)"one file",
+ (UnicodeString)"{0,number} files"
+ };
+ ChoiceFormat *fileform = new ChoiceFormat(filelimits, filepart, 3);
+ form1->setFormat(1, *fileform);
+ form2->setFormat(0, *fileform);
+ //Object[] testArgs = {new Long(12373), "MyDisk"};
+ Formattable testArgs [] = {
+ Formattable((int32_t)12373),
+ Formattable((UnicodeString)"MyDisk")
+ };
+
+ FieldPosition bogus(FieldPosition::DONT_CARE);
+
+ UnicodeString result;
+ logln(form1->format(testArgs, 2, result, bogus, status));
+ failure(status, "form1->format");
+ result.remove();
+ logln(form2->format(testArgs, 2, result, bogus, status));
+ failure(status, "form1->format");
+
+ delete form1;
+ delete form2;
+ delete fileform;
+}
+/* @bug 4120552
+ * MessageFormat.parse incorrectly sets errorIndex.
+ */
+void MessageFormatRegressionTest::Test4120552()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *mf = new MessageFormat("pattern", status);
+ failure(status, "new MessageFormat");
+ UnicodeString texts[] = {
+ (UnicodeString)"pattern",
+ (UnicodeString)"pat",
+ (UnicodeString)"1234"
+ };
+ UnicodeString pat;
+ logln("pattern: \"" + mf->toPattern(pat) + "\"");
+ for (int i = 0; i < 3; i++) {
+ ParsePosition pp(0);
+ //Object[] objs = mf.parse(texts[i], pp);
+ int32_t count = 0;
+ Formattable *objs = mf->parse(texts[i], pp, count);
+ log(" text for parsing: \"" + texts[i] + "\"");
+ if (objs == NULL) {
+ logln(" (incorrectly formatted string)");
+ if (pp.getErrorIndex() == -1)
+ errln(UnicodeString("Incorrect error index: ") + pp.getErrorIndex());
+ } else {
+ logln(" (correctly formatted string)");
+ delete[] objs;
+ }
+ }
+ delete mf;
+}
+
+/**
+ * @bug 4142938
+ * MessageFormat handles single quotes in pattern wrong.
+ * This is actually a problem in ChoiceFormat; it doesn't
+ * understand single quotes.
+ */
+void MessageFormatRegressionTest::Test4142938()
+{
+ UnicodeString pat = CharsToUnicodeString("''Vous'' {0,choice,0#n''|1#}avez s\\u00E9lectionn\\u00E9 "
+ "{0,choice,0#aucun|1#{0}} client{0,choice,0#s|1#|2#s} "
+ "personnel{0,choice,0#s|1#|2#s}.");
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *mf = new MessageFormat(pat, status);
+ failure(status, "new MessageFormat");
+
+ UnicodeString PREFIX [] = {
+ CharsToUnicodeString("'Vous' n'avez s\\u00E9lectionn\\u00E9 aucun clients personnels."),
+ CharsToUnicodeString("'Vous' avez s\\u00E9lectionn\\u00E9 "),
+ CharsToUnicodeString("'Vous' avez s\\u00E9lectionn\\u00E9 ")
+ };
+ UnicodeString SUFFIX [] = {
+ UnicodeString(),
+ UNICODE_STRING(" client personnel.", 18),
+ UNICODE_STRING(" clients personnels.", 20)
+ };
+
+ for (int i=0; i<3; i++) {
+ UnicodeString out;
+ //out = mf->format(new Object[]{new Integer(i)});
+ Formattable objs [] = {
+ Formattable((int32_t)i)
+ };
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ out = mf->format(objs, 1, out, pos, status);
+ failure(status, "mf->format");
+ if (SUFFIX[i] == "") {
+ if (out != PREFIX[i])
+ errln((UnicodeString)"" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"");
+ }
+ else {
+ if (!out.startsWith(PREFIX[i]) ||
+ !out.endsWith(SUFFIX[i]))
+ errln((UnicodeString)"" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"...\"" +
+ SUFFIX[i] + "\"");
+ }
+ }
+
+ delete mf;
+}
+
+/**
+ * @bug 4142938
+ * Test the applyPattern and toPattern handling of single quotes
+ * by ChoiceFormat. (This is in here because this was a bug reported
+ * against MessageFormat.) The single quote is used to quote the
+ * pattern characters '|', '#', '<', and '\u2264'. Two quotes in a row
+ * is a quote literal.
+ */
+void MessageFormatRegressionTest::TestChoicePatternQuote()
+{
+ UnicodeString DATA [] = {
+ // Pattern 0 value 1 value
+ // {sfb} hacked - changed \u2264 to = (copied from Character Map)
+ (UnicodeString)"0#can''t|1#can", (UnicodeString)"can't", (UnicodeString)"can",
+ (UnicodeString)"0#'pound(#)=''#'''|1#xyz", (UnicodeString)"pound(#)='#'", (UnicodeString)"xyz",
+ (UnicodeString)"0#'1<2 | 1=1'|1#''", (UnicodeString)"1<2 | 1=1", (UnicodeString)"'",
+ };
+ for (int i=0; i<9; i+=3) {
+ //try {
+ UErrorCode status = U_ZERO_ERROR;
+ ChoiceFormat *cf = new ChoiceFormat(DATA[i], status);
+ failure(status, "new ChoiceFormat");
+ for (int j=0; j<=1; ++j) {
+ UnicodeString out;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ out = cf->format((double)j, out, pos);
+ if (out != DATA[i+1+j])
+ errln("Fail: Pattern \"" + DATA[i] + "\" x "+j+" -> " +
+ out + "; want \"" + DATA[i+1+j] + '"');
+ }
+ UnicodeString pat;
+ pat = cf->toPattern(pat);
+ UnicodeString pat2;
+ ChoiceFormat *cf2 = new ChoiceFormat(pat, status);
+ pat2 = cf2->toPattern(pat2);
+ if (pat != pat2)
+ errln("Fail: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');
+ else
+ logln("Ok: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');
+ /*}
+ catch (IllegalArgumentException e) {
+ errln("Fail: Pattern \"" + DATA[i] + "\" -> " + e);
+ }*/
+
+ delete cf;
+ delete cf2;
+ }
+}
+
+/**
+ * @bug 4112104
+ * MessageFormat.equals(null) throws a NullPointerException. The JLS states
+ * that it should return false.
+ */
+void MessageFormatRegressionTest::Test4112104()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ MessageFormat *format = new MessageFormat("", status);
+ failure(status, "new MessageFormat");
+ //try {
+ // This should NOT throw an exception
+ if (format == NULL) {
+ // It also should return false
+ errln("MessageFormat.equals(null) returns false");
+ }
+ /*}
+ catch (NullPointerException e) {
+ errln("MessageFormat.equals(null) throws " + e);
+ }*/
+ delete format;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/msfmrgts.h b/Build/source/libs/icu/icu-xetex/test/intltest/msfmrgts.h
new file mode 100644
index 00000000000..e9e45218a70
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/msfmrgts.h
@@ -0,0 +1,55 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _MESSAGEFORMATREGRESSIONTEST_
+#define _MESSAGEFORMATREGRESSIONTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+/**
+ * Performs regression test for MessageFormat
+ **/
+class MessageFormatRegressionTest: public IntlTest {
+
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+
+ void Test4074764(void);
+ void Test4058973(void);
+ void Test4031438(void);
+ void Test4052223(void);
+ void Test4104976(void);
+ void Test4106659(void);
+ void Test4106660(void);
+ void Test4111739(void);
+ void Test4114743(void);
+ void Test4116444(void);
+ void Test4114739(void);
+ void Test4113018(void);
+ void Test4106661(void);
+ void Test4094906(void);
+ void Test4118592(void);
+ void Test4118594(void);
+ void Test4105380(void);
+ void Test4120552(void);
+ void Test4142938(void);
+ void TestChoicePatternQuote(void);
+ void Test4112104(void);
+
+protected:
+ UBool failure(UErrorCode status, const char* msg);
+
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _MESSAGEFORMATREGRESSIONTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/nmfmapts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/nmfmapts.cpp
new file mode 100644
index 00000000000..117b2ed3159
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/nmfmapts.cpp
@@ -0,0 +1,409 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "nmfmapts.h"
+
+#include "unicode/numfmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/locid.h"
+#include "unicode/unum.h"
+#include "unicode/strenum.h"
+
+// This is an API test, not a unit test. It doesn't test very many cases, and doesn't
+// try to test the full functionality. It just calls each function in the class and
+// verifies that it works on a basic level.
+
+void IntlTestNumberFormatAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite NumberFormatAPI");
+ switch (index) {
+ case 0: name = "NumberFormat API test";
+ if (exec) {
+ logln("NumberFormat API test---"); logln("");
+ UErrorCode status = U_ZERO_ERROR;
+ Locale saveLocale;
+ Locale::setDefault(Locale::getEnglish(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not set default locale, test may not give correct results");
+ }
+ testAPI(/* par */);
+ Locale::setDefault(saveLocale, status);
+ }
+ break;
+ case 1: name = "NumberFormatRegistration";
+ if (exec) {
+ logln("NumberFormat Registration test---"); logln("");
+ UErrorCode status = U_ZERO_ERROR;
+ Locale saveLocale;
+ Locale::setDefault(Locale::getEnglish(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not set default locale, test may not give correct results");
+ }
+ testRegistration();
+ Locale::setDefault(saveLocale, status);
+ }
+ break;
+ default: name = ""; break;
+ }
+}
+
+/**
+ * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
+ * NumberFormat.
+ */
+void IntlTestNumberFormatAPI::testAPI(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+// ======= Test constructors
+
+ logln("Testing NumberFormat constructors");
+
+ NumberFormat *def = NumberFormat::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create NumberFormat (default)");
+ }
+
+ status = U_ZERO_ERROR;
+ NumberFormat *fr = NumberFormat::createInstance(Locale::getFrench(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create NumberFormat (French)");
+ }
+
+ NumberFormat *cur = NumberFormat::createCurrencyInstance(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create NumberFormat (currency, default)");
+ }
+
+ status = U_ZERO_ERROR;
+ NumberFormat *cur_fr = NumberFormat::createCurrencyInstance(Locale::getFrench(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create NumberFormat (currency, French)");
+ }
+
+ NumberFormat *per = NumberFormat::createPercentInstance(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create NumberFormat (percent, default)");
+ }
+
+ status = U_ZERO_ERROR;
+ NumberFormat *per_fr = NumberFormat::createPercentInstance(Locale::getFrench(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create NumberFormat (percent, French)");
+ }
+
+// ======= Test equality
+if (per_fr != NULL && cur_fr != NULL)
+{
+ logln("Testing equality operator");
+
+ if( *per_fr == *cur_fr || ! ( *per_fr != *cur_fr) ) {
+ errln("ERROR: == failed");
+ }
+}
+
+// ======= Test various format() methods
+if (cur_fr != NULL)
+{
+ logln("Testing various format() methods");
+
+ double d = -10456.0037;
+ int32_t l = 100000000;
+ Formattable fD(d);
+ Formattable fL(l);
+
+ UnicodeString res1, res2, res3, res4, res5, res6;
+ FieldPosition pos1(0), pos2(0), pos3(0), pos4(0);
+
+ res1 = cur_fr->format(d, res1);
+ logln( (UnicodeString) "" + (int32_t) d + " formatted to " + res1);
+
+ res2 = cur_fr->format(l, res2);
+ logln((UnicodeString) "" + (int32_t) l + " formatted to " + res2);
+
+ res3 = cur_fr->format(d, res3, pos1);
+ logln( (UnicodeString) "" + (int32_t) d + " formatted to " + res3);
+
+ res4 = cur_fr->format(l, res4, pos2);
+ logln((UnicodeString) "" + (int32_t) l + " formatted to " + res4);
+
+ status = U_ZERO_ERROR;
+ res5 = cur_fr->format(fD, res5, pos3, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: format(Formattable [double]) failed");
+ }
+ logln((UnicodeString) "" + (int32_t) fD.getDouble() + " formatted to " + res5);
+
+ status = U_ZERO_ERROR;
+ res6 = cur_fr->format(fL, res6, pos4, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: format(Formattable [long]) failed");
+ }
+ logln((UnicodeString) "" + fL.getLong() + " formatted to " + res6);
+}
+
+// ======= Test parse()
+if (fr != NULL)
+{
+ logln("Testing parse()");
+
+ double d = -10456.0037;
+ UnicodeString text("-10,456.0037");
+ Formattable result1, result2, result3;
+ ParsePosition pos(0), pos01(0);
+ fr->parseObject(text, result1, pos);
+ if(result1.getType() != Formattable::kDouble && result1.getDouble() != d) {
+ errln("ERROR: Roundtrip failed (via parse()) for " + text);
+ }
+ logln(text + " parsed into " + (int32_t) result1.getDouble());
+
+ fr->parse(text, result2, pos01);
+ if(result2.getType() != Formattable::kDouble && result2.getDouble() != d) {
+ errln("ERROR: Roundtrip failed (via parse()) for " + text);
+ }
+ logln(text + " parsed into " + (int32_t) result2.getDouble());
+
+ status = U_ZERO_ERROR;
+ fr->parse(text, result3, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: parse() failed");
+ }
+ if(result3.getType() != Formattable::kDouble && result3.getDouble() != d) {
+ errln("ERROR: Roundtrip failed (via parse()) for " + text);
+ }
+ logln(text + " parsed into " + (int32_t) result3.getDouble());
+}
+
+// ======= Test getters and setters
+if (fr != NULL && def != NULL)
+{
+ logln("Testing getters and setters");
+
+ int32_t count = 0;
+ const Locale *locales = NumberFormat::getAvailableLocales(count);
+ logln((UnicodeString) "Got " + count + " locales" );
+ for(int32_t i = 0; i < count; i++) {
+ UnicodeString name(locales[i].getName(),"");
+ logln(name);
+ }
+
+ fr->setParseIntegerOnly( def->isParseIntegerOnly() );
+ if(fr->isParseIntegerOnly() != def->isParseIntegerOnly() ) {
+ errln("ERROR: setParseIntegerOnly() failed");
+ }
+
+ fr->setGroupingUsed( def->isGroupingUsed() );
+ if(fr->isGroupingUsed() != def->isGroupingUsed() ) {
+ errln("ERROR: setGroupingUsed() failed");
+ }
+
+ fr->setMaximumIntegerDigits( def->getMaximumIntegerDigits() );
+ if(fr->getMaximumIntegerDigits() != def->getMaximumIntegerDigits() ) {
+ errln("ERROR: setMaximumIntegerDigits() failed");
+ }
+
+ fr->setMinimumIntegerDigits( def->getMinimumIntegerDigits() );
+ if(fr->getMinimumIntegerDigits() != def->getMinimumIntegerDigits() ) {
+ errln("ERROR: setMinimumIntegerDigits() failed");
+ }
+
+ fr->setMaximumFractionDigits( def->getMaximumFractionDigits() );
+ if(fr->getMaximumFractionDigits() != def->getMaximumFractionDigits() ) {
+ errln("ERROR: setMaximumFractionDigits() failed");
+ }
+
+ fr->setMinimumFractionDigits( def->getMinimumFractionDigits() );
+ if(fr->getMinimumFractionDigits() != def->getMinimumFractionDigits() ) {
+ errln("ERROR: setMinimumFractionDigits() failed");
+ }
+}
+
+// ======= Test getStaticClassID()
+
+ logln("Testing getStaticClassID()");
+
+ status = U_ZERO_ERROR;
+ NumberFormat *test = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Couldn't create a NumberFormat");
+ }
+
+ if(test->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ errln("ERROR: getDynamicClassID() didn't return the expected value");
+ }
+
+ delete test;
+ delete def;
+ delete fr;
+ delete cur;
+ delete cur_fr;
+ delete per;
+ delete per_fr;
+}
+
+#if !UCONFIG_NO_SERVICE
+
+#define SRC_LOC Locale::getFrance()
+#define SWAP_LOC Locale::getUS()
+
+class NFTestFactory : public SimpleNumberFormatFactory {
+ NumberFormat* currencyStyle;
+
+public:
+ NFTestFactory()
+ : SimpleNumberFormatFactory(SRC_LOC, TRUE)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ currencyStyle = NumberFormat::createInstance(SWAP_LOC, status);
+ }
+
+ virtual ~NFTestFactory()
+ {
+ delete currencyStyle;
+ }
+
+ virtual NumberFormat* createFormat(const Locale& /* loc */, UNumberFormatStyle formatType)
+ {
+ if (formatType == UNUM_CURRENCY) {
+ return (NumberFormat*)currencyStyle->clone();
+ }
+ return NULL;
+ }
+
+ virtual inline UClassID getDynamicClassID() const
+ {
+ return (UClassID)&gID;
+ }
+
+ static inline UClassID getStaticClassID()
+ {
+ return (UClassID)&gID;
+ }
+
+private:
+ static char gID;
+};
+
+char NFTestFactory::gID = 0;
+#endif
+
+void
+IntlTestNumberFormatAPI::testRegistration()
+{
+#if !UCONFIG_NO_SERVICE
+ UErrorCode status = U_ZERO_ERROR;
+
+ NumberFormat* f0 = NumberFormat::createInstance(SWAP_LOC, status);
+ NumberFormat* f1 = NumberFormat::createInstance(SRC_LOC, status);
+ NumberFormat* f2 = NumberFormat::createCurrencyInstance(SRC_LOC, status);
+ URegistryKey key = NumberFormat::registerFactory(new NFTestFactory(), status);
+ NumberFormat* f3 = NumberFormat::createCurrencyInstance(SRC_LOC, status);
+ NumberFormat* f3a = NumberFormat::createCurrencyInstance(SRC_LOC, status);
+ NumberFormat* f4 = NumberFormat::createInstance(SRC_LOC, status);
+
+ StringEnumeration* locs = NumberFormat::getAvailableLocales();
+
+ UNumberFormat* uf3 = unum_open(UNUM_CURRENCY, NULL, 0, SRC_LOC.getName(),NULL, &status);
+ UNumberFormat* uf4 = unum_open(UNUM_DEFAULT, NULL, 0, SRC_LOC.getName(), NULL, &status);
+
+ const UnicodeString* res;
+ for (res = locs->snext(status); res; res = locs->snext(status)) {
+ logln(*res); // service is still in synch
+ }
+
+ NumberFormat::unregister(key, status); // restore for other tests
+ NumberFormat* f5 = NumberFormat::createCurrencyInstance(SRC_LOC, status);
+ UNumberFormat* uf5 = unum_open(UNUM_CURRENCY, NULL, 0, SRC_LOC.getName(),NULL, &status);
+
+ if (U_FAILURE(status)) {
+ dataerrln("Error creating instnaces.");
+ return;
+ } else {
+ float n = 1234.567f;
+ UnicodeString res0, res1, res2, res3, res4, res5;
+ UChar ures3[50];
+ UChar ures4[50];
+ UChar ures5[50];
+
+ f0->format(n, res0);
+ f1->format(n, res1);
+ f2->format(n, res2);
+ f3->format(n, res3);
+ f4->format(n, res4);
+ f5->format(n, res5);
+
+ unum_formatDouble(uf3, n, ures3, 50, NULL, &status);
+ unum_formatDouble(uf4, n, ures4, 50, NULL, &status);
+ unum_formatDouble(uf5, n, ures5, 50, NULL, &status);
+
+ logln((UnicodeString)"f0 swap int: " + res0);
+ logln((UnicodeString)"f1 src int: " + res1);
+ logln((UnicodeString)"f2 src cur: " + res2);
+ logln((UnicodeString)"f3 reg cur: " + res3);
+ logln((UnicodeString)"f4 reg int: " + res4);
+ logln((UnicodeString)"f5 unreg cur: " + res5);
+ log("uf3 reg cur: ");
+ logln(ures3);
+ log("uf4 reg int: ");
+ logln(ures4);
+ log("uf5 ureg cur: ");
+ logln(ures5);
+
+ if (f3 == f3a) {
+ errln("did not get new instance from service");
+ } else {
+ delete f3a;
+ }
+ if (res3 != res0) {
+ errln("registered service did not match");
+ }
+ if (res4 != res1) {
+ errln("registered service did not inherit");
+ }
+ if (res5 != res2) {
+ errln("unregistered service did not match original");
+ }
+
+ if (res0 != ures3) {
+ errln("registered service did not match / unum");
+ }
+ if (res1 != ures4) {
+ errln("registered service did not inherit / unum");
+ }
+ if (res2 != ures5) {
+ errln("unregistered service did not match original / unum");
+ }
+ }
+
+ unum_close(uf5);
+ delete f5;
+ unum_close(uf4);
+ unum_close(uf3);
+ delete f4;
+ delete f3;
+ delete f2;
+ delete f1;
+ delete f0;
+
+ for (res = locs->snext(status); res; res = locs->snext(status)) {
+ errln(*res); // service should be out of synch
+ }
+
+ locs->reset(status); // now in synch again, we hope
+ for (res = locs->snext(status); res; res = locs->snext(status)) {
+ logln(*res);
+ }
+
+ delete locs;
+#endif
+}
+
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/nmfmapts.h b/Build/source/libs/icu/icu-xetex/test/intltest/nmfmapts.h
new file mode 100644
index 00000000000..a2bcae2381d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/nmfmapts.h
@@ -0,0 +1,33 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _INTLTESTNUMBERFORMATAPI
+#define _INTLTESTNUMBERFORMATAPI
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+
+/**
+ * This test executes basic functionality checks of various API functions
+ **/
+class IntlTestNumberFormatAPI: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+private:
+ /**
+ * executes tests of API functions, see detailed comments in source code
+ **/
+ void testAPI(/* char* par */);
+ void testRegistration();
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/nmfmtrt.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/nmfmtrt.cpp
new file mode 100644
index 00000000000..580918aec8e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/nmfmtrt.cpp
@@ -0,0 +1,351 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "nmfmtrt.h"
+
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/locid.h"
+#include "putilimp.h"
+
+#include <float.h>
+#include <stdio.h> // for sprintf
+#include <stdlib.h>
+
+// *****************************************************************************
+// class NumberFormatRoundTripTest
+// *****************************************************************************
+
+UBool NumberFormatRoundTripTest::verbose = FALSE;
+UBool NumberFormatRoundTripTest::STRING_COMPARE = TRUE;
+UBool NumberFormatRoundTripTest::EXACT_NUMERIC_COMPARE = FALSE;
+UBool NumberFormatRoundTripTest::DEBUG = FALSE;
+double NumberFormatRoundTripTest::MAX_ERROR = 1e-14;
+double NumberFormatRoundTripTest::max_numeric_error = 0.0;
+double NumberFormatRoundTripTest::min_numeric_error = 1.0;
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
+
+void NumberFormatRoundTripTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite NumberFormatRoundTripTest");
+ switch (index) {
+ CASE(0, start)
+ default: name = ""; break;
+ }
+}
+
+UBool
+NumberFormatRoundTripTest::failure(UErrorCode status, const char* msg)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+uint32_t
+NumberFormatRoundTripTest::randLong()
+{
+ // Assume 8-bit (or larger) rand values. Also assume
+ // that the system rand() function is very poor, which it always is.
+ uint32_t d;
+ uint32_t i;
+ char* poke = (char*)&d;
+ for (i=0; i < sizeof(uint32_t); ++i)
+ {
+ poke[i] = (char)(rand() & 0xFF);
+ }
+ return d;
+}
+
+/**
+ * Return a random value from -range..+range.
+ */
+double
+NumberFormatRoundTripTest::randomDouble(double range)
+{
+ double a = randFraction();
+ return (2.0 * range * a) - range;
+}
+
+void
+NumberFormatRoundTripTest::start()
+{
+// test(NumberFormat.getInstance(new Locale("sr", "", "")));
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ NumberFormat *fmt = NULL;
+
+ logln("Default Locale");
+
+ fmt = NumberFormat::createInstance(status);
+ if (!failure(status, "NumberFormat::createInstance")){
+ test(fmt);
+ }
+ delete fmt;
+
+ fmt = NumberFormat::createCurrencyInstance(status);
+ if (!failure(status, "NumberFormat::createCurrencyInstance")){
+ test(fmt);
+ }
+ delete fmt;
+
+ fmt = NumberFormat::createPercentInstance(status);
+ if (!failure(status, "NumberFormat::createPercentInstance")){
+ test(fmt);
+ }
+ delete fmt;
+
+
+ int32_t locCount = 0;
+ const Locale *loc = NumberFormat::getAvailableLocales(locCount);
+ if(quick) {
+ if(locCount > 5)
+ locCount = 5;
+ logln("Quick mode: only testing first 5 Locales");
+ }
+ for(int i = 0; i < locCount; ++i) {
+ UnicodeString name;
+ logln(loc[i].getDisplayName(name));
+
+ fmt = NumberFormat::createInstance(loc[i], status);
+ failure(status, "NumberFormat::createInstance");
+ test(fmt);
+ delete fmt;
+
+ fmt = NumberFormat::createCurrencyInstance(loc[i], status);
+ failure(status, "NumberFormat::createCurrencyInstance");
+ test(fmt);
+ delete fmt;
+
+ fmt = NumberFormat::createPercentInstance(loc[i], status);
+ failure(status, "NumberFormat::createPercentInstance");
+ test(fmt);
+ delete fmt;
+ }
+
+ logln(UnicodeString("Numeric error ") + min_numeric_error + " to " + max_numeric_error);
+}
+
+
+void
+NumberFormatRoundTripTest::test(NumberFormat *fmt)
+{
+#if IEEE_754 && !defined(OS400)
+ test(fmt, uprv_getNaN());
+ test(fmt, uprv_getInfinity());
+ test(fmt, -uprv_getInfinity());
+#endif
+
+ test(fmt, (int32_t)500);
+ test(fmt, (int32_t)0);
+ test(fmt, (int32_t)-0);
+ test(fmt, 0.0);
+ double negZero = 0.0; negZero /= -1.0;
+ test(fmt, negZero);
+ test(fmt, 9223372036854775808.0);
+ test(fmt, -9223372036854775809.0);
+
+ for(int i = 0; i < 10; ++i) {
+ test(fmt, randomDouble(1));
+ test(fmt, randomDouble(10000));
+ test(fmt, uprv_floor((randomDouble(10000))));
+ test(fmt, randomDouble(1e50));
+ test(fmt, randomDouble(1e-50));
+#if !defined(OS390) && !defined(OS400)
+ test(fmt, randomDouble(1e100));
+#elif IEEE_754
+ test(fmt, randomDouble(1e75)); /*OS390 and OS400*/
+#endif /* OS390 and OS400 */
+ // {sfb} When formatting with a percent instance, numbers very close to
+ // DBL_MAX will fail the round trip. This is because:
+ // 1) Format the double into a string --> INF% (since 100 * double > DBL_MAX)
+ // 2) Parse the string into a double --> INF
+ // 3) Re-format the double --> INF%
+ // 4) The strings are equal, so that works.
+ // 5) Calculate the proportional error --> INF, so the test will fail
+ // I'll get around this by dividing by the multiplier to make sure
+ // the double will stay in range.
+ //if(fmt->getMultipler() == 1)
+ if(fmt->getDynamicClassID() == DecimalFormat::getStaticClassID())
+ {
+#if !defined(OS390) && !defined(OS400)
+ /* DBL_MAX/2 is here because randomDouble does a *2 in the math */
+ test(fmt, randomDouble(DBL_MAX/2.0) / ((DecimalFormat*)fmt)->getMultiplier());
+#elif IEEE_754
+ test(fmt, randomDouble(1e75) / ((DecimalFormat*)fmt)->getMultiplier());
+#else
+ test(fmt, randomDouble(1e65) / ((DecimalFormat*)fmt)->getMultiplier()); /*OS390*/
+#endif
+ }
+
+#if (defined(_MSC_VER) && _MSC_VER < 1400) || defined(__alpha__) || defined(U_OSF)
+ // These machines and compilers don't fully support denormalized doubles,
+ test(fmt, randomDouble(1e-292));
+ test(fmt, randomDouble(1e-100));
+#elif defined(OS390) || defined(OS400)
+ // i5/OS (OS400) throws exceptions on denormalized numbers
+# if IEEE_754
+ test(fmt, randomDouble(1e-78));
+ test(fmt, randomDouble(1e-78));
+ // #else we're using something like the old z/OS floating point.
+# endif
+#else
+ // This is a normal machine that can support IEEE754 denormalized doubles without throwing an error.
+ test(fmt, randomDouble(DBL_MIN)); /* Usually 2.2250738585072014e-308 */
+ test(fmt, randomDouble(1e-100));
+#endif
+ }
+}
+
+void
+NumberFormatRoundTripTest::test(NumberFormat *fmt, double value)
+{
+ test(fmt, Formattable(value));
+}
+
+void
+NumberFormatRoundTripTest::test(NumberFormat *fmt, int32_t value)
+{
+ test(fmt, Formattable(value));
+}
+
+void
+NumberFormatRoundTripTest::test(NumberFormat *fmt, const Formattable& value)
+{
+ fmt->setMaximumFractionDigits(999);
+ if(fmt->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ ((DecimalFormat *)fmt)->setRoundingIncrement(0.0);
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString s, s2, temp;
+ if(isDouble(value))
+ s = fmt->format(value.getDouble(), s);
+ else
+ s = fmt->format(value.getLong(), s);
+
+ Formattable n;
+ UBool show = verbose;
+ if(DEBUG)
+ logln(/*value.getString(temp) +*/ " F> " + escape(s));
+
+ fmt->parse(s, n, status);
+ failure(status, "fmt->parse");
+ if(DEBUG)
+ logln(escape(s) + " P> " /*+ n.getString(temp)*/);
+
+ if(isDouble(n))
+ s2 = fmt->format(n.getDouble(), s2);
+ else
+ s2 = fmt->format(n.getLong(), s2);
+
+ if(DEBUG)
+ logln(/*n.getString(temp) +*/ " F> " + escape(s2));
+
+ if(STRING_COMPARE) {
+ if (s != s2) {
+ errln("*** STRING ERROR \"" + escape(s) + "\" != \"" + escape(s2) + "\"");
+ show = TRUE;
+ }
+ }
+
+ if(EXACT_NUMERIC_COMPARE) {
+ if(value != n) {
+ errln("*** NUMERIC ERROR");
+ show = TRUE;
+ }
+ }
+ else {
+ // Compute proportional error
+ double error = proportionalError(value, n);
+
+ if(error > MAX_ERROR) {
+ errln(UnicodeString("*** NUMERIC ERROR ") + error);
+ show = TRUE;
+ }
+
+ if (error > max_numeric_error)
+ max_numeric_error = error;
+ if (error < min_numeric_error)
+ min_numeric_error = error;
+ }
+
+ if (show) {
+ errln(/*value.getString(temp) +*/ typeOf(value, temp) + " F> " +
+ escape(s) + " P> " + (n.getType() == Formattable::kDouble ? n.getDouble() : (double)n.getLong())
+ /*n.getString(temp) */ + typeOf(n, temp) + " F> " +
+ escape(s2));
+ }
+}
+
+double
+NumberFormatRoundTripTest::proportionalError(const Formattable& a, const Formattable& b)
+{
+ double aa,bb;
+
+ if(isDouble(a))
+ aa = a.getDouble();
+ else
+ aa = a.getLong();
+
+ if(isDouble(b))
+ bb = b.getDouble();
+ else
+ bb = b.getLong();
+
+ double error = aa - bb;
+ if(aa != 0 && bb != 0)
+ error /= aa;
+
+ return uprv_fabs(error);
+}
+
+UnicodeString&
+NumberFormatRoundTripTest::typeOf(const Formattable& n, UnicodeString& result)
+{
+ if(n.getType() == Formattable::kLong) {
+ result = UnicodeString(" Long");
+ }
+ else if(n.getType() == Formattable::kDouble) {
+ result = UnicodeString(" Double");
+ }
+ else if(n.getType() == Formattable::kString) {
+ result = UnicodeString(" UnicodeString");
+ UnicodeString temp;
+ }
+
+ return result;
+}
+
+
+UnicodeString&
+NumberFormatRoundTripTest::escape(UnicodeString& s)
+{
+ UnicodeString copy(s);
+ s.remove();
+ for(int i = 0; i < copy.length(); ++i) {
+ UChar c = copy[i];
+ if(c < 0x00FF)
+ s += c;
+ else {
+ s += "+U";
+ char temp[16];
+ sprintf(temp, "%4X", c); // might not work
+ s += temp;
+ }
+ }
+ return s;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/nmfmtrt.h b/Build/source/libs/icu/icu-xetex/test/intltest/nmfmtrt.h
new file mode 100644
index 00000000000..12eff9a29d8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/nmfmtrt.h
@@ -0,0 +1,77 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _NUMBERFORMATROUNDTRIPTEST_
+#define _NUMBERFORMATROUNDTRIPTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/numfmt.h"
+#include "unicode/fmtable.h"
+#include "intltest.h"
+
+/**
+ * Performs round-trip tests for NumberFormat
+ **/
+class NumberFormatRoundTripTest : public IntlTest {
+
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+
+ static UBool verbose;
+ static UBool STRING_COMPARE;
+ static UBool EXACT_NUMERIC_COMPARE;
+ static UBool DEBUG;
+ static double MAX_ERROR;
+ static double max_numeric_error;
+ static double min_numeric_error;
+
+
+ void start(void);
+
+ void test(NumberFormat *fmt);
+ void test(NumberFormat *fmt, double value);
+ void test(NumberFormat *fmt, int32_t value);
+ void test(NumberFormat *fmt, const Formattable& value);
+
+ static double randomDouble(double range);
+ static double proportionalError(const Formattable& a, const Formattable& b);
+ static UnicodeString& typeOf(const Formattable& n, UnicodeString& result);
+ static UnicodeString& escape(UnicodeString& s);
+
+ static inline UBool
+ isDouble(const Formattable& n)
+ { return (n.getType() == Formattable::kDouble); }
+
+ static inline UBool
+ isLong(const Formattable& n)
+ { return (n.getType() == Formattable::kLong); }
+
+ /*
+ * Return a random uint32_t
+ **/
+ static uint32_t randLong();
+
+ /**
+ * Return a random double 0 <= x < 1.0
+ **/
+ static double randFraction()
+ {
+ return (double)randLong() / (double)0xFFFFFFFF;
+ }
+
+protected:
+ UBool failure(UErrorCode status, const char* msg);
+
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _NUMBERFORMATROUNDTRIPTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/normconf.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/normconf.cpp
new file mode 100644
index 00000000000..c7a530dac9d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/normconf.cpp
@@ -0,0 +1,581 @@
+/*
+************************************************************************
+* Copyright (c) 1997-2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/uchar.h"
+#include "unicode/normlzr.h"
+#include "unicode/uniset.h"
+#include "unicode/putil.h"
+#include "unormimp.h"
+#include "cstring.h"
+#include "filestrm.h"
+#include "normconf.h"
+#include <stdio.h>
+
+#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
+
+#define CASE(id,test) case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ test(); \
+ } \
+ break
+
+void NormalizerConformanceTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par*/) {
+ switch (index) {
+ CASE(0, TestConformance);
+ CASE(1, TestConformance32);
+ // CASE(2, TestCase6);
+ default: name = ""; break;
+ }
+}
+
+#define FIELD_COUNT 5
+
+NormalizerConformanceTest::NormalizerConformanceTest() :
+ normalizer(UnicodeString(), UNORM_NFC) {}
+
+NormalizerConformanceTest::~NormalizerConformanceTest() {}
+
+// more interesting conformance test cases, not in the unicode.org NormalizationTest.txt
+static const char *moreCases[]={
+ // Markus 2001aug30
+ "0061 0332 0308;00E4 0332;0061 0332 0308;00E4 0332;0061 0332 0308; # Markus 0",
+
+ // Markus 2001oct26 - test edge case for iteration: U+0f73.cc==0 but decomposition.lead.cc==129
+ "0061 0301 0F73;00E1 0F71 0F72;0061 0F71 0F72 0301;00E1 0F71 0F72;0061 0F71 0F72 0301; # Markus 1"
+};
+
+void NormalizerConformanceTest::compare(const UnicodeString& s1, const UnicodeString& s2){
+ UErrorCode status=U_ZERO_ERROR;
+ // TODO: Re-enable this tests after UTC fixes UAX 21
+ if(s1.indexOf((UChar32)0x0345)>=0)return;
+ if(Normalizer::compare(s1,s2,U_FOLD_CASE_DEFAULT,status)!=0){
+ errln("Normalizer::compare() failed for s1: " + prettify(s1) + " s2: " +prettify(s2));
+ }
+}
+
+FileStream *
+NormalizerConformanceTest::openNormalizationTestFile(const char *filename) {
+ char unidataPath[2000];
+ const char *folder;
+ FileStream *input;
+ UErrorCode errorCode;
+
+ // look inside ICU_DATA first
+ folder=pathToDataDirectory();
+ if(folder!=NULL) {
+ strcpy(unidataPath, folder);
+ strcat(unidataPath, "unidata" U_FILE_SEP_STRING);
+ strcat(unidataPath, filename);
+ input=T_FileStream_open(unidataPath, "rb");
+ if(input!=NULL) {
+ return input;
+ }
+ }
+
+ // find icu/source/data/unidata relative to the test data
+ errorCode=U_ZERO_ERROR;
+ folder=loadTestData(errorCode);
+ if(U_SUCCESS(errorCode)) {
+ strcpy(unidataPath, folder);
+ strcat(unidataPath, U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".."
+ U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".."
+ U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "unidata" U_FILE_SEP_STRING);
+ strcat(unidataPath, filename);
+ input=T_FileStream_open(unidataPath, "rb");
+ if(input!=NULL) {
+ return input;
+ }
+ }
+
+ // look in icu/source/test/testdata/out/build
+ errorCode=U_ZERO_ERROR;
+ folder=loadTestData(errorCode);
+ if(U_SUCCESS(errorCode)) {
+ strcpy(unidataPath, folder);
+ strcat(unidataPath, U_FILE_SEP_STRING);
+ strcat(unidataPath, filename);
+ input=T_FileStream_open(unidataPath, "rb");
+ if(input!=NULL) {
+ return input;
+ }
+ }
+
+ // look in icu/source/test/testdata
+ errorCode=U_ZERO_ERROR;
+ folder=loadTestData(errorCode);
+ if(U_SUCCESS(errorCode)) {
+ strcpy(unidataPath, folder);
+ strcat(unidataPath, U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING);
+ strcat(unidataPath, filename);
+ input=T_FileStream_open(unidataPath, "rb");
+ if(input!=NULL) {
+ return input;
+ }
+ }
+
+ // find icu/source/data/unidata relative to U_TOPSRCDIR
+#if defined(U_TOPSRCDIR)
+ strcpy(unidataPath, U_TOPSRCDIR U_FILE_SEP_STRING "data" U_FILE_SEP_STRING "unidata" U_FILE_SEP_STRING);
+ strcat(unidataPath, filename);
+ input=T_FileStream_open(unidataPath, "rb");
+ if(input!=NULL) {
+ return input;
+ }
+
+ strcpy(unidataPath, U_TOPSRCDIR U_FILE_SEP_STRING "test" U_FILE_SEP_STRING "testdata" U_FILE_SEP_STRING);
+ strcat(unidataPath, filename);
+ input=T_FileStream_open(unidataPath, "rb");
+ if(input!=NULL) {
+ return input;
+ }
+#endif
+
+ errln("Failed to open %s", filename);
+ return NULL;
+}
+
+/**
+ * Test the conformance of Normalizer to
+ * http://www.unicode.org/Public/UNIDATA/NormalizationTest.txt
+ */
+void NormalizerConformanceTest::TestConformance() {
+ TestConformance(openNormalizationTestFile("NormalizationTest.txt"), 0);
+}
+
+void NormalizerConformanceTest::TestConformance32() {
+ TestConformance(openNormalizationTestFile("NormalizationTest-3.2.0.txt"), UNORM_UNICODE_3_2);
+}
+
+void NormalizerConformanceTest::TestConformance(FileStream *input, int32_t options) {
+ enum { BUF_SIZE = 1024 };
+ char lineBuf[BUF_SIZE];
+ UnicodeString fields[FIELD_COUNT];
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t passCount = 0;
+ int32_t failCount = 0;
+ UChar32 c;
+
+ if(input==NULL) {
+ return;
+ }
+
+ // UnicodeSet for all code points that are not mentioned in NormalizationTest.txt
+ UnicodeSet other(0, 0x10ffff);
+
+ int32_t count, countMoreCases = sizeof(moreCases)/sizeof(moreCases[0]);
+ for (count = 1;;++count) {
+ if (!T_FileStream_eof(input)) {
+ T_FileStream_readLine(input, lineBuf, (int32_t)sizeof(lineBuf));
+ } else {
+ // once NormalizationTest.txt is finished, use moreCases[]
+ if(count > countMoreCases) {
+ count = 0;
+ } else if(count == countMoreCases) {
+ // all done
+ break;
+ }
+ uprv_strcpy(lineBuf, moreCases[count]);
+ }
+ if (lineBuf[0] == 0 || lineBuf[0] == '\n' || lineBuf[0] == '\r') continue;
+
+ // Expect 5 columns of this format:
+ // 1E0C;1E0C;0044 0323;1E0C;0044 0323; # <comments>
+
+ // Parse out the comment.
+ if (lineBuf[0] == '#') continue;
+
+ // Read separator lines starting with '@'
+ if (lineBuf[0] == '@') {
+ logln(lineBuf);
+ continue;
+ }
+
+ // Parse out the fields
+ if (!hexsplit(lineBuf, ';', fields, FIELD_COUNT)) {
+ errln((UnicodeString)"Unable to parse line " + count);
+ break; // Syntax error
+ }
+
+ // Remove a single code point from the "other" UnicodeSet
+ if(fields[0].length()==fields[0].moveIndex32(0, 1)) {
+ c=fields[0].char32At(0);
+ if(0xac20<=c && c<=0xd73f && quick) {
+ // not an exhaustive test run: skip most Hangul syllables
+ if(c==0xac20) {
+ other.remove(0xac20, 0xd73f);
+ }
+ continue;
+ }
+ other.remove(c);
+ }
+
+ if (checkConformance(fields, lineBuf, options, status)) {
+ ++passCount;
+ } else {
+ ++failCount;
+ if(status == U_FILE_ACCESS_ERROR) {
+ errln("Something is wrong with the normalizer, skipping the rest of the test.");
+ break;
+ }
+ }
+ if ((count % 1000) == 0) {
+ logln("Line %d", count);
+ }
+ }
+
+ T_FileStream_close(input);
+
+ /*
+ * Test that all characters that are not mentioned
+ * as single code points in column 1
+ * do not change under any normalization.
+ */
+
+ // remove U+ffff because that is the end-of-iteration sentinel value
+ other.remove(0xffff);
+
+ for(c=0; c<=0x10ffff; quick ? c+=113 : ++c) {
+ if(0x30000<=c && c<0xe0000) {
+ c=0xe0000;
+ }
+ if(!other.contains(c)) {
+ continue;
+ }
+
+ fields[0]=fields[1]=fields[2]=fields[3]=fields[4].setTo(c);
+ sprintf(lineBuf, "not mentioned code point U+%04lx", (long)c);
+
+ if (checkConformance(fields, lineBuf, options, status)) {
+ ++passCount;
+ } else {
+ ++failCount;
+ if(status == U_FILE_ACCESS_ERROR) {
+ errln("Something is wrong with the normalizer, skipping the rest of the test.");
+ break;
+ }
+ }
+ if ((c % 0x1000) == 0) {
+ logln("Code point U+%04lx", c);
+ }
+ }
+
+ if (failCount != 0) {
+ errln((UnicodeString)"Total: " + failCount + " lines/code points failed, " +
+ passCount + " lines/code points passed");
+ } else {
+ logln((UnicodeString)"Total: " + passCount + " lines/code points passed");
+ }
+}
+
+/**
+ * Verify the conformance of the given line of the Unicode
+ * normalization (UTR 15) test suite file. For each line,
+ * there are five columns, corresponding to field[0]..field[4].
+ *
+ * The following invariants must be true for all conformant implementations
+ * c2 == NFC(c1) == NFC(c2) == NFC(c3)
+ * c3 == NFD(c1) == NFD(c2) == NFD(c3)
+ * c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5)
+ * c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5)
+ *
+ * @param field the 5 columns
+ * @param line the source line from the test suite file
+ * @return true if the test passes
+ */
+UBool NormalizerConformanceTest::checkConformance(const UnicodeString* field,
+ const char *line,
+ int32_t options,
+ UErrorCode &status) {
+ UBool pass = TRUE, result;
+ //UErrorCode status = U_ZERO_ERROR;
+ UnicodeString out, fcd;
+ int32_t fieldNum;
+
+ for (int32_t i=0; i<FIELD_COUNT; ++i) {
+ fieldNum = i+1;
+ if (i<3) {
+ Normalizer::normalize(field[i], UNORM_NFC, options, out, status);
+ pass &= assertEqual("C", field[i], out, field[1], "c2!=C(c", fieldNum);
+ iterativeNorm(field[i], UNORM_NFC, options, out, +1);
+ pass &= assertEqual("C(+1)", field[i], out, field[1], "c2!=C(c", fieldNum);
+ iterativeNorm(field[i], UNORM_NFC, options, out, -1);
+ pass &= assertEqual("C(-1)", field[i], out, field[1], "c2!=C(c", fieldNum);
+
+ Normalizer::normalize(field[i], UNORM_NFD, options, out, status);
+ pass &= assertEqual("D", field[i], out, field[2], "c3!=D(c", fieldNum);
+ iterativeNorm(field[i], UNORM_NFD, options, out, +1);
+ pass &= assertEqual("D(+1)", field[i], out, field[2], "c3!=D(c", fieldNum);
+ iterativeNorm(field[i], UNORM_NFD, options, out, -1);
+ pass &= assertEqual("D(-1)", field[i], out, field[2], "c3!=D(c", fieldNum);
+ }
+ Normalizer::normalize(field[i], UNORM_NFKC, options, out, status);
+ pass &= assertEqual("KC", field[i], out, field[3], "c4!=KC(c", fieldNum);
+ iterativeNorm(field[i], UNORM_NFKC, options, out, +1);
+ pass &= assertEqual("KC(+1)", field[i], out, field[3], "c4!=KC(c", fieldNum);
+ iterativeNorm(field[i], UNORM_NFKC, options, out, -1);
+ pass &= assertEqual("KC(-1)", field[i], out, field[3], "c4!=KC(c", fieldNum);
+
+ Normalizer::normalize(field[i], UNORM_NFKD, options, out, status);
+ pass &= assertEqual("KD", field[i], out, field[4], "c5!=KD(c", fieldNum);
+ iterativeNorm(field[i], UNORM_NFKD, options, out, +1);
+ pass &= assertEqual("KD(+1)", field[i], out, field[4], "c5!=KD(c", fieldNum);
+ iterativeNorm(field[i], UNORM_NFKD, options, out, -1);
+ pass &= assertEqual("KD(-1)", field[i], out, field[4], "c5!=KD(c", fieldNum);
+ }
+ compare(field[1],field[2]);
+ compare(field[0],field[1]);
+ // test quick checks
+ if(UNORM_NO == Normalizer::quickCheck(field[1], UNORM_NFC, options, status)) {
+ errln("Normalizer error: quickCheck(NFC(s), UNORM_NFC) is UNORM_NO");
+ pass = FALSE;
+ }
+ if(UNORM_NO == Normalizer::quickCheck(field[2], UNORM_NFD, options, status)) {
+ errln("Normalizer error: quickCheck(NFD(s), UNORM_NFD) is UNORM_NO");
+ pass = FALSE;
+ }
+ if(UNORM_NO == Normalizer::quickCheck(field[3], UNORM_NFKC, options, status)) {
+ errln("Normalizer error: quickCheck(NFKC(s), UNORM_NFKC) is UNORM_NO");
+ pass = FALSE;
+ }
+ if(UNORM_NO == Normalizer::quickCheck(field[4], UNORM_NFKD, options, status)) {
+ errln("Normalizer error: quickCheck(NFKD(s), UNORM_NFKD) is UNORM_NO");
+ pass = FALSE;
+ }
+
+ // branch on options==0 for better code coverage
+ if(options==0) {
+ result = Normalizer::isNormalized(field[1], UNORM_NFC, status);
+ } else {
+ result = Normalizer::isNormalized(field[1], UNORM_NFC, options, status);
+ }
+ if(!result) {
+ errln("Normalizer error: isNormalized(NFC(s), UNORM_NFC) is FALSE");
+ pass = FALSE;
+ }
+ if(field[0]!=field[1] && Normalizer::isNormalized(field[0], UNORM_NFC, options, status)) {
+ errln("Normalizer error: isNormalized(s, UNORM_NFC) is TRUE");
+ pass = FALSE;
+ }
+ if(!Normalizer::isNormalized(field[3], UNORM_NFKC, options, status)) {
+ errln("Normalizer error: isNormalized(NFKC(s), UNORM_NFKC) is FALSE");
+ pass = FALSE;
+ }
+ if(field[0]!=field[3] && Normalizer::isNormalized(field[0], UNORM_NFKC, options, status)) {
+ errln("Normalizer error: isNormalized(s, UNORM_NFKC) is TRUE");
+ pass = FALSE;
+ }
+
+ // test FCD quick check and "makeFCD"
+ Normalizer::normalize(field[0], UNORM_FCD, options, fcd, status);
+ if(UNORM_NO == Normalizer::quickCheck(fcd, UNORM_FCD, options, status)) {
+ errln("Normalizer error: quickCheck(FCD(s), UNORM_FCD) is UNORM_NO");
+ pass = FALSE;
+ }
+ if(UNORM_NO == Normalizer::quickCheck(field[2], UNORM_FCD, options, status)) {
+ errln("Normalizer error: quickCheck(NFD(s), UNORM_FCD) is UNORM_NO");
+ pass = FALSE;
+ }
+ if(UNORM_NO == Normalizer::quickCheck(field[4], UNORM_FCD, options, status)) {
+ errln("Normalizer error: quickCheck(NFKD(s), UNORM_FCD) is UNORM_NO");
+ pass = FALSE;
+ }
+
+ Normalizer::normalize(fcd, UNORM_NFD, options, out, status);
+ if(out != field[2]) {
+ errln("Normalizer error: NFD(FCD(s))!=NFD(s)");
+ pass = FALSE;
+ }
+
+ if (U_FAILURE(status)) {
+ errln("Normalizer::normalize returned error status");
+ pass = FALSE;
+ }
+
+ if(field[0]!=field[2]) {
+ // two strings that are canonically equivalent must test
+ // equal under a canonical caseless match
+ // see UAX #21 Case Mappings and Jitterbug 2021 and
+ // Unicode Technical Committee meeting consensus 92-C31
+ int32_t rc;
+
+ status=U_ZERO_ERROR;
+ rc=Normalizer::compare(field[0], field[2], (options<<UNORM_COMPARE_NORM_OPTIONS_SHIFT)|U_COMPARE_IGNORE_CASE, status);
+ if(U_FAILURE(status)) {
+ errln("Normalizer::compare(case-insensitive) sets %s", u_errorName(status));
+ pass=FALSE;
+ } else if(rc!=0) {
+ errln("Normalizer::compare(original, NFD, case-insensitive) returned %d instead of 0 for equal", rc);
+ pass=FALSE;
+ }
+ }
+
+ if (!pass) {
+ errln("FAIL: %s", line);
+ }
+ return pass;
+}
+
+/**
+ * Do a normalization using the iterative API in the given direction.
+ * @param dir either +1 or -1
+ */
+void NormalizerConformanceTest::iterativeNorm(const UnicodeString& str,
+ UNormalizationMode mode, int32_t options,
+ UnicodeString& result,
+ int8_t dir) {
+ UErrorCode status = U_ZERO_ERROR;
+ normalizer.setText(str, status);
+ normalizer.setMode(mode);
+ normalizer.setOption(-1, 0); // reset all options
+ normalizer.setOption(options, 1); // set desired options
+ result.truncate(0);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ UChar32 ch;
+ if (dir > 0) {
+ for (ch = normalizer.first(); ch != Normalizer::DONE;
+ ch = normalizer.next()) {
+ result.append(ch);
+ }
+ } else {
+ for (ch = normalizer.last(); ch != Normalizer::DONE;
+ ch = normalizer.previous()) {
+ result.insert(0, ch);
+ }
+ }
+}
+
+/**
+ * @param op name of normalization form, e.g., "KC"
+ * @param s string being normalized
+ * @param got value received
+ * @param exp expected value
+ * @param msg description of this test
+ * @param return true if got == exp
+ */
+UBool NormalizerConformanceTest::assertEqual(const char *op,
+ const UnicodeString& s,
+ const UnicodeString& got,
+ const UnicodeString& exp,
+ const char *msg,
+ int32_t field)
+{
+ if (exp == got)
+ return TRUE;
+
+ char *sChars, *gotChars, *expChars;
+ UnicodeString sPretty(prettify(s));
+ UnicodeString gotPretty(prettify(got));
+ UnicodeString expPretty(prettify(exp));
+
+ sChars = new char[sPretty.length() + 1];
+ gotChars = new char[gotPretty.length() + 1];
+ expChars = new char[expPretty.length() + 1];
+
+ sPretty.extract(0, sPretty.length(), sChars, sPretty.length() + 1);
+ sChars[sPretty.length()] = 0;
+ gotPretty.extract(0, gotPretty.length(), gotChars, gotPretty.length() + 1);
+ gotChars[gotPretty.length()] = 0;
+ expPretty.extract(0, expPretty.length(), expChars, expPretty.length() + 1);
+ expChars[expPretty.length()] = 0;
+
+ errln(" %s%d)%s(%s)=%s, exp. %s", msg, field, op, sChars, gotChars, expChars);
+
+ delete []sChars;
+ delete []gotChars;
+ delete []expChars;
+ return FALSE;
+}
+
+/**
+ * Split a string into pieces based on the given delimiter
+ * character. Then, parse the resultant fields from hex into
+ * characters. That is, "0040 0400;0C00;0899" -> new String[] {
+ * "\u0040\u0400", "\u0C00", "\u0899" }. The output is assumed to
+ * be of the proper length already, and exactly output.length
+ * fields are parsed. If there are too few an exception is
+ * thrown. If there are too many the extras are ignored.
+ *
+ * @return FALSE upon failure
+ */
+UBool NormalizerConformanceTest::hexsplit(const char *s, char delimiter,
+ UnicodeString output[], int32_t outputLength) {
+ const char *t = s;
+ char *end = NULL;
+ UChar32 c;
+ int32_t i;
+ for (i=0; i<outputLength; ++i) {
+ // skip whitespace
+ while(*t == ' ' || *t == '\t') {
+ ++t;
+ }
+
+ // read a sequence of code points
+ output[i].remove();
+ for(;;) {
+ c = (UChar32)uprv_strtoul(t, &end, 16);
+
+ if( (char *)t == end ||
+ (uint32_t)c > 0x10ffff ||
+ (*end != ' ' && *end != '\t' && *end != delimiter)
+ ) {
+ errln(UnicodeString("Bad field ", "") + (i + 1) + " in " + UnicodeString(s, ""));
+ return FALSE;
+ }
+
+ output[i].append(c);
+
+ t = (const char *)end;
+
+ // skip whitespace
+ while(*t == ' ' || *t == '\t') {
+ ++t;
+ }
+
+ if(*t == delimiter) {
+ ++t;
+ break;
+ }
+ if(*t == 0) {
+ if((i + 1) == outputLength) {
+ return TRUE;
+ } else {
+ errln(UnicodeString("Missing field(s) in ", "") + s + " only " + (i + 1) + " out of " + outputLength);
+ return FALSE;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+// Specific tests for debugging. These are generally failures taken from
+// the conformance file, but culled out to make debugging easier.
+
+void NormalizerConformanceTest::TestCase6(void) {
+ _testOneLine("0385;0385;00A8 0301;0020 0308 0301;0020 0308 0301;");
+}
+
+void NormalizerConformanceTest::_testOneLine(const char *line) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString fields[FIELD_COUNT];
+ if (!hexsplit(line, ';', fields, FIELD_COUNT)) {
+ errln((UnicodeString)"Unable to parse line " + line);
+ } else {
+ checkConformance(fields, line, 0, status);
+ }
+}
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/normconf.h b/Build/source/libs/icu/icu-xetex/test/intltest/normconf.h
new file mode 100644
index 00000000000..472c2dfd61f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/normconf.h
@@ -0,0 +1,105 @@
+/*
+************************************************************************
+* Copyright (c) 1997-2003, International Business Machines
+* Corporation and others. All Rights Reserved.
+************************************************************************
+*/
+
+#ifndef _NORMCONF
+#define _NORMCONF
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/normlzr.h"
+#include "intltest.h"
+
+typedef struct _FileStream FileStream;
+
+class NormalizerConformanceTest : public IntlTest {
+ Normalizer normalizer;
+
+ public:
+ NormalizerConformanceTest();
+ virtual ~NormalizerConformanceTest();
+
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par=NULL);
+
+ /**
+ * Test the conformance of Normalizer to
+ * http://www.unicode.org/Public/UNIDATA/NormalizationTest.txt
+ */
+ void TestConformance();
+ void TestConformance32();
+ void TestConformance(FileStream *input, int32_t options);
+
+ // Specific tests for debugging. These are generally failures taken from
+ // the conformance file, but culled out to make debugging easier.
+ void TestCase6(void);
+
+ private:
+ FileStream *openNormalizationTestFile(const char *filename);
+
+ /**
+ * Verify the conformance of the given line of the Unicode
+ * normalization (UTR 15) test suite file. For each line,
+ * there are five columns, corresponding to field[0]..field[4].
+ *
+ * The following invariants must be true for all conformant implementations
+ * c2 == NFC(c1) == NFC(c2) == NFC(c3)
+ * c3 == NFD(c1) == NFD(c2) == NFD(c3)
+ * c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5)
+ * c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5)
+ *
+ * @param field the 5 columns
+ * @param line the source line from the test suite file
+ * @return true if the test passes
+ */
+ UBool checkConformance(const UnicodeString* field,
+ const char *line,
+ int32_t options,
+ UErrorCode &status);
+
+ void iterativeNorm(const UnicodeString& str,
+ UNormalizationMode mode, int32_t options,
+ UnicodeString& result,
+ int8_t dir);
+
+ /**
+ * @param op name of normalization form, e.g., "KC"
+ * @param s string being normalized
+ * @param got value received
+ * @param exp expected value
+ * @param msg description of this test
+ * @param return true if got == exp
+ */
+ UBool assertEqual(const char *op,
+ const UnicodeString& s,
+ const UnicodeString& got,
+ const UnicodeString& exp,
+ const char *msg,
+ int32_t field);
+
+ /**
+ * Split a string into pieces based on the given delimiter
+ * character. Then, parse the resultant fields from hex into
+ * characters. That is, "0040 0400;0C00;0899" -> new String[] {
+ * "\u0040\u0400", "\u0C00", "\u0899" }. The output is assumed to
+ * be of the proper length already, and exactly output.length
+ * fields are parsed. If there are too few an exception is
+ * thrown. If there are too many the extras are ignored.
+ *
+ * @param buf scratch buffer
+ * @return FALSE upon failure
+ */
+ UBool hexsplit(const char *s, char delimiter,
+ UnicodeString output[], int32_t outputLength);
+
+ void _testOneLine(const char *line);
+ void compare(const UnicodeString& s1,const UnicodeString& s2);
+};
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/nptrans.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/nptrans.cpp
new file mode 100644
index 00000000000..eae8db5d59e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/nptrans.cpp
@@ -0,0 +1,289 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2003-2005, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: nptrans.h
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2003feb1
+ * created by: Ram Viswanadha
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+#if !UCONFIG_NO_IDNA
+
+#include "nptrans.h"
+#include "unicode/resbund.h"
+#include "unicode/uniset.h"
+#include "sprpimpl.h"
+#include "cmemory.h"
+#include "ustr_imp.h"
+#include "intltest.h"
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+const char NamePrepTransform::fgClassID=0;
+
+//Factory method
+NamePrepTransform* NamePrepTransform::createInstance(UParseError& parseError, UErrorCode& status){
+ NamePrepTransform* transform = new NamePrepTransform(parseError, status);
+ if(U_FAILURE(status)){
+ delete transform;
+ return NULL;
+ }
+ return transform;
+}
+
+//constructor
+NamePrepTransform::NamePrepTransform(UParseError& parseError, UErrorCode& status)
+: unassigned(), prohibited(), labelSeparatorSet(){
+
+ mapping = NULL;
+ bundle = NULL;
+
+
+ const char* testDataName = IntlTest::loadTestData(status);
+
+ if(U_FAILURE(status)){
+ return;
+ }
+
+ bundle = ures_openDirect(testDataName,"idna_rules",&status);
+
+ if(bundle != NULL && U_SUCCESS(status)){
+ // create the mapping transliterator
+ int32_t ruleLen = 0;
+ const UChar* ruleUChar = ures_getStringByKey(bundle, "MapNFKC",&ruleLen, &status);
+ int32_t mapRuleLen = 0;
+ const UChar *mapRuleUChar = ures_getStringByKey(bundle, "MapNoNormalization", &mapRuleLen, &status);
+ UnicodeString rule(mapRuleUChar, mapRuleLen);
+ rule.append(ruleUChar, ruleLen);
+
+ mapping = Transliterator::createFromRules(UnicodeString("NamePrepTransform", ""), rule,
+ UTRANS_FORWARD, parseError,status);
+ if(U_FAILURE(status)) {
+ return;
+ }
+
+ //create the unassigned set
+ int32_t patternLen =0;
+ const UChar* pattern = ures_getStringByKey(bundle,"UnassignedSet",&patternLen, &status);
+ unassigned.applyPattern(UnicodeString(pattern, patternLen), status);
+
+ //create prohibited set
+ patternLen=0;
+ pattern = ures_getStringByKey(bundle,"ProhibitedSet",&patternLen, &status);
+ UnicodeString test(pattern,patternLen);
+ prohibited.applyPattern(test,status);
+#ifdef DEBUG
+ if(U_FAILURE(status)){
+ printf("Construction of Unicode set failed\n");
+ }
+
+ if(U_SUCCESS(status)){
+ if(prohibited.contains((UChar) 0x644)){
+ printf("The string contains 0x644 ... damn !!\n");
+ }
+ UnicodeString temp;
+ prohibited.toPattern(temp,TRUE);
+
+ for(int32_t i=0;i<temp.length();i++){
+ printf("%c", (char)temp.charAt(i));
+ }
+ printf("\n");
+ }
+#endif
+
+ //create label separator set
+ patternLen=0;
+ pattern = ures_getStringByKey(bundle,"LabelSeparatorSet",&patternLen, &status);
+ labelSeparatorSet.applyPattern(UnicodeString(pattern,patternLen),status);
+ }
+
+ if(U_SUCCESS(status) &&
+ (mapping == NULL)
+ ){
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete mapping;
+ ures_close(bundle);
+ mapping = NULL;
+ bundle = NULL;
+ }
+
+}
+
+
+UBool NamePrepTransform::isProhibited(UChar32 ch){
+ return (UBool)(ch != ASCII_SPACE);
+}
+
+NamePrepTransform::~NamePrepTransform(){
+ delete mapping;
+ mapping = NULL;
+
+ //close the bundle
+ ures_close(bundle);
+ bundle = NULL;
+}
+
+
+int32_t NamePrepTransform::map(const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ UBool allowUnassigned,
+ UParseError* /*parseError*/,
+ UErrorCode& status ){
+
+ if(U_FAILURE(status)){
+ return 0;
+ }
+ //check arguments
+ if(src==NULL || srcLength<-1 || (dest==NULL && destCapacity!=0)) {
+ status=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UnicodeString rsource(src,srcLength);
+ // map the code points
+ // transliteration also performs NFKC
+ mapping->transliterate(rsource);
+
+ const UChar* buffer = rsource.getBuffer();
+ int32_t bufLen = rsource.length();
+ // check if unassigned
+ if(allowUnassigned == FALSE){
+ int32_t bufIndex=0;
+ UChar32 ch =0 ;
+ for(;bufIndex<bufLen;){
+ U16_NEXT(buffer, bufIndex, bufLen, ch);
+ if(unassigned.contains(ch)){
+ status = U_IDNA_UNASSIGNED_ERROR;
+ return 0;
+ }
+ }
+ }
+ // check if there is enough room in the output
+ if(bufLen < destCapacity){
+ uprv_memcpy(dest,buffer,bufLen*U_SIZEOF_UCHAR);
+ }
+
+ return u_terminateUChars(dest, destCapacity, bufLen, &status);
+}
+
+
+#define MAX_BUFFER_SIZE 300
+
+int32_t NamePrepTransform::process( const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ UBool allowUnassigned,
+ UParseError* parseError,
+ UErrorCode& status ){
+ // check error status
+ if(U_FAILURE(status)){
+ return 0;
+ }
+
+ //check arguments
+ if(src==NULL || srcLength<-1 || (dest==NULL && destCapacity!=0)) {
+ status=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UChar b1Stack[MAX_BUFFER_SIZE];
+ UChar *b1 = b1Stack;
+ int32_t b1Len,b1Capacity = MAX_BUFFER_SIZE;
+
+ int32_t b1Index = 0;
+ UCharDirection direction=U_CHAR_DIRECTION_COUNT, firstCharDir=U_CHAR_DIRECTION_COUNT;
+ UBool leftToRight=FALSE, rightToLeft=FALSE;
+
+ b1Len = map(src,srcLength, b1, b1Capacity,allowUnassigned,parseError, status);
+
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ // redo processing of string
+ /* we do not have enough room so grow the buffer*/
+ if(!u_growBufferFromStatic(b1Stack,&b1,&b1Capacity,b1Len,0)){
+ status = U_MEMORY_ALLOCATION_ERROR;
+ goto CLEANUP;
+ }
+
+ status = U_ZERO_ERROR; // reset error
+
+ b1Len = map(src,srcLength, b1, b1Len,allowUnassigned, parseError, status);
+
+ }
+
+ if(U_FAILURE(status)){
+ goto CLEANUP;
+ }
+
+
+ for(; b1Index<b1Len; ){
+
+ UChar32 ch = 0;
+
+ U16_NEXT(b1, b1Index, b1Len, ch);
+
+ if(prohibited.contains(ch) && ch!=0x0020){
+ status = U_IDNA_PROHIBITED_ERROR;
+ goto CLEANUP;
+ }
+
+ direction = u_charDirection(ch);
+ if(firstCharDir==U_CHAR_DIRECTION_COUNT){
+ firstCharDir = direction;
+ }
+ if(direction == U_LEFT_TO_RIGHT){
+ leftToRight = TRUE;
+ }
+ if(direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC){
+ rightToLeft = TRUE;
+ }
+ }
+
+ // satisfy 2
+ if( leftToRight == TRUE && rightToLeft == TRUE){
+ status = U_IDNA_CHECK_BIDI_ERROR;
+ goto CLEANUP;
+ }
+
+ //satisfy 3
+ if( rightToLeft == TRUE &&
+ !((firstCharDir == U_RIGHT_TO_LEFT || firstCharDir == U_RIGHT_TO_LEFT_ARABIC) &&
+ (direction == U_RIGHT_TO_LEFT || direction == U_RIGHT_TO_LEFT_ARABIC))
+ ){
+ status = U_IDNA_CHECK_BIDI_ERROR;
+ return FALSE;
+ }
+
+ if(b1Len <= destCapacity){
+ uprv_memmove(dest,b1, b1Len*U_SIZEOF_UCHAR);
+ }
+
+CLEANUP:
+ if(b1!=b1Stack){
+ uprv_free(b1);
+ }
+
+ return u_terminateUChars(dest, destCapacity, b1Len, &status);
+}
+
+UBool NamePrepTransform::isLabelSeparator(UChar32 ch, UErrorCode& status){
+ // check error status
+ if(U_FAILURE(status)){
+ return FALSE;
+ }
+
+ return labelSeparatorSet.contains(ch);
+}
+
+#endif /* #if !UCONFIG_NO_IDNA */
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/nptrans.h b/Build/source/libs/icu/icu-xetex/test/intltest/nptrans.h
new file mode 100644
index 00000000000..ece53e3e8fd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/nptrans.h
@@ -0,0 +1,164 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2003-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: nptrans.h
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2003feb1
+ * created by: Ram Viswanadha
+ */
+
+#ifndef NPTRANS_H
+#define NPTRANS_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/uniset.h"
+#include "unicode/ures.h"
+#include "unicode/translit.h"
+
+#include "intltest.h"
+
+
+#define ASCII_SPACE 0x0020
+
+class NamePrepTransform {
+
+private :
+ Transliterator *mapping;
+ UnicodeSet unassigned;
+ UnicodeSet prohibited;
+ UnicodeSet labelSeparatorSet;
+ UResourceBundle *bundle;
+ NamePrepTransform(UParseError& parseError, UErrorCode& status);
+
+
+public :
+
+ static NamePrepTransform* createInstance(UParseError& parseError, UErrorCode& status);
+
+ virtual ~NamePrepTransform();
+
+
+ inline UBool isProhibited(UChar32 ch);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.6
+ */
+ inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.6
+ */
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+ /**
+ * Map every character in input stream with mapping character
+ * in the mapping table and populate the output stream.
+ * For any individual character the mapping table may specify
+ * that that a character be mapped to nothing, mapped to one
+ * other character or to a string of other characters.
+ *
+ * @param src Pointer to UChar buffer containing a single label
+ * @param srcLength Number of characters in the source label
+ * @param dest Pointer to the destination buffer to receive the output
+ * @param destCapacity The capacity of destination array
+ * @param allowUnassigned Unassigned values can be converted to ASCII for query operations
+ * If TRUE unassigned values are treated as normal Unicode code point.
+ * If FALSE the operation fails with U_UNASSIGNED_CODE_POINT_FOUND error code.
+ * @param status ICU error code in/out parameter.
+ * Must fulfill U_SUCCESS before the function call.
+ * @return The number of UChars in the destination buffer
+ *
+ */
+ int32_t map(const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ UBool allowUnassigned,
+ UParseError* parseError,
+ UErrorCode& status );
+
+ /**
+ * Prepare the input stream with for use. This operation maps, normalizes(NFKC),
+ * checks for prohited and BiDi characters in the order defined by RFC 3454
+ *
+ * @param src Pointer to UChar buffer containing a single label
+ * @param srcLength Number of characters in the source label
+ * @param dest Pointer to the destination buffer to receive the output
+ * @param destCapacity The capacity of destination array
+ * @param allowUnassigned Unassigned values can be converted to ASCII for query operations
+ * If TRUE unassigned values are treated as normal Unicode code point.
+ * If FALSE the operation fails with U_UNASSIGNED_CODE_POINT error code.
+ * @param status ICU error code in/out parameter.
+ * Must fulfill U_SUCCESS before the function call.
+ * @return The number of UChars in the destination buffer
+ */
+ int32_t process(const UChar* src, int32_t srcLength,
+ UChar* dest, int32_t destCapacity,
+ UBool allowUnassigned,
+ UParseError* parseError,
+ UErrorCode& status );
+
+ /**
+ * Ascertain if the given code point is a label separator as specified by IDNA
+ *
+ * @return TRUE is the code point is a label separator
+ *
+ *
+ */
+ UBool isLabelSeparator(UChar32 ch, UErrorCode& status);
+
+
+ inline UBool isLDHChar(UChar32 ch);
+private:
+ /**
+ * The address of this static class variable serves as this class's ID
+ * for ICU "poor man's RTTI".
+ */
+ static const char fgClassID;
+};
+
+inline UBool NamePrepTransform::isLDHChar(UChar32 ch){
+ // high runner case
+ if(ch>0x007A){
+ return FALSE;
+ }
+ //[\\u002D \\u0030-\\u0039 \\u0041-\\u005A \\u0061-\\u007A]
+ if( (ch==0x002D) ||
+ (0x0030 <= ch && ch <= 0x0039) ||
+ (0x0041 <= ch && ch <= 0x005A) ||
+ (0x0061 <= ch && ch <= 0x007A)
+ ){
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+#else
+class NamePrepTransform {
+};
+#endif /* #if !UCONFIG_NO_IDNA */
+
+#endif
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp
new file mode 100644
index 00000000000..14d8f113ce6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.cpp
@@ -0,0 +1,2412 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/* Modification History:
+* Date Name Description
+* 07/15/99 helena Ported to HPUX 10/11 CC.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "numfmtst.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/ucurr.h"
+#include "unicode/ustring.h"
+#include "unicode/measfmt.h"
+#include "unicode/curramt.h"
+#include "digitlst.h"
+#include "textfile.h"
+#include "tokiter.h"
+#include "charstr.h"
+#include "putilimp.h"
+#include "winnmtst.h"
+#include <float.h>
+#include <string.h>
+
+static const UChar EUR[] = {69,85,82,0}; // "EUR"
+
+// *****************************************************************************
+// class NumberFormatTest
+// *****************************************************************************
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
+
+#define CHECK(status,str) if (U_FAILURE(status)) { errln(UnicodeString("FAIL: ") + str); return; }
+
+void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite DateFormatTest");
+ switch (index) {
+ CASE(0,TestCurrencySign);
+ CASE(1,TestCurrency);
+ CASE(2,TestParse);
+ CASE(3,TestRounding487);
+ CASE(4,TestQuotes);
+ CASE(5,TestExponential);
+ CASE(6,TestPatterns);
+
+ // Upgrade to alphaWorks - liu 5/99
+ CASE(7,TestExponent);
+ CASE(8,TestScientific);
+ CASE(9,TestPad);
+ CASE(10,TestPatterns2);
+ CASE(11,TestSecondaryGrouping);
+ CASE(12,TestSurrogateSupport);
+ CASE(13,TestAPI);
+
+ CASE(14,TestCurrencyObject);
+ CASE(15,TestCurrencyPatterns);
+ //CASE(16,TestDigitList);
+ CASE(16,TestWhiteSpaceParsing);
+ CASE(17,TestComplexCurrency);
+ CASE(18,TestRegCurrency);
+ CASE(19,TestSymbolsWithBadLocale);
+ CASE(20,TestAdoptDecimalFormatSymbols);
+
+ CASE(21,TestScientific2);
+ CASE(22,TestScientificGrouping);
+ CASE(23,TestInt64);
+
+ CASE(24,TestPerMill);
+ CASE(25,TestIllegalPatterns);
+ CASE(26,TestCases);
+
+ CASE(27,TestCurrencyNames);
+ CASE(28,TestCurrencyAmount);
+ CASE(29,TestCurrencyUnit);
+ CASE(30,TestCoverage);
+ CASE(31,TestJB3832);
+ CASE(32,TestHost);
+ CASE(33,TestHostClone);
+ CASE(34,TestCurrencyFormat);
+ CASE(35,TestRounding);
+ default: name = ""; break;
+ }
+}
+
+// -------------------------------------
+
+// Test API (increase code coverage)
+void
+NumberFormatTest::TestAPI(void)
+{
+ logln("Test API");
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *test = NumberFormat::createInstance("root", status);
+ if(U_FAILURE(status)) {
+ errln("unable to create format object");
+ }
+ if(test != NULL) {
+ test->setMinimumIntegerDigits(10);
+ test->setMaximumIntegerDigits(2);
+
+ test->setMinimumFractionDigits(10);
+ test->setMaximumFractionDigits(2);
+
+ UnicodeString result;
+ FieldPosition pos;
+ Formattable bla("Paja Patak"); // Donald Duck for non Serbian speakers
+ test->format(bla, result, pos, status);
+ if(U_SUCCESS(status)) {
+ errln("Yuck... Formatted a duck... As a number!");
+ } else {
+ status = U_ZERO_ERROR;
+ }
+
+ result.remove();
+ int64_t ll = 12;
+ test->format(ll, result);
+ if (result != "12.00"){
+ errln("format int64_t error");
+ }
+
+ delete test;
+ }
+}
+
+class StubNumberForamt :public NumberFormat{
+public:
+ StubNumberForamt(){};
+ virtual UnicodeString& format(double ,UnicodeString& appendTo,FieldPosition& ) const {
+ return appendTo;
+ }
+ virtual UnicodeString& format(int32_t ,UnicodeString& appendTo,FieldPosition& ) const {
+ return appendTo.append((UChar)0x0033);
+ }
+ virtual UnicodeString& format(int64_t number,UnicodeString& appendTo,FieldPosition& pos) const {
+ return NumberFormat::format(number, appendTo, pos);
+ }
+ virtual UnicodeString& format(const Formattable& , UnicodeString& appendTo, FieldPosition& , UErrorCode& ) const {
+ return appendTo;
+ }
+ virtual void parse(const UnicodeString& ,
+ Formattable& ,
+ ParsePosition& ) const {}
+ virtual void parse( const UnicodeString& ,
+ Formattable& ,
+ UErrorCode& ) const {}
+ virtual UClassID getDynamicClassID(void) const {
+ static char classID = 0;
+ return (UClassID)&classID;
+ }
+ virtual Format* clone() const {return NULL;}
+};
+
+void
+NumberFormatTest::TestCoverage(void){
+ StubNumberForamt stub;
+ UnicodeString agent("agent");
+ FieldPosition pos;
+ int64_t num = 4;
+ if (stub.format(num, agent, pos) != UnicodeString("agent3")){
+ errln("NumberFormat::format(int64, UnicodString&, FieldPosition&) should delegate to (int32, ,)");
+ };
+}
+
+// Test various patterns
+void
+NumberFormatTest::TestPatterns(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols sym(Locale::getUS(), status);
+ if (U_FAILURE(status)) { errln("FAIL: Could not construct DecimalFormatSymbols"); return; }
+
+ const char* pat[] = { "#.#", "#.", ".#", "#" };
+ int32_t pat_length = (int32_t)(sizeof(pat) / sizeof(pat[0]));
+ const char* newpat[] = { "#0.#", "#0.", "#.0", "#" };
+ const char* num[] = { "0", "0.", ".0", "0" };
+ for (int32_t i=0; i<pat_length; ++i)
+ {
+ status = U_ZERO_ERROR;
+ DecimalFormat fmt(pat[i], sym, status);
+ if (U_FAILURE(status)) { errln((UnicodeString)"FAIL: DecimalFormat constructor failed for " + pat[i]); continue; }
+ UnicodeString newp; fmt.toPattern(newp);
+ if (!(newp == newpat[i]))
+ errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should transmute to " + newpat[i] +
+ "; " + newp + " seen instead");
+
+ UnicodeString s; (*(NumberFormat*)&fmt).format((int32_t)0, s);
+ if (!(s == num[i]))
+ {
+ errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should format zero as " + num[i] +
+ "; " + s + " seen instead");
+ logln((UnicodeString)"Min integer digits = " + fmt.getMinimumIntegerDigits());
+ }
+ }
+}
+
+/*
+icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug
+icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug
+icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug
+*/
+/*
+void
+NumberFormatTest::TestDigitList(void)
+{
+ // API coverage for DigitList
+ DigitList list1;
+ list1.append('1');
+ list1.fDecimalAt = 1;
+ DigitList list2;
+ list2.set((int32_t)1);
+ if (list1 != list2) {
+ errln("digitlist append, operator!= or set failed ");
+ }
+ if (!(list1 == list2)) {
+ errln("digitlist append, operator== or set failed ");
+ }
+}
+*/
+
+// -------------------------------------
+
+// Test exponential pattern
+void
+NumberFormatTest::TestExponential(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols sym(Locale::getUS(), status);
+ if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormatSymbols ct"); return; }
+ const char* pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" };
+ int32_t pat_length = (int32_t)(sizeof(pat) / sizeof(pat[0]));
+
+// The following #if statements allow this test to be built and run on
+// platforms that do not have standard IEEE numerics. For example,
+// S/390 doubles have an exponent range of -78 to +75. For the
+// following #if statements to work, float.h must define
+// DBL_MAX_10_EXP to be a compile-time constant.
+
+// This section may be expanded as needed.
+
+#if DBL_MAX_10_EXP > 300
+ double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 };
+ int32_t val_length = (int32_t)(sizeof(val) / sizeof(val[0]));
+ const char* valFormat[] =
+ {
+ // 0.####E0
+ "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271",
+ // 00.000E00
+ "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272",
+ // ##0.######E000
+ "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273",
+ // 0.###E0;[0.###E0]
+ "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]"
+ };
+ double valParse[] =
+ {
+ 0.01234, 123460000, 1.23E300, -3.1416E-271,
+ 0.01234, 123460000, 1.23E300, -3.1416E-271,
+ 0.01234, 123456800, 1.23E300, -3.141593E-271,
+ 0.01234, 123500000, 1.23E300, -3.142E-271,
+ };
+#elif DBL_MAX_10_EXP > 70
+ double val[] = { 0.01234, 123456789, 1.23e70, -3.141592653e-71 };
+ int32_t val_length = sizeof(val) / sizeof(val[0]);
+ char* valFormat[] =
+ {
+ // 0.####E0
+ "1.234E-2", "1.2346E8", "1.23E70", "-3.1416E-71",
+ // 00.000E00
+ "12.340E-03", "12.346E07", "12.300E69", "-31.416E-72",
+ // ##0.######E000
+ "12.34E-003", "123.4568E006", "12.3E069", "-31.41593E-072",
+ // 0.###E0;[0.###E0]
+ "1.234E-2", "1.235E8", "1.23E70", "[3.142E-71]"
+ };
+ double valParse[] =
+ {
+ 0.01234, 123460000, 1.23E70, -3.1416E-71,
+ 0.01234, 123460000, 1.23E70, -3.1416E-71,
+ 0.01234, 123456800, 1.23E70, -3.141593E-71,
+ 0.01234, 123500000, 1.23E70, -3.142E-71,
+ };
+#else
+ // Don't test double conversion
+ double* val = 0;
+ int32_t val_length = 0;
+ char** valFormat = 0;
+ double* valParse = 0;
+ logln("Warning: Skipping double conversion tests");
+#endif
+
+ int32_t lval[] = { 0, -1, 1, 123456789 };
+ int32_t lval_length = (int32_t)(sizeof(lval) / sizeof(lval[0]));
+ const char* lvalFormat[] =
+ {
+ // 0.####E0
+ "0E0", "-1E0", "1E0", "1.2346E8",
+ // 00.000E00
+ "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07",
+ // ##0.######E000
+ "0E000", "-1E000", "1E000", "123.4568E006",
+ // 0.###E0;[0.###E0]
+ "0E0", "[1E0]", "1E0", "1.235E8"
+ };
+ int32_t lvalParse[] =
+ {
+ 0, -1, 1, 123460000,
+ 0, -1, 1, 123460000,
+ 0, -1, 1, 123456800,
+ 0, -1, 1, 123500000,
+ };
+ int32_t ival = 0, ilval = 0;
+ for (int32_t p=0; p<pat_length; ++p)
+ {
+ DecimalFormat fmt(pat[p], sym, status);
+ if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormat ct"); continue; }
+ UnicodeString pattern;
+ logln((UnicodeString)"Pattern \"" + pat[p] + "\" -toPattern-> \"" +
+ fmt.toPattern(pattern) + "\"");
+ int32_t v;
+ for (v=0; v<val_length; ++v)
+ {
+ UnicodeString s; (*(NumberFormat*)&fmt).format(val[v], s);
+ logln((UnicodeString)" " + val[v] + " -format-> " + s);
+ if (s != valFormat[v+ival])
+ errln((UnicodeString)"FAIL: Expected " + valFormat[v+ival]);
+
+ ParsePosition pos(0);
+ Formattable af;
+ fmt.parse(s, af, pos);
+ double a;
+ UBool useEpsilon = FALSE;
+ if (af.getType() == Formattable::kLong)
+ a = af.getLong();
+ else if (af.getType() == Formattable::kDouble) {
+ a = af.getDouble();
+#if defined(OS390) || defined(OS400)
+ // S/390 will show a failure like this:
+ //| -3.141592652999999e-271 -format-> -3.1416E-271
+ //| -parse-> -3.1416e-271
+ //| FAIL: Expected -3.141599999999999e-271
+ // To compensate, we use an epsilon-based equality
+ // test on S/390 only. We don't want to do this in
+ // general because it's less exacting.
+ useEpsilon = TRUE;
+#endif
+ }
+ else {
+ errln((UnicodeString)"FAIL: Non-numeric Formattable returned");
+ continue;
+ }
+ if (pos.getIndex() == s.length())
+ {
+ logln((UnicodeString)" -parse-> " + a);
+ // Use epsilon comparison as necessary
+ if ((useEpsilon &&
+ (uprv_fabs(a - valParse[v+ival]) / a > (2*DBL_EPSILON))) ||
+ (!useEpsilon && a != valParse[v+ival]))
+ {
+ errln((UnicodeString)"FAIL: Expected " + valParse[v+ival]);
+ }
+ }
+ else {
+ errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
+ errln((UnicodeString)" should be (" + s.length() + " chars) -> " + valParse[v+ival]);
+ }
+ }
+ for (v=0; v<lval_length; ++v)
+ {
+ UnicodeString s;
+ (*(NumberFormat*)&fmt).format(lval[v], s);
+ logln((UnicodeString)" " + lval[v] + "L -format-> " + s);
+ if (s != lvalFormat[v+ilval])
+ errln((UnicodeString)"ERROR: Expected " + lvalFormat[v+ilval] + " Got: " + s);
+
+ ParsePosition pos(0);
+ Formattable af;
+ fmt.parse(s, af, pos);
+ if (af.getType() == Formattable::kLong ||
+ af.getType() == Formattable::kInt64) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t a = af.getLong(status);
+ if (pos.getIndex() == s.length())
+ {
+ logln((UnicodeString)" -parse-> " + a);
+ if (a != lvalParse[v+ilval])
+ errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval]);
+ }
+ else
+ errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
+ }
+ else
+ errln((UnicodeString)"FAIL: Non-long Formattable returned for " + s
+ + " Double: " + af.getDouble()
+ + ", Long: " + af.getLong());
+ }
+ ival += val_length;
+ ilval += lval_length;
+ }
+}
+
+void
+NumberFormatTest::TestScientific2() {
+ // jb 2552
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat* fmt = (DecimalFormat*)NumberFormat::createCurrencyInstance("en_US", status);
+ if (U_SUCCESS(status)) {
+ double num = 12.34;
+ expect(*fmt, num, "$12.34");
+ fmt->setScientificNotation(TRUE);
+ expect(*fmt, num, "$1.23E1");
+ fmt->setScientificNotation(FALSE);
+ expect(*fmt, num, "$12.34");
+ }
+ delete fmt;
+}
+
+void
+NumberFormatTest::TestScientificGrouping() {
+ // jb 2552
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat fmt("##0.00E0",status);
+ if (U_SUCCESS(status)) {
+ expect(fmt, .01234, "12.3E-3");
+ expect(fmt, .1234, "123E-3");
+ expect(fmt, 1.234, "1.23E0");
+ expect(fmt, 12.34, "12.3E0");
+ expect(fmt, 123.4, "123E0");
+ expect(fmt, 1234., "1.23E3");
+ }
+}
+
+/*static void setFromString(DigitList& dl, const char* str) {
+ char c;
+ UBool decimalSet = FALSE;
+ dl.clear();
+ while ((c = *str++)) {
+ if (c == '-') {
+ dl.fIsPositive = FALSE;
+ } else if (c == '+') {
+ dl.fIsPositive = TRUE;
+ } else if (c == '.') {
+ dl.fDecimalAt = dl.fCount;
+ decimalSet = TRUE;
+ } else {
+ dl.append(c);
+ }
+ }
+ if (!decimalSet) {
+ dl.fDecimalAt = dl.fCount;
+ }
+}*/
+
+void
+NumberFormatTest::TestInt64() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat fmt("#.#E0",status);
+ fmt.setMaximumFractionDigits(20);
+ if (U_SUCCESS(status)) {
+ expect(fmt, (Formattable)(int64_t)0, "0E0");
+ expect(fmt, (Formattable)(int64_t)-1, "-1E0");
+ expect(fmt, (Formattable)(int64_t)1, "1E0");
+ expect(fmt, (Formattable)(int64_t)2147483647, "2.147483647E9");
+ expect(fmt, (Formattable)((int64_t)-2147483647-1), "-2.147483648E9");
+ expect(fmt, (Formattable)(int64_t)U_INT64_MAX, "9.223372036854775807E18");
+ expect(fmt, (Formattable)(int64_t)U_INT64_MIN, "-9.223372036854775808E18");
+ }
+
+ // also test digitlist
+/* int64_t int64max = U_INT64_MAX;
+ int64_t int64min = U_INT64_MIN;
+ const char* int64maxstr = "9223372036854775807";
+ const char* int64minstr = "-9223372036854775808";
+ UnicodeString fail("fail: ");
+
+ // test max int64 value
+ DigitList dl;
+ setFromString(dl, int64maxstr);
+ {
+ if (!dl.fitsIntoInt64(FALSE)) {
+ errln(fail + int64maxstr + " didn't fit");
+ }
+ int64_t int64Value = dl.getInt64();
+ if (int64Value != int64max) {
+ errln(fail + int64maxstr);
+ }
+ dl.set(int64Value);
+ int64Value = dl.getInt64();
+ if (int64Value != int64max) {
+ errln(fail + int64maxstr);
+ }
+ }
+ // test negative of max int64 value (1 shy of min int64 value)
+ dl.fIsPositive = FALSE;
+ {
+ if (!dl.fitsIntoInt64(FALSE)) {
+ errln(fail + "-" + int64maxstr + " didn't fit");
+ }
+ int64_t int64Value = dl.getInt64();
+ if (int64Value != -int64max) {
+ errln(fail + "-" + int64maxstr);
+ }
+ dl.set(int64Value);
+ int64Value = dl.getInt64();
+ if (int64Value != -int64max) {
+ errln(fail + "-" + int64maxstr);
+ }
+ }
+ // test min int64 value
+ setFromString(dl, int64minstr);
+ {
+ if (!dl.fitsIntoInt64(FALSE)) {
+ errln(fail + "-" + int64minstr + " didn't fit");
+ }
+ int64_t int64Value = dl.getInt64();
+ if (int64Value != int64min) {
+ errln(fail + int64minstr);
+ }
+ dl.set(int64Value);
+ int64Value = dl.getInt64();
+ if (int64Value != int64min) {
+ errln(fail + int64minstr);
+ }
+ }
+ // test negative of min int 64 value (1 more than max int64 value)
+ dl.fIsPositive = TRUE; // won't fit
+ {
+ if (dl.fitsIntoInt64(FALSE)) {
+ errln(fail + "-(" + int64minstr + ") didn't fit");
+ }
+ }*/
+}
+
+// -------------------------------------
+
+// Test the handling of quotes
+void
+NumberFormatTest::TestQuotes(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString *pat;
+ DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), status);
+ pat = new UnicodeString("a'fo''o'b#");
+ DecimalFormat *fmt = new DecimalFormat(*pat, *sym, status);
+ UnicodeString s;
+ ((NumberFormat*)fmt)->format((int32_t)123, s);
+ logln((UnicodeString)"Pattern \"" + *pat + "\"");
+ logln((UnicodeString)" Format 123 -> " + escape(s));
+ if (!(s=="afo'ob123"))
+ errln((UnicodeString)"FAIL: Expected afo'ob123");
+
+ s.truncate(0);
+ delete fmt;
+ delete pat;
+
+ pat = new UnicodeString("a''b#");
+ fmt = new DecimalFormat(*pat, *sym, status);
+ ((NumberFormat*)fmt)->format((int32_t)123, s);
+ logln((UnicodeString)"Pattern \"" + *pat + "\"");
+ logln((UnicodeString)" Format 123 -> " + escape(s));
+ if (!(s=="a'b123"))
+ errln((UnicodeString)"FAIL: Expected a'b123");
+ delete fmt;
+ delete pat;
+ delete sym;
+}
+
+/**
+ * Test the handling of the currency symbol in patterns.
+ */
+void
+NumberFormatTest::TestCurrencySign(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale::getUS(), status);
+ UnicodeString pat;
+ UChar currency = 0x00A4;
+ // "\xA4#,##0.00;-\xA4#,##0.00"
+ pat.append(currency).append("#,##0.00;-").
+ append(currency).append("#,##0.00");
+ DecimalFormat *fmt = new DecimalFormat(pat, *sym, status);
+ UnicodeString s; ((NumberFormat*)fmt)->format(1234.56, s);
+ pat.truncate(0);
+ logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
+ logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
+ if (s != "$1,234.56") errln((UnicodeString)"FAIL: Expected $1,234.56");
+ s.truncate(0);
+ ((NumberFormat*)fmt)->format(- 1234.56, s);
+ logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
+ if (s != "-$1,234.56") errln((UnicodeString)"FAIL: Expected -$1,234.56");
+ delete fmt;
+ pat.truncate(0);
+ // "\xA4\xA4 #,##0.00;\xA4\xA4 -#,##0.00"
+ pat.append(currency).append(currency).
+ append(" #,##0.00;").
+ append(currency).append(currency).
+ append(" -#,##0.00");
+ fmt = new DecimalFormat(pat, *sym, status);
+ s.truncate(0);
+ ((NumberFormat*)fmt)->format(1234.56, s);
+ logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
+ logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
+ if (s != "USD 1,234.56") errln((UnicodeString)"FAIL: Expected USD 1,234.56");
+ s.truncate(0);
+ ((NumberFormat*)fmt)->format(-1234.56, s);
+ logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
+ if (s != "USD -1,234.56") errln((UnicodeString)"FAIL: Expected USD -1,234.56");
+ delete fmt;
+ delete sym;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+}
+
+// -------------------------------------
+
+static UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
+
+UnicodeString&
+NumberFormatTest::escape(UnicodeString& s)
+{
+ UnicodeString buf;
+ for (int32_t i=0; i<s.length(); ++i)
+ {
+ UChar c = s[(int32_t)i];
+ if (c <= (UChar)0x7F) buf += c;
+ else {
+ buf += (UChar)0x5c; buf += (UChar)0x55;
+ buf += toHexString((c & 0xF000) >> 12);
+ buf += toHexString((c & 0x0F00) >> 8);
+ buf += toHexString((c & 0x00F0) >> 4);
+ buf += toHexString(c & 0x000F);
+ }
+ }
+ return (s = buf);
+}
+
+
+// -------------------------------------
+static const char* testCases[][2]= {
+ /* locale ID */ /* expected */
+ {"ca_ES_PREEURO", "1.150 \\u20A7" },
+ {"de_LU_PREEURO", "1,150 F" },
+ {"el_GR_PREEURO", "1.150,50\\u0394\\u03C1\\u03C7" },
+ {"en_BE_PREEURO", "1.150,50 BF" },
+ {"es_ES_PREEURO", "1.150 \\u20A7" },
+ {"eu_ES_PREEURO", "1.150 \\u20A7" },
+ {"gl_ES_PREEURO", "1.150 \\u20A7" },
+ {"it_IT_PREEURO", "\\u20A4 1.150" },
+ {"pt_PT_PREEURO", "1,150$50 Esc."},
+ {"en_US@currency=JPY", "\\u00A51,150"}
+};
+/**
+ * Test localized currency patterns.
+ */
+void
+NumberFormatTest::TestCurrency(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(Locale::getCanadaFrench(), status);
+ if (U_FAILURE(status)) {
+ dataerrln("Error calling NumberFormat::createCurrencyInstance()");
+ return;
+ }
+
+ UnicodeString s; currencyFmt->format(1.50, s);
+ logln((UnicodeString)"Un pauvre ici a..........." + s);
+ if (!(s=="1,50 $"))
+ errln((UnicodeString)"FAIL: Expected 1,50 $");
+ delete currencyFmt;
+ s.truncate(0);
+ char loc[256]={0};
+ int len = uloc_canonicalize("de_DE_PREEURO", loc, 256, &status);
+ currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc),status);
+ currencyFmt->format(1.50, s);
+ logln((UnicodeString)"Un pauvre en Allemagne a.." + s);
+ if (!(s=="1,50 DM"))
+ errln((UnicodeString)"FAIL: Expected 1,50 DM");
+ delete currencyFmt;
+ s.truncate(0);
+ len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);
+ currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
+ currencyFmt->format(1.50, s);
+ logln((UnicodeString)"Un pauvre en France a....." + s);
+ if (!(s=="1,50 F"))
+ errln((UnicodeString)"FAIL: Expected 1,50 F");
+ delete currencyFmt;
+ if (U_FAILURE(status))
+ errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+
+ for(int i=0; i < (int)(sizeof(testCases)/sizeof(testCases[i])); i++){
+ status = U_ZERO_ERROR;
+ const char *localeID = testCases[i][0];
+ UnicodeString expected(testCases[i][1]);
+ expected = expected.unescape();
+ s.truncate(0);
+ char loc[256]={0};
+ uloc_canonicalize(localeID, loc, 256, &status);
+ currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
+ if(U_FAILURE(status)){
+ errln("Could not create currency formatter for locale %s",localeID);
+ continue;
+ }
+ currencyFmt->format(1150.50, s);
+ if(s!=expected){
+ errln(UnicodeString("FAIL: Expected: ")+expected
+ + UnicodeString(" Got: ") + s
+ + UnicodeString( " for locale: ")+ UnicodeString(localeID) );
+ }
+ if (U_FAILURE(status)){
+ errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+ }
+ delete currencyFmt;
+ }
+}
+
+// -------------------------------------
+
+/**
+ * Test the Currency object handling, new as of ICU 2.2.
+ */
+void NumberFormatTest::TestCurrencyObject() {
+ UErrorCode ec = U_ZERO_ERROR;
+ NumberFormat* fmt =
+ NumberFormat::createCurrencyInstance(Locale::getUS(), ec);
+
+ if (U_FAILURE(ec)) {
+ errln("FAIL: getCurrencyInstance(US)");
+ delete fmt;
+ return;
+ }
+
+ Locale null("", "", "");
+
+ expectCurrency(*fmt, null, 1234.56, "$1,234.56");
+
+ expectCurrency(*fmt, Locale::getFrance(),
+ 1234.56, CharsToUnicodeString("\\u20AC1,234.56")); // Euro
+
+ expectCurrency(*fmt, Locale::getJapan(),
+ 1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen
+
+ expectCurrency(*fmt, Locale("fr", "CH", ""),
+ 1234.56, "SwF1,234.55"); // 0.05 rounding
+
+ expectCurrency(*fmt, Locale::getUS(),
+ 1234.56, "$1,234.56");
+
+ delete fmt;
+ fmt = NumberFormat::createCurrencyInstance(Locale::getFrance(), ec);
+
+ if (U_FAILURE(ec)) {
+ errln("FAIL: getCurrencyInstance(FRANCE)");
+ delete fmt;
+ return;
+ }
+
+ expectCurrency(*fmt, null, 1234.56, CharsToUnicodeString("1 234,56 \\u20AC"));
+
+ expectCurrency(*fmt, Locale::getJapan(),
+ 1234.56, CharsToUnicodeString("1 235 \\u00A5JP")); // Yen
+
+ expectCurrency(*fmt, Locale("fr", "CH", ""),
+ 1234.56, "1 234,55 sFr."); // 0.05 rounding
+
+ expectCurrency(*fmt, Locale::getUS(),
+ 1234.56, "1 234,56 $US");
+
+ expectCurrency(*fmt, Locale::getFrance(),
+ 1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); // Euro
+
+ delete fmt;
+}
+
+// -------------------------------------
+
+/**
+ * Do rudimentary testing of parsing.
+ */
+void
+NumberFormatTest::TestParse(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString arg("0");
+ DecimalFormat* format = new DecimalFormat("00", status);
+ //try {
+ Formattable n; format->parse(arg, n, status);
+ logln((UnicodeString)"parse(" + arg + ") = " + n.getLong());
+ if (n.getType() != Formattable::kLong ||
+ n.getLong() != 0) errln((UnicodeString)"FAIL: Expected 0");
+ delete format;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+ //}
+ //catch(Exception e) {
+ // errln((UnicodeString)"Exception caught: " + e);
+ //}
+}
+
+// -------------------------------------
+
+/**
+ * Test proper rounding by the format method.
+ */
+void
+NumberFormatTest::TestRounding487(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nf = NumberFormat::createInstance(status);
+ if (U_FAILURE(status)) {
+ dataerrln("Error calling NumberFormat::createInstance()");
+ return;
+ }
+
+ roundingTest(*nf, 0.00159999, 4, "0.0016");
+ roundingTest(*nf, 0.00995, 4, "0.01");
+
+ roundingTest(*nf, 12.3995, 3, "12.4");
+
+ roundingTest(*nf, 12.4999, 0, "12");
+ roundingTest(*nf, - 19.5, 0, "-20");
+ delete nf;
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+}
+
+/**
+ * Test the functioning of the secondary grouping value.
+ */
+void NumberFormatTest::TestSecondaryGrouping(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols ct");
+
+ DecimalFormat f("#,##,###", US, status);
+ CHECK(status, "DecimalFormat ct");
+
+ expect2(f, (int32_t)123456789L, "12,34,56,789");
+ expectPat(f, "#,##,###");
+ f.applyPattern("#,###", status);
+ CHECK(status, "applyPattern");
+
+ f.setSecondaryGroupingSize(4);
+ expect2(f, (int32_t)123456789L, "12,3456,789");
+ expectPat(f, "#,####,###");
+ NumberFormat *g = NumberFormat::createInstance(Locale("hi", "IN"), status);
+ CHECK(status, "createInstance(hi_IN)");
+
+ UnicodeString out;
+ int32_t l = (int32_t)1876543210L;
+ g->format(l, out);
+ delete g;
+ // expect "1,87,65,43,210", but with Hindi digits
+ // 01234567890123
+ UBool ok = TRUE;
+ if (out.length() != 14) {
+ ok = FALSE;
+ } else {
+ for (int32_t i=0; i<out.length(); ++i) {
+ UBool expectGroup = FALSE;
+ switch (i) {
+ case 1:
+ case 4:
+ case 7:
+ case 10:
+ expectGroup = TRUE;
+ break;
+ }
+ // Later -- fix this to get the actual grouping
+ // character from the resource bundle.
+ UBool isGroup = (out.charAt(i) == 0x002C);
+ if (isGroup != expectGroup) {
+ ok = FALSE;
+ break;
+ }
+ }
+ }
+ if (!ok) {
+ errln((UnicodeString)"FAIL Expected " + l +
+ " x hi_IN -> \"1,87,65,43,210\" (with Hindi digits), got \"" +
+ escape(out) + "\"");
+ } else {
+ logln((UnicodeString)"Ok " + l +
+ " x hi_IN -> \"" +
+ escape(out) + "\"");
+ }
+}
+
+void NumberFormatTest::TestWhiteSpaceParsing(void) {
+ UErrorCode ec = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), ec);
+ DecimalFormat fmt("a b#0c ", US, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Constructor");
+ return;
+ }
+ int32_t n = 1234;
+ expect(fmt, "a b1234c ", n);
+ expect(fmt, "a b1234c ", n);
+}
+
+/**
+ * Test currencies whose display name is a ChoiceFormat.
+ */
+void NumberFormatTest::TestComplexCurrency() {
+ UErrorCode ec = U_ZERO_ERROR;
+ Locale loc("en", "IN", "");
+ NumberFormat* fmt = NumberFormat::createCurrencyInstance(loc, ec);
+ if (U_SUCCESS(ec)) {
+ expect2(*fmt, 1.0, "Re. 1.00");
+ // Use .00392625 because that's 2^-8. Any value less than 0.005 is fine.
+ expect(*fmt, 1.00390625, "Re. 1.00"); // tricky
+ expect2(*fmt, 12345678.0, "Rs. 1,23,45,678.00");
+ expect2(*fmt, 0.5, "Rs. 0.50");
+ expect2(*fmt, -1.0, "-Re. 1.00");
+ expect2(*fmt, -10.0, "-Rs. 10.00");
+ } else {
+ errln("FAIL: getCurrencyInstance(en_IN)");
+ }
+ delete fmt;
+}
+
+// -------------------------------------
+
+void
+NumberFormatTest::roundingTest(NumberFormat& nf, double x, int32_t maxFractionDigits, const char* expected)
+{
+ nf.setMaximumFractionDigits(maxFractionDigits);
+ UnicodeString out; nf.format(x, out);
+ logln((UnicodeString)"" + x + " formats with " + maxFractionDigits + " fractional digits to " + out);
+ if (!(out==expected)) errln((UnicodeString)"FAIL: Expected " + expected);
+}
+
+/**
+ * Upgrade to alphaWorks
+ */
+void NumberFormatTest::TestExponent(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+ DecimalFormat fmt1(UnicodeString("0.###E0"), US, status);
+ CHECK(status, "DecimalFormat(0.###E0)");
+ DecimalFormat fmt2(UnicodeString("0.###E+0"), US, status);
+ CHECK(status, "DecimalFormat(0.###E+0)");
+ int32_t n = 1234;
+ expect2(fmt1, n, "1.234E3");
+ expect2(fmt2, n, "1.234E+3");
+ expect(fmt1, "1.234E+3", n); // Either format should parse "E+3"
+}
+
+/**
+ * Upgrade to alphaWorks
+ */
+void NumberFormatTest::TestScientific(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+
+ // Test pattern round-trip
+ const char* PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000",
+ "0.###E0;[0.###E0]" };
+ int32_t PAT_length = (int32_t)(sizeof(PAT) / sizeof(PAT[0]));
+ int32_t DIGITS[] = {
+ // min int, max int, min frac, max frac
+ 0, 1, 0, 0, // "#E0"
+ 1, 1, 0, 4, // "0.####E0"
+ 2, 2, 3, 3, // "00.000E00"
+ 1, 3, 0, 4, // "##0.####E000"
+ 1, 1, 0, 3, // "0.###E0;[0.###E0]"
+ };
+ for (int32_t i=0; i<PAT_length; ++i) {
+ UnicodeString pat(PAT[i]);
+ DecimalFormat df(pat, US, status);
+ CHECK(status, "DecimalFormat constructor");
+ UnicodeString pat2;
+ df.toPattern(pat2);
+ if (pat == pat2) {
+ logln(UnicodeString("Ok Pattern rt \"") +
+ pat + "\" -> \"" +
+ pat2 + "\"");
+ } else {
+ errln(UnicodeString("FAIL Pattern rt \"") +
+ pat + "\" -> \"" +
+ pat2 + "\"");
+ }
+ // Make sure digit counts match what we expect
+ if (df.getMinimumIntegerDigits() != DIGITS[4*i] ||
+ df.getMaximumIntegerDigits() != DIGITS[4*i+1] ||
+ df.getMinimumFractionDigits() != DIGITS[4*i+2] ||
+ df.getMaximumFractionDigits() != DIGITS[4*i+3]) {
+ errln(UnicodeString("FAIL \"" + pat +
+ "\" min/max int; min/max frac = ") +
+ df.getMinimumIntegerDigits() + "/" +
+ df.getMaximumIntegerDigits() + ";" +
+ df.getMinimumFractionDigits() + "/" +
+ df.getMaximumFractionDigits() + ", expect " +
+ DIGITS[4*i] + "/" +
+ DIGITS[4*i+1] + ";" +
+ DIGITS[4*i+2] + "/" +
+ DIGITS[4*i+3]);
+ }
+ }
+
+
+ // Test the constructor for default locale. We have to
+ // manually set the default locale, as there is no
+ // guarantee that the default locale has the same
+ // scientific format.
+ Locale def = Locale::getDefault();
+ Locale::setDefault(Locale::getUS(), status);
+ expect2(NumberFormat::createScientificInstance(status),
+ 12345.678901,
+ "1.2345678901E4", status);
+ Locale::setDefault(def, status);
+
+ expect2(new DecimalFormat("#E0", US, status),
+ 12345.0,
+ "1.2345E4", status);
+ expect(new DecimalFormat("0E0", US, status),
+ 12345.0,
+ "1E4", status);
+ expect2(NumberFormat::createScientificInstance(Locale::getUS(), status),
+ 12345.678901,
+ "1.2345678901E4", status);
+ expect(new DecimalFormat("##0.###E0", US, status),
+ 12345.0,
+ "12.34E3", status);
+ expect(new DecimalFormat("##0.###E0", US, status),
+ 12345.00001,
+ "12.35E3", status);
+ expect2(new DecimalFormat("##0.####E0", US, status),
+ (int32_t) 12345,
+ "12.345E3", status);
+ expect2(NumberFormat::createScientificInstance(Locale::getFrance(), status),
+ 12345.678901,
+ "1,2345678901E4", status);
+ expect(new DecimalFormat("##0.####E0", US, status),
+ 789.12345e-9,
+ "789.12E-9", status);
+ expect2(new DecimalFormat("##0.####E0", US, status),
+ 780.e-9,
+ "780E-9", status);
+ expect(new DecimalFormat(".###E0", US, status),
+ 45678.0,
+ ".457E5", status);
+ expect2(new DecimalFormat(".###E0", US, status),
+ (int32_t) 0,
+ ".0E0", status);
+ /*
+ expect(new DecimalFormat[] { new DecimalFormat("#E0", US),
+ new DecimalFormat("##E0", US),
+ new DecimalFormat("####E0", US),
+ new DecimalFormat("0E0", US),
+ new DecimalFormat("00E0", US),
+ new DecimalFormat("000E0", US),
+ },
+ new Long(45678000),
+ new String[] { "4.5678E7",
+ "45.678E6",
+ "4567.8E4",
+ "5E7",
+ "46E6",
+ "457E5",
+ }
+ );
+ !
+ ! Unroll this test into individual tests below...
+ !
+ */
+ expect2(new DecimalFormat("#E0", US, status),
+ (int32_t) 45678000, "4.5678E7", status);
+ expect2(new DecimalFormat("##E0", US, status),
+ (int32_t) 45678000, "45.678E6", status);
+ expect2(new DecimalFormat("####E0", US, status),
+ (int32_t) 45678000, "4567.8E4", status);
+ expect(new DecimalFormat("0E0", US, status),
+ (int32_t) 45678000, "5E7", status);
+ expect(new DecimalFormat("00E0", US, status),
+ (int32_t) 45678000, "46E6", status);
+ expect(new DecimalFormat("000E0", US, status),
+ (int32_t) 45678000, "457E5", status);
+ /*
+ expect(new DecimalFormat("###E0", US, status),
+ new Object[] { new Double(0.0000123), "12.3E-6",
+ new Double(0.000123), "123E-6",
+ new Double(0.00123), "1.23E-3",
+ new Double(0.0123), "12.3E-3",
+ new Double(0.123), "123E-3",
+ new Double(1.23), "1.23E0",
+ new Double(12.3), "12.3E0",
+ new Double(123), "123E0",
+ new Double(1230), "1.23E3",
+ });
+ !
+ ! Unroll this test into individual tests below...
+ !
+ */
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.0000123, "12.3E-6", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.000123, "123E-6", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.00123, "1.23E-3", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.0123, "12.3E-3", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 0.123, "123E-3", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 1.23, "1.23E0", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 12.3, "12.3E0", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 123.0, "123E0", status);
+ expect2(new DecimalFormat("###E0", US, status),
+ 1230.0, "1.23E3", status);
+ /*
+ expect(new DecimalFormat("0.#E+00", US, status),
+ new Object[] { new Double(0.00012), "1.2E-04",
+ new Long(12000), "1.2E+04",
+ });
+ !
+ ! Unroll this test into individual tests below...
+ !
+ */
+ expect2(new DecimalFormat("0.#E+00", US, status),
+ 0.00012, "1.2E-04", status);
+ expect2(new DecimalFormat("0.#E+00", US, status),
+ (int32_t) 12000, "1.2E+04", status);
+}
+
+/**
+ * Upgrade to alphaWorks
+ */
+void NumberFormatTest::TestPad(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+
+ expect2(new DecimalFormat("*^##.##", US, status),
+ int32_t(0), "^^^^0", status);
+ expect2(new DecimalFormat("*^##.##", US, status),
+ -1.3, "^-1.3", status);
+ expect2(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
+ int32_t(0), "0.0E0______ g-m/s^2", status);
+ expect(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
+ 1.0/3, "333.333E-3_ g-m/s^2", status);
+ expect2(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
+ int32_t(0), "0.0______ g-m/s^2", status);
+ expect(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
+ 1.0/3, "0.33333__ g-m/s^2", status);
+
+ // Test padding before a sign
+ const char *formatStr = "*x#,###,###,##0.0#;*x(###,###,##0.0#)";
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(-10), "xxxxxxxxxx(10.0)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(-1000),"xxxxxxx(1,000.0)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(-1000000),"xxx(1,000,000.0)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -100.37, "xxxxxxxx(100.37)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -10456.37, "xxxxx(10,456.37)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -1120456.37, "xx(1,120,456.37)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -112045600.37, "(112,045,600.37)", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ -1252045600.37,"(1,252,045,600.37)", status);
+
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(10), "xxxxxxxxxxxx10.0", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(1000),"xxxxxxxxx1,000.0", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ int32_t(1000000),"xxxxx1,000,000.0", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 100.37, "xxxxxxxxxx100.37", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 10456.37, "xxxxxxx10,456.37", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 1120456.37, "xxxx1,120,456.37", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 112045600.37, "xx112,045,600.37", status);
+ expect2(new DecimalFormat(formatStr, US, status),
+ 10252045600.37,"10,252,045,600.37", status);
+
+
+ // Test padding between a sign and a number
+ const char *formatStr2 = "#,###,###,##0.0#*x;(###,###,##0.0#*x)";
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(-10), "(10.0xxxxxxxxxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(-1000),"(1,000.0xxxxxxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(-1000000),"(1,000,000.0xxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -100.37, "(100.37xxxxxxxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -10456.37, "(10,456.37xxxxx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -1120456.37, "(1,120,456.37xx)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -112045600.37, "(112,045,600.37)", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ -1252045600.37,"(1,252,045,600.37)", status);
+
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(10), "10.0xxxxxxxxxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(1000),"1,000.0xxxxxxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ int32_t(1000000),"1,000,000.0xxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 100.37, "100.37xxxxxxxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 10456.37, "10,456.37xxxxxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 1120456.37, "1,120,456.37xxxx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 112045600.37, "112,045,600.37xx", status);
+ expect2(new DecimalFormat(formatStr2, US, status),
+ 10252045600.37,"10,252,045,600.37", status);
+
+ //testing the setPadCharacter(UnicodeString) and getPadCharacterString()
+ DecimalFormat fmt("#", US, status);
+ CHECK(status, "DecimalFormat constructor");
+ UnicodeString padString("P");
+ fmt.setPadCharacter(padString);
+ expectPad(fmt, "*P##.##", DecimalFormat::kPadBeforePrefix, 5, padString);
+ fmt.setPadCharacter((UnicodeString)"^");
+ expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, (UnicodeString)"^");
+ //commented untill implementation is complete
+ /* fmt.setPadCharacter((UnicodeString)"^^^");
+ expectPad(fmt, "*^^^#", DecimalFormat::kPadBeforePrefix, 3, (UnicodeString)"^^^");
+ padString.remove();
+ padString.append((UChar)0x0061);
+ padString.append((UChar)0x0302);
+ fmt.setPadCharacter(padString);
+ UChar patternChars[]={0x002a, 0x0061, 0x0302, 0x0061, 0x0302, 0x0023, 0x0000};
+ UnicodeString pattern(patternChars);
+ expectPad(fmt, pattern , DecimalFormat::kPadBeforePrefix, 4, padString);
+ */
+
+}
+
+/**
+ * Upgrade to alphaWorks
+ */
+void NumberFormatTest::TestPatterns2(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+
+ DecimalFormat fmt("#", US, status);
+ CHECK(status, "DecimalFormat constructor");
+
+ UChar hat = 0x005E; /*^*/
+
+ expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, hat);
+ expectPad(fmt, "$*^#", DecimalFormat::kPadAfterPrefix, 2, hat);
+ expectPad(fmt, "#*^", DecimalFormat::kPadBeforeSuffix, 1, hat);
+ expectPad(fmt, "#$*^", DecimalFormat::kPadAfterSuffix, 2, hat);
+ expectPad(fmt, "$*^$#", ILLEGAL);
+ expectPad(fmt, "#$*^$", ILLEGAL);
+ expectPad(fmt, "'pre'#,##0*x'post'", DecimalFormat::kPadBeforeSuffix,
+ 12, (UChar)0x0078 /*x*/);
+ expectPad(fmt, "''#0*x", DecimalFormat::kPadBeforeSuffix,
+ 3, (UChar)0x0078 /*x*/);
+ expectPad(fmt, "'I''ll'*a###.##", DecimalFormat::kPadAfterPrefix,
+ 10, (UChar)0x0061 /*a*/);
+
+ fmt.applyPattern("AA#,##0.00ZZ", status);
+ CHECK(status, "applyPattern");
+ fmt.setPadCharacter(hat);
+
+ fmt.setFormatWidth(10);
+
+ fmt.setPadPosition(DecimalFormat::kPadBeforePrefix);
+ expectPat(fmt, "*^AA#,##0.00ZZ");
+
+ fmt.setPadPosition(DecimalFormat::kPadBeforeSuffix);
+ expectPat(fmt, "AA#,##0.00*^ZZ");
+
+ fmt.setPadPosition(DecimalFormat::kPadAfterSuffix);
+ expectPat(fmt, "AA#,##0.00ZZ*^");
+
+ // 12 3456789012
+ UnicodeString exp("AA*^#,##0.00ZZ", "");
+ fmt.setFormatWidth(12);
+ fmt.setPadPosition(DecimalFormat::kPadAfterPrefix);
+ expectPat(fmt, exp);
+
+ fmt.setFormatWidth(13);
+ // 12 34567890123
+ expectPat(fmt, "AA*^##,##0.00ZZ");
+
+ fmt.setFormatWidth(14);
+ // 12 345678901234
+ expectPat(fmt, "AA*^###,##0.00ZZ");
+
+ fmt.setFormatWidth(15);
+ // 12 3456789012345
+ expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case
+
+ fmt.setFormatWidth(16);
+ // 12 34567890123456
+ expectPat(fmt, "AA*^#,###,##0.00ZZ");
+}
+
+void NumberFormatTest::TestSurrogateSupport(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols custom(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+
+ custom.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, "decimal");
+ custom.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, "plus");
+ custom.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, " minus ");
+ custom.setSymbol(DecimalFormatSymbols::kExponentialSymbol, "exponent");
+
+ UnicodeString patternStr("*\\U00010000##.##", "");
+ patternStr = patternStr.unescape();
+ UnicodeString expStr("\\U00010000\\U00010000\\U00010000\\U000100000", "");
+ expStr = expStr.unescape();
+ expect2(new DecimalFormat(patternStr, custom, status),
+ int32_t(0), expStr, status);
+
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("*^##.##", custom, status),
+ int32_t(0), "^^^^0", status);
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("##.##", custom, status),
+ -1.3, " minus 1decimal3", status);
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
+ int32_t(0), "0decimal0exponent0 g-m/s^2", status);
+ status = U_ZERO_ERROR;
+ expect(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
+ 1.0/3, "333decimal333exponent minus 3 g-m/s^2", status);
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
+ int32_t(0), "0decimal0 g-m/s^2", status);
+ status = U_ZERO_ERROR;
+ expect(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
+ 1.0/3, "0decimal33333 g-m/s^2", status);
+
+ UnicodeString zero((UChar32)0x10000);
+ custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, zero);
+ expStr = UnicodeString("\\U00010001decimal\\U00010002\\U00010005\\U00010000", "");
+ expStr = expStr.unescape();
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat("##0.000", custom, status),
+ 1.25, expStr, status);
+
+ custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, (UChar)0x30);
+ custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "units of money");
+ custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, "money separator");
+ patternStr = "0.00 \\u00A4' in your bank account'";
+ patternStr = patternStr.unescape();
+ expStr = UnicodeString(" minus 20money separator00 units of money in your bank account", "");
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat(patternStr, custom, status),
+ int32_t(-20), expStr, status);
+
+ custom.setSymbol(DecimalFormatSymbols::kPercentSymbol, "percent");
+ patternStr = "'You''ve lost ' -0.00 %' of your money today'";
+ patternStr = patternStr.unescape();
+ expStr = UnicodeString(" minus You've lost minus 2000decimal00 percent of your money today", "");
+ status = U_ZERO_ERROR;
+ expect2(new DecimalFormat(patternStr, custom, status),
+ int32_t(-20), expStr, status);
+}
+
+void NumberFormatTest::TestCurrencyPatterns(void) {
+ int32_t i, locCount;
+ const Locale* locs = NumberFormat::getAvailableLocales(locCount);
+ for (i=0; i<locCount; ++i) {
+ UErrorCode ec = U_ZERO_ERROR;
+ NumberFormat* nf = NumberFormat::createCurrencyInstance(locs[i], ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Can't create NumberFormat(%s) - %s", locs[i].getName(), u_errorName(ec));
+ } else {
+ // Make sure currency formats do not have a variable number
+ // of fraction digits
+ int32_t min = nf->getMinimumFractionDigits();
+ int32_t max = nf->getMaximumFractionDigits();
+ if (min != max) {
+ UnicodeString a, b;
+ nf->format(1.0, a);
+ nf->format(1.125, b);
+ errln((UnicodeString)"FAIL: " + locs[i].getName() +
+ " min fraction digits != max fraction digits; "
+ "x 1.0 => " + escape(a) +
+ "; x 1.125 => " + escape(b));
+ }
+
+ // Make sure EURO currency formats have exactly 2 fraction digits
+ if (nf->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
+ DecimalFormat* df = (DecimalFormat*) nf;
+ if (u_strcmp(EUR, df->getCurrency()) == 0) {
+ if (min != 2 || max != 2) {
+ UnicodeString a;
+ nf->format(1.0, a);
+ errln((UnicodeString)"FAIL: " + locs[i].getName() +
+ " is a EURO format but it does not have 2 fraction digits; "
+ "x 1.0 => " +
+ escape(a));
+ }
+ }
+ }
+ }
+ delete nf;
+ }
+}
+
+void NumberFormatTest::TestRegCurrency(void) {
+#if !UCONFIG_NO_SERVICE
+ UErrorCode status = U_ZERO_ERROR;
+ UChar USD[4];
+ ucurr_forLocale("en_US", USD, 4, &status);
+ UChar YEN[4];
+ ucurr_forLocale("ja_JP", YEN, 4, &status);
+ UChar TMP[4];
+ static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
+ if(U_FAILURE(status)) {
+ errln("Unable to get currency for locale, error %s", u_errorName(status));
+ return;
+ }
+
+ UCurrRegistryKey enkey = ucurr_register(YEN, "en_US", &status);
+ UCurrRegistryKey enUSEUROkey = ucurr_register(QQQ, "en_US_EURO", &status);
+
+ ucurr_forLocale("en_US", TMP, 4, &status);
+ if (u_strcmp(YEN, TMP) != 0) {
+ errln("FAIL: didn't return YEN registered for en_US");
+ }
+
+ ucurr_forLocale("en_US_EURO", TMP, 4, &status);
+ if (u_strcmp(QQQ, TMP) != 0) {
+ errln("FAIL: didn't return QQQ for en_US_EURO");
+ }
+
+ int32_t fallbackLen = ucurr_forLocale("en_XX_BAR", TMP, 4, &status);
+ if (fallbackLen) {
+ errln("FAIL: tried to fallback en_XX_BAR");
+ }
+ status = U_ZERO_ERROR; // reset
+
+ if (!ucurr_unregister(enkey, &status)) {
+ errln("FAIL: couldn't unregister enkey");
+ }
+
+ ucurr_forLocale("en_US", TMP, 4, &status);
+ if (u_strcmp(USD, TMP) != 0) {
+ errln("FAIL: didn't return USD for en_US after unregister of en_US");
+ }
+ status = U_ZERO_ERROR; // reset
+
+ ucurr_forLocale("en_US_EURO", TMP, 4, &status);
+ if (u_strcmp(QQQ, TMP) != 0) {
+ errln("FAIL: didn't return QQQ for en_US_EURO after unregister of en_US");
+ }
+
+ ucurr_forLocale("en_US_BLAH", TMP, 4, &status);
+ if (u_strcmp(USD, TMP) != 0) {
+ errln("FAIL: could not find USD for en_US_BLAH after unregister of en");
+ }
+ status = U_ZERO_ERROR; // reset
+
+ if (!ucurr_unregister(enUSEUROkey, &status)) {
+ errln("FAIL: couldn't unregister enUSEUROkey");
+ }
+
+ ucurr_forLocale("en_US_EURO", TMP, 4, &status);
+ if (u_strcmp(EUR, TMP) != 0) {
+ errln("FAIL: didn't return EUR for en_US_EURO after unregister of en_US_EURO");
+ }
+ status = U_ZERO_ERROR; // reset
+#endif
+}
+
+void NumberFormatTest::TestCurrencyNames(void) {
+ // Do a basic check of getName()
+ // USD { "US$", "US Dollar" } // 04/04/1792-
+ UErrorCode ec = U_ZERO_ERROR;
+ static const UChar USD[] = {0x55, 0x53, 0x44, 0}; /*USD*/
+ static const UChar USX[] = {0x55, 0x53, 0x58, 0}; /*USX*/
+ static const UChar CAD[] = {0x43, 0x41, 0x44, 0}; /*CAD*/
+ static const UChar ITL[] = {0x49, 0x54, 0x4C, 0}; /*ITL*/
+ UBool isChoiceFormat;
+ int32_t len;
+ // Warning: HARD-CODED LOCALE DATA in this test. If it fails, CHECK
+ // THE LOCALE DATA before diving into the code.
+ assertEquals("USD.getName(SYMBOL_NAME)",
+ UnicodeString("$"),
+ UnicodeString(ucurr_getName(USD, "en",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("USD.getName(LONG_NAME)",
+ UnicodeString("US Dollar"),
+ UnicodeString(ucurr_getName(USD, "en",
+ UCURR_LONG_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("CAD.getName(SYMBOL_NAME)",
+ UnicodeString("Can$"),
+ UnicodeString(ucurr_getName(CAD, "en",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("CAD.getName(SYMBOL_NAME)",
+ UnicodeString("$"),
+ UnicodeString(ucurr_getName(CAD, "en_CA",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("USD.getName(SYMBOL_NAME)",
+ UnicodeString("US$"),
+ UnicodeString(ucurr_getName(USD, "en_AU",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("CAD.getName(SYMBOL_NAME)",
+ UnicodeString("Can$"),
+ UnicodeString(ucurr_getName(CAD, "en_AU",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertEquals("USX.getName(LONG_NAME)",
+ UnicodeString("USX"),
+ UnicodeString(ucurr_getName(USX, "en_US",
+ UCURR_LONG_NAME,
+ &isChoiceFormat, &len, &ec)));
+ assertSuccess("ucurr_getName", ec);
+
+ ec = U_ZERO_ERROR;
+
+ // Test that a default or fallback warning is being returned. JB 4239.
+ ucurr_getName(CAD, "es_ES", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (fallback)",
+ U_USING_FALLBACK_WARNING == ec, TRUE);
+
+ ucurr_getName(CAD, "zh_TW", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (fallback)",
+ U_USING_FALLBACK_WARNING == ec, TRUE);
+
+ ucurr_getName(CAD, "en_US", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (default)",
+ U_USING_DEFAULT_WARNING == ec, TRUE);
+
+ ucurr_getName(CAD, "vi", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (default)",
+ U_USING_DEFAULT_WARNING == ec, TRUE);
+
+ // Test that a default warning is being returned when falling back to root. JB 4536.
+ ucurr_getName(ITL, "cy", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (default to root)",
+ U_USING_DEFAULT_WARNING == ec, TRUE);
+
+ // TODO add more tests later
+}
+
+void NumberFormatTest::TestCurrencyUnit(void){
+ UErrorCode ec = U_ZERO_ERROR;
+ static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
+ CurrencyUnit cu(USD, ec);
+ assertSuccess("CurrencyUnit", ec);
+
+ const UChar * r = cu.getISOCurrency(); // who is the buffer owner ?
+ assertEquals("getISOCurrency()", USD, r);
+
+ CurrencyUnit cu2(cu);
+ if (!(cu2 == cu)){
+ errln("CurrencyUnit copy constructed object should be same");
+ }
+
+ CurrencyUnit * cu3 = (CurrencyUnit *)cu.clone();
+ if (!(*cu3 == cu)){
+ errln("CurrencyUnit cloned object should be same");
+ }
+ delete cu3;
+}
+
+void NumberFormatTest::TestCurrencyAmount(void){
+ UErrorCode ec = U_ZERO_ERROR;
+ static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
+ CurrencyAmount ca(9, USD, ec);
+ assertSuccess("CurrencyAmount", ec);
+
+ CurrencyAmount ca2(ca);
+ if (!(ca2 == ca)){
+ errln("CurrencyAmount copy constructed object should be same");
+ }
+
+ ca2=ca;
+ if (!(ca2 == ca)){
+ errln("CurrencyAmount assigned object should be same");
+ }
+
+ CurrencyAmount *ca3 = (CurrencyAmount *)ca.clone();
+ if (!(*ca3 == ca)){
+ errln("CurrencyAmount cloned object should be same");
+ }
+ delete ca3;
+}
+
+void NumberFormatTest::TestSymbolsWithBadLocale(void) {
+ Locale locDefault;
+ Locale locBad("x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME");
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString intlCurrencySymbol((UChar)0xa4);
+
+ intlCurrencySymbol.append((UChar)0xa4);
+
+ logln("Current locale is %s", Locale::getDefault().getName());
+ Locale::setDefault(locBad, status);
+ logln("Current locale is %s", Locale::getDefault().getName());
+ DecimalFormatSymbols mySymbols(status);
+ if (status != U_USING_FALLBACK_WARNING) {
+ errln("DecimalFormatSymbols should returned U_USING_FALLBACK_WARNING.");
+ }
+ if (strcmp(mySymbols.getLocale().getName(), locBad.getName()) != 0) {
+ errln("DecimalFormatSymbols does not have the right locale.");
+ }
+ int symbolEnum = (int)DecimalFormatSymbols::kDecimalSeparatorSymbol;
+ for (; symbolEnum < (int)DecimalFormatSymbols::kFormatSymbolCount; symbolEnum++) {
+ logln(UnicodeString("DecimalFormatSymbols[") + symbolEnum + UnicodeString("] = ")
+ + prettify(mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum)));
+
+ if (mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum).length() == 0
+ && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol
+ && symbolEnum != (int)DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol)
+ {
+ errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum);
+ }
+ }
+ status = U_ZERO_ERROR;
+ Locale::setDefault(locDefault, status);
+ logln("Current locale is %s", Locale::getDefault().getName());
+}
+
+/**
+ * Check that adoptDecimalFormatSymbols and setDecimalFormatSymbols
+ * behave the same, except for memory ownership semantics. (No
+ * version of this test on Java, since Java has only one method.)
+ */
+void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) {
+ UErrorCode ec = U_ZERO_ERROR;
+ DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormatSymbols constructor");
+ delete sym;
+ return;
+ }
+ UnicodeString pat(" #,##0.00");
+ pat.insert(0, (UChar)0x00A4);
+ DecimalFormat fmt(pat, sym, ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormat constructor");
+ return;
+ }
+
+ UnicodeString str;
+ fmt.format(2350.75, str);
+ if (str == "$ 2,350.75") {
+ logln(str);
+ } else {
+ errln("Fail: " + str + ", expected $ 2,350.75");
+ }
+
+ sym = new DecimalFormatSymbols(Locale::getUS(), ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormatSymbols constructor");
+ delete sym;
+ return;
+ }
+ sym->setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
+ fmt.adoptDecimalFormatSymbols(sym);
+
+ str.truncate(0);
+ fmt.format(2350.75, str);
+ if (str == "Q 2,350.75") {
+ logln(str);
+ } else {
+ errln("Fail: adoptDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
+ }
+
+ sym = new DecimalFormatSymbols(Locale::getUS(), ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormatSymbols constructor");
+ delete sym;
+ return;
+ }
+ DecimalFormat fmt2(pat, sym, ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormat constructor");
+ return;
+ }
+
+ DecimalFormatSymbols sym2(Locale::getUS(), ec);
+ if (U_FAILURE(ec)) {
+ errln("Fail: DecimalFormatSymbols constructor");
+ return;
+ }
+ sym2.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
+ fmt2.setDecimalFormatSymbols(sym2);
+
+ str.truncate(0);
+ fmt2.format(2350.75, str);
+ if (str == "Q 2,350.75") {
+ logln(str);
+ } else {
+ errln("Fail: setDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
+ }
+}
+
+void NumberFormatTest::TestPerMill() {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString str;
+ DecimalFormat fmt(ctou("###.###\\u2030"), ec);
+ if (!assertSuccess("DecimalFormat ct", ec)) return;
+ assertEquals("0.4857 x ###.###\\u2030",
+ ctou("485.7\\u2030"), fmt.format(0.4857, str));
+
+ DecimalFormatSymbols sym(Locale::getUS(), ec);
+ sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, ctou("m"));
+ DecimalFormat fmt2("", sym, ec);
+ fmt2.applyLocalizedPattern("###.###m", ec);
+ if (!assertSuccess("setup", ec)) return;
+ str.truncate(0);
+ assertEquals("0.4857 x ###.###m",
+ "485.7m", fmt2.format(0.4857, str));
+}
+
+/**
+ * Generic test for patterns that should be legal/illegal.
+ */
+void NumberFormatTest::TestIllegalPatterns() {
+ // Test cases:
+ // Prefix with "-:" for illegal patterns
+ // Prefix with "+:" for legal patterns
+ const char* DATA[] = {
+ // Unquoted special characters in the suffix are illegal
+ "-:000.000|###",
+ "+:000.000'|###'",
+ 0
+ };
+ for (int32_t i=0; DATA[i]; ++i) {
+ const char* pat=DATA[i];
+ UBool valid = (*pat) == '+';
+ pat += 2;
+ UErrorCode ec = U_ZERO_ERROR;
+ DecimalFormat fmt(pat, ec); // locale doesn't matter here
+ if (U_SUCCESS(ec) == valid) {
+ logln("Ok: pattern \"%s\": %s",
+ pat, u_errorName(ec));
+ } else {
+ errln("FAIL: pattern \"%s\" should have %s; got %s",
+ pat, (valid?"succeeded":"failed"),
+ u_errorName(ec));
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+
+static const char* KEYWORDS[] = {
+ /*0*/ "ref=", // <reference pattern to parse numbers>
+ /*1*/ "loc=", // <locale for formats>
+ /*2*/ "f:", // <pattern or '-'> <number> <exp. string>
+ /*3*/ "fp:", // <pattern or '-'> <number> <exp. string> <exp. number>
+ /*4*/ "rt:", // <pattern or '-'> <(exp.) number> <(exp.) string>
+ /*5*/ "p:", // <pattern or '-'> <string> <exp. number>
+ /*6*/ "perr:", // <pattern or '-'> <invalid string>
+ /*7*/ "pat:", // <pattern or '-'> <exp. toPattern or '-' or 'err'>
+ /*8*/ "fpc:", // <pattern or '-'> <curr.amt> <exp. string> <exp. curr.amt>
+ 0
+};
+
+/**
+ * Return an integer representing the next token from this
+ * iterator. The integer will be an index into the given list, or
+ * -1 if there are no more tokens, or -2 if the token is not on
+ * the list.
+ */
+static int32_t keywordIndex(const UnicodeString& tok) {
+ for (int32_t i=0; KEYWORDS[i]!=0; ++i) {
+ if (tok==KEYWORDS[i]) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Parse a CurrencyAmount using the given NumberFormat, with
+ * the 'delim' character separating the number and the currency.
+ */
+static void parseCurrencyAmount(const UnicodeString& str,
+ const NumberFormat& fmt,
+ UChar delim,
+ Formattable& result,
+ UErrorCode& ec) {
+ UnicodeString num, cur;
+ int32_t i = str.indexOf(delim);
+ str.extractBetween(0, i, num);
+ str.extractBetween(i+1, INT32_MAX, cur);
+ Formattable n;
+ fmt.parse(num, n, ec);
+ result.adoptObject(new CurrencyAmount(n, cur.getTerminatedBuffer(), ec));
+}
+
+void NumberFormatTest::TestCases() {
+ UErrorCode ec = U_ZERO_ERROR;
+ TextFile reader("NumberFormatTestCases.txt", "UTF8", ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Couldn't open NumberFormatTestCases.txt");
+ return;
+ }
+ TokenIterator tokens(&reader);
+
+ Locale loc("en", "US", "");
+ DecimalFormat *ref = 0, *fmt = 0;
+ MeasureFormat *mfmt = 0;
+ UnicodeString pat, tok, mloc, str, out, where, currAmt;
+ Formattable n;
+
+ for (;;) {
+ ec = U_ZERO_ERROR;
+ if (!tokens.next(tok, ec)) {
+ break;
+ }
+ where = UnicodeString("(") + tokens.getLineNumber() + ") ";
+ int32_t cmd = keywordIndex(tok);
+ switch (cmd) {
+ case 0:
+ // ref= <reference pattern>
+ if (!tokens.next(tok, ec)) goto error;
+ delete ref;
+ ref = new DecimalFormat(tok,
+ new DecimalFormatSymbols(Locale::getUS(), ec), ec);
+ if (U_FAILURE(ec)) {
+ dataerrln("Error constructing DecimalFormat");
+ goto error;
+ }
+ break;
+ case 1:
+ // loc= <locale>
+ if (!tokens.next(tok, ec)) goto error;
+ loc = Locale::createFromName(CharString(tok));
+ break;
+ case 2: // f:
+ case 3: // fp:
+ case 4: // rt:
+ case 5: // p:
+ if (!tokens.next(tok, ec)) goto error;
+ if (tok != "-") {
+ pat = tok;
+ delete fmt;
+ fmt = new DecimalFormat(pat, new DecimalFormatSymbols(loc, ec), ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: " + where + "Pattern \"" + pat + "\": " + u_errorName(ec));
+ ec = U_ZERO_ERROR;
+ if (!tokens.next(tok, ec)) goto error;
+ if (!tokens.next(tok, ec)) goto error;
+ if (cmd == 3) {
+ if (!tokens.next(tok, ec)) goto error;
+ }
+ continue;
+ }
+ }
+ if (cmd == 2 || cmd == 3 || cmd == 4) {
+ // f: <pattern or '-'> <number> <exp. string>
+ // fp: <pattern or '-'> <number> <exp. string> <exp. number>
+ // rt: <pattern or '-'> <number> <string>
+ UnicodeString num;
+ if (!tokens.next(num, ec)) goto error;
+ if (!tokens.next(str, ec)) goto error;
+ ref->parse(num, n, ec);
+ assertSuccess("parse", ec);
+ assertEquals(where + "\"" + pat + "\".format(" + num + ")",
+ str, fmt->format(n, out.remove(), ec));
+ assertSuccess("format", ec);
+ if (cmd == 3) { // fp:
+ if (!tokens.next(num, ec)) goto error;
+ ref->parse(num, n, ec);
+ assertSuccess("parse", ec);
+ }
+ if (cmd != 2) { // != f:
+ Formattable m;
+ fmt->parse(str, m, ec);
+ assertSuccess("parse", ec);
+ assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
+ n, m);
+ }
+ }
+ // p: <pattern or '-'> <string to parse> <exp. number>
+ else {
+ UnicodeString expstr;
+ if (!tokens.next(str, ec)) goto error;
+ if (!tokens.next(expstr, ec)) goto error;
+ Formattable exp, n;
+ ref->parse(expstr, exp, ec);
+ assertSuccess("parse", ec);
+ fmt->parse(str, n, ec);
+ assertSuccess("parse", ec);
+ assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
+ exp, n);
+ }
+ break;
+ case 8: // fpc:
+ if (!tokens.next(tok, ec)) goto error;
+ if (tok != "-") {
+ mloc = tok;
+ delete mfmt;
+ mfmt = MeasureFormat::createCurrencyFormat(
+ Locale::createFromName(CharString(mloc)), ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: " + where + "Loc \"" + mloc + "\": " + u_errorName(ec));
+ ec = U_ZERO_ERROR;
+ if (!tokens.next(tok, ec)) goto error;
+ if (!tokens.next(tok, ec)) goto error;
+ if (!tokens.next(tok, ec)) goto error;
+ continue;
+ }
+ }
+ // fpc: <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
+ if (!tokens.next(currAmt, ec)) goto error;
+ if (!tokens.next(str, ec)) goto error;
+ parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
+ if (assertSuccess("parseCurrencyAmount", ec)) {
+ assertEquals(where + "getCurrencyFormat(" + mloc + ").format(" + currAmt + ")",
+ str, mfmt->format(n, out.remove(), ec));
+ assertSuccess("format", ec);
+ }
+ if (!tokens.next(currAmt, ec)) goto error;
+ parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
+ if (assertSuccess("parseCurrencyAmount", ec)) {
+ Formattable m;
+ mfmt->parseObject(str, m, ec);
+ if (assertSuccess("parseCurrency", ec)) {
+ assertEquals(where + "getCurrencyFormat(" + mloc + ").parse(\"" + str + "\")",
+ n, m);
+ }
+ }
+ break;
+ case 6:
+ // perr: <pattern or '-'> <invalid string>
+ errln("FAIL: Under construction");
+ goto done;
+ case 7: {
+ // pat: <pattern> <exp. toPattern, or '-' or 'err'>
+ UnicodeString testpat;
+ UnicodeString exppat;
+ if (!tokens.next(testpat, ec)) goto error;
+ if (!tokens.next(exppat, ec)) goto error;
+ UBool err = exppat == "err";
+ UBool existingPat = FALSE;
+ if (testpat == "-") {
+ if (err) {
+ errln("FAIL: " + where + "Invalid command \"pat: - err\"");
+ continue;
+ }
+ existingPat = TRUE;
+ testpat = pat;
+ }
+ if (exppat == "-") exppat = testpat;
+ DecimalFormat* f = 0;
+ UErrorCode ec2 = U_ZERO_ERROR;
+ if (existingPat) {
+ f = fmt;
+ } else {
+ f = new DecimalFormat(testpat, ec2);
+ }
+ if (U_SUCCESS(ec2)) {
+ if (err) {
+ errln("FAIL: " + where + "Invalid pattern \"" + testpat +
+ "\" was accepted");
+ } else {
+ UnicodeString pat2;
+ assertEquals(where + "\"" + testpat + "\".toPattern()",
+ exppat, f->toPattern(pat2));
+ }
+ } else {
+ if (err) {
+ logln("Ok: " + where + "Invalid pattern \"" + testpat +
+ "\" failed: " + u_errorName(ec2));
+ } else {
+ errln("FAIL: " + where + "Valid pattern \"" + testpat +
+ "\" failed: " + u_errorName(ec2));
+ }
+ }
+ if (!existingPat) delete f;
+ } break;
+ case -1:
+ errln("FAIL: " + where + "Unknown command \"" + tok + "\"");
+ goto done;
+ }
+ }
+ goto done;
+
+ error:
+ if (U_SUCCESS(ec)) {
+ errln("FAIL: Unexpected EOF");
+ } else {
+ errln("FAIL: " + where + "Unexpected " + u_errorName(ec));
+ }
+
+ done:
+ delete mfmt;
+ delete fmt;
+ delete ref;
+}
+
+
+//----------------------------------------------------------------------
+// Support methods
+//----------------------------------------------------------------------
+
+UBool NumberFormatTest::equalValue(const Formattable& a, const Formattable& b) {
+ if (a.getType() == b.getType()) {
+ return a == b;
+ }
+
+ if (a.getType() == Formattable::kLong) {
+ if (b.getType() == Formattable::kInt64) {
+ return a.getLong() == b.getLong();
+ } else if (b.getType() == Formattable::kDouble) {
+ return (double) a.getLong() == b.getDouble(); // TODO check use of double instead of long
+ }
+ } else if (a.getType() == Formattable::kDouble) {
+ if (b.getType() == Formattable::kLong) {
+ return a.getDouble() == (double) b.getLong();
+ } else if (b.getType() == Formattable::kInt64) {
+ return a.getDouble() == (double)b.getInt64();
+ }
+ } else if (a.getType() == Formattable::kInt64) {
+ if (b.getType() == Formattable::kLong) {
+ return a.getInt64() == (int64_t)b.getLong();
+ } else if (b.getType() == Formattable::kDouble) {
+ return a.getInt64() == (int64_t)b.getDouble();
+ }
+ }
+ return FALSE;
+}
+
+void NumberFormatTest::expect2(NumberFormat& fmt, const Formattable& n, const UnicodeString& str) {
+ // Don't round-trip format test, since we explicitly do it
+ expect(fmt, n, str, FALSE);
+ expect(fmt, str, n);
+}
+
+void NumberFormatTest::expect2(NumberFormat* fmt, const Formattable& n,
+ const UnicodeString& exp,
+ UErrorCode status) {
+ if (U_FAILURE(status)) {
+ errln("FAIL: NumberFormat constructor");
+ } else {
+ expect2(*fmt, n, exp);
+ }
+ delete fmt;
+}
+
+void NumberFormatTest::expect(NumberFormat& fmt, const UnicodeString& str, const Formattable& n) {
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable num;
+ fmt.parse(str, num, status);
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: Parse failed for \"") + str + "\"");
+ return;
+ }
+ UnicodeString pat;
+ ((DecimalFormat*) &fmt)->toPattern(pat);
+ if (equalValue(num, n)) {
+ logln(UnicodeString("Ok \"") + str + "\" x " +
+ pat + " = " +
+ toString(num));
+ } else {
+ errln(UnicodeString("FAIL \"") + str + "\" x " +
+ pat + " = " +
+ toString(num) + ", expected " + toString(n));
+ }
+}
+
+void NumberFormatTest::expect(NumberFormat& fmt, const Formattable& n,
+ const UnicodeString& exp, UBool rt) {
+ UnicodeString saw;
+ FieldPosition pos;
+ UErrorCode status = U_ZERO_ERROR;
+ fmt.format(n, saw, pos, status);
+ CHECK(status, "NumberFormat::format");
+ UnicodeString pat;
+ ((DecimalFormat*) &fmt)->toPattern(pat);
+ if (saw == exp) {
+ logln(UnicodeString("Ok ") + toString(n) + " x " +
+ escape(pat) + " = \"" +
+ escape(saw) + "\"");
+ // We should be able to round-trip the formatted string =>
+ // number => string (but not the other way around: number
+ // => string => number2, might have number2 != number):
+ if (rt) {
+ Formattable n2;
+ fmt.parse(exp, n2, status);
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: Parse failed for \"") + exp + "\"");
+ return;
+ }
+ UnicodeString saw2;
+ fmt.format(n2, saw2, pos, status);
+ CHECK(status, "NumberFormat::format");
+ if (saw2 != exp) {
+ errln((UnicodeString)"FAIL \"" + exp + "\" => " + toString(n2) +
+ " => \"" + saw2 + "\"");
+ }
+ }
+ } else {
+ errln(UnicodeString("FAIL ") + toString(n) + " x " +
+ escape(pat) + " = \"" +
+ escape(saw) + "\", expected \"" + exp + "\"");
+ }
+}
+
+void NumberFormatTest::expect(NumberFormat* fmt, const Formattable& n,
+ const UnicodeString& exp,
+ UErrorCode status) {
+ if (U_FAILURE(status)) {
+ errln("FAIL: NumberFormat constructor");
+ } else {
+ expect(*fmt, n, exp);
+ }
+ delete fmt;
+}
+
+void NumberFormatTest::expectCurrency(NumberFormat& nf, const Locale& locale,
+ double value, const UnicodeString& string) {
+ UErrorCode ec = U_ZERO_ERROR;
+ DecimalFormat& fmt = * (DecimalFormat*) &nf;
+ const UChar DEFAULT_CURR[] = {45/*-*/,0};
+ UChar curr[4];
+ u_strcpy(curr, DEFAULT_CURR);
+ if (*locale.getLanguage() != 0) {
+ ucurr_forLocale(locale.getName(), curr, 4, &ec);
+ assertSuccess("ucurr_forLocale", ec);
+ fmt.setCurrency(curr, ec);
+ assertSuccess("DecimalFormat::setCurrency", ec);
+ fmt.setCurrency(curr); //Deprecated variant, for coverage only
+ }
+ UnicodeString s;
+ fmt.format(value, s);
+ s.findAndReplace((UChar32)0x00A0, (UChar32)0x0020);
+
+ // Default display of the number yields "1234.5599999999999"
+ // instead of "1234.56". Use a formatter to fix this.
+ NumberFormat* f =
+ NumberFormat::createInstance(Locale::getUS(), ec);
+ UnicodeString v;
+ if (U_FAILURE(ec)) {
+ // Oops; bad formatter. Use default op+= display.
+ v = (UnicodeString)"" + value;
+ } else {
+ f->setMaximumFractionDigits(4);
+ f->setGroupingUsed(FALSE);
+ f->format(value, v);
+ }
+ delete f;
+
+ if (s == string) {
+ logln((UnicodeString)"Ok: " + v + " x " + curr + " => " + prettify(s));
+ } else {
+ errln((UnicodeString)"FAIL: " + v + " x " + curr + " => " + prettify(s) +
+ ", expected " + prettify(string));
+ }
+}
+
+void NumberFormatTest::expectPat(DecimalFormat& fmt, const UnicodeString& exp) {
+ UnicodeString pat;
+ fmt.toPattern(pat);
+ if (pat == exp) {
+ logln(UnicodeString("Ok \"") + pat + "\"");
+ } else {
+ errln(UnicodeString("FAIL \"") + pat + "\", expected \"" + exp + "\"");
+ }
+}
+
+void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
+ int32_t pos) {
+ expectPad(fmt, pat, pos, 0, (UnicodeString)"");
+}
+void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
+ int32_t pos, int32_t width, UChar pad) {
+ expectPad(fmt, pat, pos, width, UnicodeString(pad));
+}
+void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
+ int32_t pos, int32_t width, const UnicodeString& pad) {
+ int32_t apos = 0, awidth = 0;
+ UnicodeString apadStr;
+ UErrorCode status = U_ZERO_ERROR;
+ fmt.applyPattern(pat, status);
+ if (U_SUCCESS(status)) {
+ apos = fmt.getPadPosition();
+ awidth = fmt.getFormatWidth();
+ apadStr=fmt.getPadCharacterString();
+ } else {
+ apos = -1;
+ awidth = width;
+ apadStr = pad;
+ }
+ if (apos == pos && awidth == width && apadStr == pad) {
+ UnicodeString infoStr;
+ if (pos == ILLEGAL) {
+ infoStr = UnicodeString(" width=", "") + awidth + UnicodeString(" pad=", "") + apadStr;
+ }
+ logln(UnicodeString("Ok \"") + pat + "\" pos=" + apos + infoStr);
+ } else {
+ errln(UnicodeString("FAIL \"") + pat + "\" pos=" + apos +
+ " width=" + awidth + " pad=" + apadStr +
+ ", expected " + pos + " " + width + " " + pad);
+ }
+}
+void NumberFormatTest::TestJB3832(){
+ const char* localeID = "pt_PT@currency=PTE";
+ Locale loc(localeID);
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString expected("1,150$50 Esc.");
+ UnicodeString s;
+ NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(loc, status);
+ if(U_FAILURE(status)){
+ errln("Could not create currency formatter for locale %s", localeID);
+ return;
+ }
+ currencyFmt->format(1150.50, s);
+ if(s!=expected){
+ errln(UnicodeString("FAIL: Expected: ")+expected
+ + UnicodeString(" Got: ") + s
+ + UnicodeString( " for locale: ")+ UnicodeString(localeID) );
+ }
+ if (U_FAILURE(status)){
+ errln("FAIL: Status %s", u_errorName(status));
+ }
+ delete currencyFmt;
+}
+
+void NumberFormatTest::TestHost()
+{
+#ifdef U_WINDOWS
+ Win32NumberTest::testLocales(this);
+#endif
+}
+
+void NumberFormatTest::TestHostClone()
+{
+ /*
+ Verify that a cloned formatter gives the same results
+ and is useable after the original has been deleted.
+ */
+ // This is mainly important on Windows.
+ UErrorCode status = U_ZERO_ERROR;
+ Locale loc("en_US@compat=host");
+ UDate now = Calendar::getNow();
+ NumberFormat *full = NumberFormat::createInstance(loc, status);
+ if (full == NULL || U_FAILURE(status)) {
+ errln("FAIL: Can't create Relative date instance");
+ return;
+ }
+ UnicodeString result1;
+ full->format(now, result1, status);
+ Format *fullClone = full->clone();
+ delete full;
+ full = NULL;
+
+ UnicodeString result2;
+ fullClone->format(now, result2, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: format failure.");
+ }
+ if (result1 != result2) {
+ errln("FAIL: Clone returned different result from non-clone.");
+ }
+ delete fullClone;
+}
+
+void NumberFormatTest::TestCurrencyFormat()
+{
+ // This test is here to increase code coverage.
+ UErrorCode status = U_ZERO_ERROR;
+ MeasureFormat *cloneObj;
+ UnicodeString str;
+ Formattable toFormat, result;
+ static const UChar ISO_CODE[4] = {0x0047, 0x0042, 0x0050, 0};
+
+ Locale saveDefaultLocale = Locale::getDefault();
+ Locale::setDefault( Locale::getUK(), status );
+ if (U_FAILURE(status)) {
+ errln("couldn't set default Locale!");
+ return;
+ }
+
+ MeasureFormat *measureObj = MeasureFormat::createCurrencyFormat(status);
+ Locale::setDefault( saveDefaultLocale, status );
+ if (U_FAILURE(status)){
+ errln("FAIL: Status %s", u_errorName(status));
+ return;
+ }
+ cloneObj = (MeasureFormat *)measureObj->clone();
+ if (cloneObj == NULL) {
+ errln("Clone doesn't work");
+ return;
+ }
+ toFormat.adoptObject(new CurrencyAmount(1234.56, ISO_CODE, status));
+ measureObj->format(toFormat, str, status);
+ measureObj->parseObject(str, result, status);
+ if (U_FAILURE(status)){
+ errln("FAIL: Status %s", u_errorName(status));
+ }
+ if (result != toFormat) {
+ errln("measureObj does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat));
+ }
+ status = U_ZERO_ERROR;
+ str.truncate(0);
+ cloneObj->format(toFormat, str, status);
+ cloneObj->parseObject(str, result, status);
+ if (U_FAILURE(status)){
+ errln("FAIL: Status %s", u_errorName(status));
+ }
+ if (result != toFormat) {
+ errln("Clone does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat));
+ }
+ if (*measureObj != *cloneObj) {
+ errln("Cloned object is not equal to the original object");
+ }
+ delete measureObj;
+ delete cloneObj;
+
+ status = U_USELESS_COLLATOR_ERROR;
+ if (MeasureFormat::createCurrencyFormat(status) != NULL) {
+ errln("createCurrencyFormat should have returned NULL.");
+ }
+}
+
+/* Port of ICU4J rounding test. */
+void NumberFormatTest::TestRounding() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = (DecimalFormat*)NumberFormat::createCurrencyInstance(Locale::getEnglish(), status);
+
+ if (U_FAILURE(status)) {
+ errln("Unable to create decimal formatter.");
+ return;
+ }
+
+ int roundingIncrements[]={1, 2, 5, 20, 50, 100};
+ int testValues[]={0, 300};
+
+ for (int j=0; j<2; j++) {
+ for (int mode=DecimalFormat::kRoundUp;mode<DecimalFormat::kRoundHalfEven;mode++) {
+ df->setRoundingMode((DecimalFormat::ERoundingMode)mode);
+ for (int increment=0; increment<6; increment++) {
+ double base=testValues[j];
+ double rInc=roundingIncrements[increment];
+ checkRounding(df, base, 20, rInc);
+ rInc=1.000000000/rInc;
+ checkRounding(df, base, 20, rInc);
+ }
+ }
+ }
+
+}
+
+void NumberFormatTest::checkRounding(DecimalFormat* df, double base, int iterations, double increment) {
+ df->setRoundingIncrement(increment);
+ double lastParsed=INT32_MIN; //Intger.MIN_VALUE
+ for (int i=-iterations; i<=iterations;i++) {
+ double iValue=base+(increment*(i*0.1));
+ double smallIncrement=0.00000001;
+ if (iValue!=0) {
+ smallIncrement*=iValue;
+ }
+ //we not only test the value, but some values in a small range around it
+ lastParsed=checkRound(df, iValue-smallIncrement, lastParsed);
+ lastParsed=checkRound(df, iValue, lastParsed);
+ lastParsed=checkRound(df, iValue+smallIncrement, lastParsed);
+ }
+}
+
+double NumberFormatTest::checkRound(DecimalFormat* df, double iValue, double lastParsed) {
+ UErrorCode status=U_ZERO_ERROR;
+ UnicodeString formattedDecimal;
+ double parsed;
+ Formattable result;
+ df->format(iValue, formattedDecimal, status);
+
+ if (U_FAILURE(status)) {
+ errln("Error formatting number.");
+ }
+
+ df->parse(formattedDecimal, result, status);
+
+ if (U_FAILURE(status)) {
+ errln("Error parsing number.");
+ }
+
+ parsed=result.getDouble();
+
+ if (lastParsed>parsed) {
+ errln("Rounding wrong direction! %d > %d", lastParsed, parsed);
+ }
+
+ return lastParsed;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.h b/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.h
new file mode 100644
index 00000000000..80baa1456e3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/numfmtst.h
@@ -0,0 +1,219 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _NUMBERFORMATTEST_
+#define _NUMBERFORMATTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/numfmt.h"
+#include "unicode/decimfmt.h"
+#include "caltztst.h"
+
+/**
+ * Performs various in-depth test on NumberFormat
+ **/
+class NumberFormatTest: public CalendarTimeZoneTest {
+
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+ public:
+
+ /**
+ * Test APIs (to increase code coverage)
+ */
+ void TestAPI(void);
+
+ void TestCoverage(void);
+
+ /**
+ * Test the handling of quotes
+ **/
+ void TestQuotes(void);
+ /**
+ * Test patterns with exponential representation
+ **/
+ void TestExponential(void);
+ /**
+ * Test handling of patterns with currency symbols
+ **/
+ void TestCurrencySign(void);
+ /**
+ * Test different format patterns
+ **/
+ void TestPatterns(void);
+ /**
+ * API coverage for DigitList
+ **/
+ //void TestDigitList(void);
+
+ /**
+ * Test localized currency patterns.
+ */
+ void TestCurrency(void);
+
+ /**
+ * Test the Currency object handling, new as of ICU 2.2.
+ */
+ void TestCurrencyObject(void);
+
+ void TestCurrencyPatterns(void);
+
+ /**
+ * Do rudimentary testing of parsing.
+ */
+ void TestParse(void);
+ /**
+ * Test proper rounding by the format method.
+ */
+ void TestRounding487(void);
+
+ // New tests for alphaWorks upgrade
+ void TestExponent(void);
+
+ void TestScientific(void);
+
+ void TestScientific2(void);
+
+ void TestScientificGrouping(void);
+
+ void TestInt64(void);
+
+ void TestSurrogateSupport(void);
+
+ /**
+ * Test the functioning of the secondary grouping value.
+ */
+ void TestSecondaryGrouping(void);
+
+ void TestWhiteSpaceParsing(void);
+
+ void TestComplexCurrency(void);
+
+ void TestPad(void);
+ void TestPatterns2(void);
+
+ /**
+ * Test currency registration.
+ */
+ void TestRegCurrency(void);
+
+ void TestCurrencyNames(void);
+
+ void TestCurrencyAmount(void);
+
+ void TestCurrencyUnit(void);
+
+ void TestSymbolsWithBadLocale(void);
+
+ void TestAdoptDecimalFormatSymbols(void);
+
+ void TestPerMill(void);
+
+ void TestIllegalPatterns(void);
+
+ void TestCases(void);
+
+ void TestJB3832(void);
+
+ void TestHost(void);
+
+ void TestHostClone(void);
+
+ void TestCurrencyFormat(void);
+
+ /* Port of ICU4J rounding test. */
+ void TestRounding(void);
+ private:
+
+ static UBool equalValue(const Formattable& a, const Formattable& b);
+
+ void expect2(NumberFormat& fmt, const Formattable& n, const UnicodeString& str);
+
+ void expect2(NumberFormat& fmt, const Formattable& n, const char* str) {
+ expect2(fmt, n, UnicodeString(str, ""));
+ }
+
+ void expect2(NumberFormat* fmt, const Formattable& n, const UnicodeString& str, UErrorCode ec);
+
+ void expect2(NumberFormat* fmt, const Formattable& n, const char* str, UErrorCode ec) {
+ expect2(fmt, n, UnicodeString(str, ""), ec);
+ }
+
+ void expect(NumberFormat& fmt, const UnicodeString& str, const Formattable& n);
+
+ void expect(NumberFormat& fmt, const char *str, const Formattable& n) {
+ expect(fmt, UnicodeString(str, ""), n);
+ }
+
+ void expect(NumberFormat& fmt, const Formattable& n,
+ const UnicodeString& exp, UBool rt=TRUE);
+
+ void expect(NumberFormat& fmt, const Formattable& n,
+ const char *exp, UBool rt=TRUE) {
+ expect(fmt, n, UnicodeString(exp, ""), rt);
+ }
+
+ void expect(NumberFormat* fmt, const Formattable& n,
+ const UnicodeString& exp, UErrorCode);
+
+ void expect(NumberFormat* fmt, const Formattable& n,
+ const char *exp, UErrorCode errorCode) {
+ expect(fmt, n, UnicodeString(exp, ""), errorCode);
+ }
+
+ void expectCurrency(NumberFormat& nf, const Locale& locale,
+ double value, const UnicodeString& string);
+
+ void expectPad(DecimalFormat& fmt, const UnicodeString& pat,
+ int32_t pos, int32_t width, UChar pad);
+
+ void expectPad(DecimalFormat& fmt, const char *pat,
+ int32_t pos, int32_t width, UChar pad) {
+ expectPad(fmt, UnicodeString(pat, ""), pos, width, pad);
+ }
+
+ void expectPad(DecimalFormat& fmt, const UnicodeString& pat,
+ int32_t pos, int32_t width, const UnicodeString& pad);
+
+ void expectPad(DecimalFormat& fmt, const char *pat,
+ int32_t pos, int32_t width, const UnicodeString& pad) {
+ expectPad(fmt, UnicodeString(pat, ""), pos, width, pad);
+ }
+
+ void expectPat(DecimalFormat& fmt, const UnicodeString& exp);
+
+ void expectPat(DecimalFormat& fmt, const char *exp) {
+ expectPat(fmt, UnicodeString(exp, ""));
+ }
+
+ void expectPad(DecimalFormat& fmt, const UnicodeString& pat,
+ int32_t pos);
+
+ void expectPad(DecimalFormat& fmt, const char *pat,
+ int32_t pos) {
+ expectPad(fmt, pat, pos, 0, (UChar)0);
+ }
+
+ // internal utility routine
+ static UnicodeString& escape(UnicodeString& s);
+
+ enum { ILLEGAL = -1 };
+
+ // internal subtest used by TestRounding487
+ void roundingTest(NumberFormat& nf, double x, int32_t maxFractionDigits, const char* expected);
+
+ // internal rounding checking for TestRounding
+ void checkRounding(DecimalFormat* df, double base, int iterations, double increment);
+
+ double checkRound(DecimalFormat* df, double iValue, double lastParsed);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _NUMBERFORMATTEST_
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/numrgts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/numrgts.cpp
new file mode 100644
index 00000000000..e93eb5ce1d6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/numrgts.cpp
@@ -0,0 +1,2647 @@
+/***********************************************************************
+ * Copyright (c) 1997-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "numrgts.h"
+
+#include <float.h> // DBL_MIN, DBL_MAX
+#include <stdio.h>
+
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/locid.h"
+#include "unicode/resbund.h"
+#include "unicode/calendar.h"
+#include "unicode/datefmt.h"
+#include "unicode/ucurr.h"
+#include "putilimp.h"
+
+class MyNumberFormatTest : public NumberFormat
+{
+public:
+
+ virtual UClassID getDynamicClassID(void) const;
+
+ virtual UnicodeString& format( double number,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+ {
+ return NumberFormat::format(number, toAppendTo, pos, status);
+ }
+
+ /* Just keep this here to make some of the compilers happy */
+ virtual UnicodeString& format(const Formattable& obj,
+ UnicodeString& toAppendTo,
+ FieldPosition& pos,
+ UErrorCode& status) const
+ {
+ return NumberFormat::format(obj, toAppendTo, pos, status);
+ }
+
+ /* Just use one of the format functions */
+ virtual UnicodeString& format( double /* number */,
+ UnicodeString& toAppendTo,
+ FieldPosition& /* pos */) const
+ {
+ toAppendTo = "";
+ return toAppendTo;
+ }
+
+ /*
+ public Number parse(String text, ParsePosition parsePosition)
+ { return new Integer(0); }
+ */
+
+ /* Just use one of the parse functions */
+ virtual void parse( const UnicodeString& /* text */,
+ Formattable& result,
+ ParsePosition& /* parsePosition */) const
+ {
+ result.setLong((int32_t)0);
+ }
+
+ virtual void parse( const UnicodeString& text,
+ Formattable& result,
+ UErrorCode& status) const
+ {
+ NumberFormat::parse(text, result, status);
+ }
+ virtual Format* clone() const
+ { return NULL; }
+
+ virtual UnicodeString& format(int32_t,
+ UnicodeString& foo,
+ FieldPosition&) const
+ { return foo.remove(); }
+
+ virtual UnicodeString& format(int64_t,
+ UnicodeString& foo,
+ FieldPosition&) const
+ { return foo.remove(); }
+
+ virtual void applyPattern(const UnicodeString&, UParseError&, UErrorCode&){
+ }
+};
+
+int32_t gMyNumberFormatTestClassID;
+UClassID MyNumberFormatTest::getDynamicClassID() const
+{
+ return (UClassID)&gMyNumberFormatTestClassID;
+}
+
+
+// *****************************************************************************
+// class NumberFormatRegressionTest
+// *****************************************************************************
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
+
+void
+NumberFormatRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest");
+ switch (index) {
+ CASE(0,Test4075713);
+ CASE(1,Test4074620);
+ CASE(2,Test4088161);
+ CASE(3,Test4087245);
+ CASE(4,Test4087535);
+ CASE(5,Test4088503);
+ CASE(6,Test4066646);
+ CASE(7,Test4059870);
+ CASE(8,Test4083018);
+ CASE(9,Test4071492);
+ CASE(10,Test4086575);
+ CASE(11,Test4068693);
+ CASE(12,Test4069754);
+ CASE(13,Test4087251);
+ CASE(14,Test4090489);
+ CASE(15,Test4090504);
+ CASE(16,Test4095713);
+ CASE(17,Test4092561);
+ CASE(18,Test4092480);
+ CASE(19,Test4087244);
+ CASE(20,Test4070798);
+ CASE(21,Test4071005);
+ CASE(22,Test4071014);
+ CASE(23,Test4071859);
+ CASE(24,Test4093610);
+ CASE(25,Test4098741);
+ CASE(26,Test4074454);
+ CASE(27,Test4099404);
+ CASE(28,Test4101481);
+ CASE(29,Test4052223);
+ CASE(30,Test4061302);
+ CASE(31,Test4062486);
+ CASE(32,Test4108738);
+ CASE(33,Test4106658);
+ CASE(34,Test4106662);
+ CASE(35,Test4114639);
+ CASE(36,Test4106664);
+ CASE(37,Test4106667);
+ CASE(38,Test4110936);
+ CASE(39,Test4122840);
+ CASE(40,Test4125885);
+ CASE(41,Test4134034);
+ CASE(42,Test4134300);
+ CASE(43,Test4140009);
+ CASE(44,Test4141750);
+ CASE(45,Test4145457);
+ CASE(46,Test4147295);
+ CASE(47,Test4147706);
+ CASE(48,Test4162198);
+ CASE(49,Test4162852);
+ CASE(50,Test4167494);
+ CASE(51,Test4170798);
+ CASE(52,Test4176114);
+ CASE(53,Test4179818);
+ CASE(54,Test4212072);
+ CASE(55,Test4216742);
+ CASE(56,Test4217661);
+ CASE(57,Test4161100);
+ CASE(58,Test4243011);
+ CASE(59,Test4243108);
+ CASE(60,TestJ691);
+
+ default: name = ""; break;
+ }
+}
+
+UBool
+NumberFormatRegressionTest::failure(UErrorCode status, const UnicodeString& msg, const Locale& l)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ", "") + msg
+ + UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), "") + UnicodeString(l.getName(),""));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+UBool
+NumberFormatRegressionTest::failure(UErrorCode status, const UnicodeString& msg, const char *l)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ", "") + msg
+ + UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), "") + UnicodeString(l, ""));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+UBool
+NumberFormatRegressionTest::failure(UErrorCode status, const UnicodeString& msg)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ", "") + msg
+ + UnicodeString(" failed, error ", "") + UnicodeString(u_errorName(status), ""));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Convert Java-style strings with \u Unicode escapes into UnicodeString objects
+ */
+inline UnicodeString str(const char *input)
+{
+ return CharsToUnicodeString(input);
+}
+
+/* @bug 4075713
+ * NumberFormat.equals comparing with null should always return false.
+ */
+// {sfb} kind of silly in C++, just checking for new success
+void NumberFormatRegressionTest::Test4075713(void)
+{
+ //try {
+ MyNumberFormatTest *tmp = new MyNumberFormatTest();
+ if(tmp != NULL)
+ logln("NumberFormat.equals passed");
+ /*} catch (NullPointerException e) {
+ errln("(new MyNumberFormatTest()).equals(null) throws unexpected exception");
+ }*/
+
+ delete tmp;
+}
+
+/* @bug 4074620
+ * NumberFormat.equals comparing two obj equal even the setGroupingUsed
+ * flag is different.
+ */
+void NumberFormatRegressionTest::Test4074620(void)
+{
+
+ MyNumberFormatTest *nf1 = new MyNumberFormatTest();
+ MyNumberFormatTest *nf2 = new MyNumberFormatTest();
+
+ nf1->setGroupingUsed(FALSE);
+ nf2->setGroupingUsed(TRUE);
+
+ if(nf1 == nf2)
+ errln("Test for bug 4074620 failed");
+ else
+ logln("Test for bug 4074620 passed.");
+
+ delete nf1;
+ delete nf2;
+}
+
+
+/* @bug 4088161
+ * DecimalFormat.format() incorrectly uses maxFractionDigits setting.
+ */
+
+void NumberFormatRegressionTest::Test4088161 (void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ failure(status, "new DecimalFormat", "");
+ double d = 100;
+ df->setMinimumFractionDigits(0);
+ df->setMaximumFractionDigits(16);
+ UnicodeString sBuf1;
+ FieldPosition fp1(0);
+ logln(UnicodeString("d = ") + d);
+ logln("maxFractionDigits = " + df->getMaximumFractionDigits());
+
+ logln(" format(d) = '" + df->format(d, sBuf1, fp1) + "'");
+ df->setMaximumFractionDigits(17);
+ UnicodeString sBuf2;
+ FieldPosition fp2(0);
+ logln("maxFractionDigits = " + df->getMaximumFractionDigits());
+ sBuf2 = df->format(d, sBuf2, fp2);
+ if(sBuf2 != "100")
+ errln(" format(d) = '" + sBuf2 + "'");
+
+ delete df;
+}
+
+/* @bug 4087245
+ * DecimalFormatSymbols should be cloned in the ctor DecimalFormat.
+ * DecimalFormat(String, DecimalFormatSymbols).
+ */
+void NumberFormatRegressionTest::Test4087245 (void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols *symbols = new DecimalFormatSymbols(status);
+ failure(status, "new DecimalFormatSymbols", "");
+ // {sfb} One note about this test: if you pass in a pointer
+ // to the symbols, they are adopted and this test will fail,
+ // even though that is the correct behavior. To test the cloning
+ // of the symbols, it is necessary to pass in a reference to the symbols
+ DecimalFormat *df = new DecimalFormat("#,##0.0", *symbols, status);
+ failure(status, "new DecimalFormat with symbols", "");
+ int32_t n = 123;
+ UnicodeString buf1;
+ UnicodeString buf2;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ logln(UnicodeString("format(") + n + ") = " +
+ df->format(n, buf1, pos));
+ symbols->setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, UnicodeString((UChar)0x70)); // change value of field
+ logln(UnicodeString("format(") + n + ") = " +
+ df->format(n, buf2, pos));
+ if(buf1 != buf2)
+ errln("Test for bug 4087245 failed");
+
+ delete df;
+ delete symbols;
+}
+
+/* @bug 4087535
+ * DecimalFormat.format() incorrectly formats 0.0
+ */
+void NumberFormatRegressionTest::Test4087535 (void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ failure(status, "new DecimalFormat", "");
+ df->setMinimumIntegerDigits(0);
+
+ double n = 0;
+ UnicodeString buffer;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ buffer = df->format(n, buffer, pos);
+ if (buffer.length() == 0)
+ errln(/*n + */": '" + buffer + "'");
+ n = 0.1;
+ buffer = df->format(n, buffer, pos);
+ if (buffer.length() == 0)
+ errln(/*n + */": '" + buffer + "'");
+
+ delete df;
+}
+
+/* @bug 4088503
+ * DecimalFormat.format fails when groupingSize is set to 0.
+ */
+// {sfb} how do I tell if this worked? --> FieldPosition doesn't change ??
+void NumberFormatRegressionTest::Test4088503 (void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ failure(status, "new DecimalFormat", "");
+ df->setGroupingSize(0);
+ UnicodeString sBuf;
+ FieldPosition fp(FieldPosition::DONT_CARE);
+ //try {
+ logln(df->format((int32_t)123, sBuf, fp));
+ //if(fp == FieldPosition(0))
+ // errln("Test for bug 4088503 failed.");
+ /*} catch (Exception foo) {
+ errln("Test for bug 4088503 failed.");
+ }*/
+ delete df;
+
+}
+/* @bug 4066646
+ * NumberFormat.getCurrencyInstance is wrong.
+ */
+void NumberFormatRegressionTest::Test4066646 (void)
+{
+ assignFloatValue(2.04f);
+ assignFloatValue(2.03f);
+ assignFloatValue(2.02f);
+ assignFloatValue(0.0f);
+}
+
+float
+NumberFormatRegressionTest::assignFloatValue(float returnfloat)
+{
+ logln(UnicodeString(" VALUE ") + returnfloat);
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nfcommon = NumberFormat::createCurrencyInstance(Locale::getUS(), status);
+ if (failure(status, "NumberFormat::createCurrencyInstance", Locale::getUS())){
+ delete nfcommon;
+ return returnfloat;
+ }
+ nfcommon->setGroupingUsed(FALSE);
+
+ UnicodeString stringValue;
+ stringValue = nfcommon->format(returnfloat, stringValue);
+ logln(" DISPLAYVALUE " + stringValue);
+ Formattable result;
+ nfcommon->parse(stringValue, result, status);
+ failure(status, "nfcommon->parse", Locale::getUS());
+ float floatResult = (float) (result.getType() == Formattable::kDouble
+ ? result.getDouble() : result.getLong());
+ if( uprv_fabs(floatResult - returnfloat) > 0.0001)
+ //String stringValue = nfcommon.format(returnfloat).substring(1);
+ //if (Float.valueOf(stringValue).floatValue() != returnfloat)
+ errln(UnicodeString("FAIL: expected ") + returnfloat + ", got " + floatResult + " (" + stringValue+")");
+
+ delete nfcommon;
+ return returnfloat;
+} // End Of assignFloatValue()
+
+/* @bug 4059870
+ * DecimalFormat throws exception when parsing "0"
+ */
+void NumberFormatRegressionTest::Test4059870(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *format = new DecimalFormat("00", status);
+ failure(status, "new Decimalformat", Locale::getUS());
+ //try {
+ Formattable result;
+ UnicodeString str;
+ format->parse(UnicodeString("0"), result, status);
+ failure(status, "format->parse", Locale::getUS());
+
+ /*}
+ catch (Exception e) {
+ errln("Test for bug 4059870 failed : " + e);
+ }*/
+
+ delete format;
+}
+/* @bug 4083018
+ * DecimalFormatSymbol.equals should always return false when
+ * comparing with null.
+ */
+// {sfb} this is silly in C++
+void NumberFormatRegressionTest::Test4083018 (void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols *dfs = new DecimalFormatSymbols(status);
+ failure(status, "new DecimalFormatSymbols", Locale::getUS());
+ //try {
+ if (dfs != NULL)
+ logln("Test Passed!");
+ else
+ errln("Test for bug 4083018 failed");
+ /*} catch (Exception foo) {
+ errln("Test for bug 4083018 failed => Message : " + foo.getMessage());
+ }*/
+
+ delete dfs;
+}
+
+/* @bug 4071492
+ * DecimalFormat does not round up correctly.
+ */
+void NumberFormatRegressionTest::Test4071492 (void)
+{
+ double x = 0.00159999;
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nf = NumberFormat::createInstance(status);
+ if (failure(status, "NumberFormat::createInstance", Locale::getUS())) {
+ delete nf;
+ return;
+ }
+ nf->setMaximumFractionDigits(4);
+ UnicodeString out;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ out = nf->format(x, out, pos);
+ logln("0.00159999 formats with 4 fractional digits to " + out);
+ UnicodeString expected("0.0016");
+ if (out != expected)
+ errln("FAIL: Expected " + expected);
+
+ delete nf;
+}
+
+/* @bug 4086575
+ * A space as a group separator for localized pattern causes
+ * wrong format. WorkAround : use non-breaking space.
+ */
+void NumberFormatRegressionTest::Test4086575(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nf1 = NumberFormat::createInstance(Locale::getFrance(), status);
+
+ // TODO: There is not a good way to find out that the creation of this number format has
+ // failed. Major rewiring of format construction proposed.
+ if(U_FAILURE(status)) {
+ errln("Something is wrong with French number format - it should not fallback. Exitting");
+ delete nf1;
+ return;
+ }
+ failure(status, "NumberFormat::createInstance", Locale::getFrance());
+
+ // C++ workaround to make sure cast works
+ // Wouldn't dynamic_cast<DecimalFormat*> be great?
+ if(nf1->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ errln("NumberFormat::createInstance returned incorrect type.");
+ return;
+ }
+
+ DecimalFormat *nf = (DecimalFormat*) nf1;
+ UnicodeString temp;
+ logln("nf toPattern1: " + nf->toPattern(temp));
+ logln("nf toLocPattern1: " + nf->toLocalizedPattern(temp));
+
+ // No group separator
+ logln("...applyLocalizedPattern ###,00;(###,00) ");
+ nf->applyLocalizedPattern(UnicodeString("###,00;(###,00)"), status);
+ failure(status, "nf->applyLocalizedPattern", Locale::getFrance());
+ logln("nf toPattern2: " + nf->toPattern(temp));
+ logln("nf toLocPattern2: " + nf->toLocalizedPattern(temp));
+
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ logln("nf: " + nf->format((int32_t)1234, temp, pos)); // 1234,00
+ logln("nf: " + nf->format((int32_t)-1234, temp, pos)); // (1234,00)
+
+ // Space as group separator
+
+ logln("...applyLocalizedPattern # ###,00;(# ###,00) ");
+ // nbsp = \u00a0
+ //nf->applyLocalizedPattern("#\u00a0###,00;(#\u00a0###,00)");
+ UChar patChars[] = {
+ 0x23, 0x00a0, 0x23, 0x23, 0x23, 0x2c, 0x30, 0x30, 0x3b,
+ 0x28, 0x23, 0x00a0, 0x23, 0x23, 0x23, 0x2c, 0x30, 0x30, 0x29
+ };
+ UnicodeString pat(patChars, 19, 19);
+ nf->applyLocalizedPattern(pat, status);
+ failure(status, "nf->applyLocalizedPattern", Locale::getFrance());
+ logln("nf toPattern2: " + nf->toPattern(temp));
+ logln("nf toLocPattern2: " + nf->toLocalizedPattern(temp));
+ UnicodeString buffer;
+ buffer = nf->format((int32_t)1234, buffer, pos);
+ //if (buffer != UnicodeString("1\u00a0234,00"))
+ UChar c[] = {
+ 0x31, 0x00a0, 0x32, 0x33, 0x34, 0x2c, 0x30, 0x30
+ };
+ UnicodeString cc(c, 8, 8);
+ if (buffer != cc)
+ errln("nf : " + buffer); // Expect 1 234,00
+
+ buffer.remove();
+ buffer = nf->format((int32_t)-1234, buffer, pos);
+ UChar c1[] = {
+ 0x28, 0x31, 0x00a0, 0x32, 0x33, 0x34, 0x2c, 0x30, 0x30, 0x29
+ };
+ UnicodeString cc1(c1, 10, 10);
+ if (buffer != cc1)
+ errln("nf : " + buffer); // Expect (1 234,00)
+
+ // Erroneously prints:
+ // 1234,00 ,
+ // (1234,00 ,)
+
+ delete nf1;
+}
+/* @bug 4068693
+ * DecimalFormat.parse returns wrong value
+ */
+// {sfb} slightly converted into a round-trip test, since in C++
+// there is no Double.toString()
+void NumberFormatRegressionTest::Test4068693(void)
+{
+ logln("----- Test Application -----");
+ ParsePosition pos(0);
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ Formattable d;
+ //Double d = (Double)df.parse("123.55456", pos=new ParsePosition(0));
+ df->parse(UnicodeString("123.55456"), d, pos);
+ //if (!d.toString().equals("123.55456")) {
+ UnicodeString dstr;
+ df->setMaximumFractionDigits(999);
+ df->setMaximumIntegerDigits(999);
+ FieldPosition fp(FieldPosition::DONT_CARE);
+ dstr = df->format(d.getDouble(), dstr, fp);
+ if (dstr != UnicodeString("123.55456")) {
+ errln(UnicodeString("Result -> ") + d.getDouble());
+ }
+
+ delete df;
+}
+
+/* @bug 4069754, 4067878
+ * null pointer thrown when accessing a deserialized DecimalFormat
+ * object.
+ */
+// {sfb} doesn't apply in C++
+void NumberFormatRegressionTest::Test4069754(void)
+{
+/* try {
+ myformat it = new myformat();
+ logln(it.Now());
+ FileOutputStream ostream = new FileOutputStream("t.tmp");
+ ObjectOutputStream p = new ObjectOutputStream(ostream);
+ p.writeObject(it);
+ ostream.close();
+ logln("Saved ok.");
+
+ FileInputStream istream = new FileInputStream("t.tmp");
+ ObjectInputStream p2 = new ObjectInputStream(istream);
+ myformat it2 = (myformat)p2.readObject();
+ logln(it2.Now());
+ istream.close();
+ logln("Loaded ok.");
+ } catch (Exception foo) {
+ errln("Test for bug 4069754 or 4057878 failed => Exception: " + foo.getMessage());
+ }
+*/}
+
+/* @bug 4087251
+ * DecimalFormat.applyPattern(String) allows illegal patterns
+ */
+void NumberFormatRegressionTest::Test4087251 (void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ //try {
+ df->applyPattern(UnicodeString("#.#.#"), status);
+ if( ! U_FAILURE(status))
+ errln("df->applyPattern with illegal pattern didn't fail");
+ UnicodeString temp;
+ logln("toPattern() returns \"" + df->toPattern(temp) + "\"");
+ //errln("applyPattern(\"#.#.#\") doesn't throw IllegalArgumentException");
+ /*} catch (IllegalArgumentException e) {
+ logln("Caught Illegal Argument Error !");
+ }*/
+ // Second test; added 5/11/98 when reported to fail on 1.2b3
+ //try {
+ df->applyPattern("#0.0#0#0", status);
+ if( ! U_FAILURE(status))
+ errln("df->applyPattern with illegal pattern didn't fail");
+ logln("toPattern() returns \"" + df->toPattern(temp) + "\"");
+ //errln("applyPattern(\"#0.0#0#0\") doesn't throw IllegalArgumentException");
+ /*} catch (IllegalArgumentException e) {
+ logln("Ok - IllegalArgumentException for #0.0#0#0");
+ }*/
+
+ delete df;
+}
+
+/* @bug 4090489
+ * DecimalFormat.format() loses precision
+ */
+void NumberFormatRegressionTest::Test4090489 (void)
+{
+// {sfb} sprintf doesn't correctly handle the double, so there is nothing
+// that NumberFormat can do. For some reason, it does not format the last 1.
+
+/* UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ failure(status, "new DecimalFormat");
+ df->setMinimumFractionDigits(10);
+ df->setMaximumFractionDigits(999);
+ df->setGroupingUsed(FALSE);
+ double d = 1.000000000000001E7;
+ //BigDecimal bd = new BigDecimal(d);
+ UnicodeString sb;
+ FieldPosition fp(0);
+ logln(UnicodeString("d = ") + d);
+ //logln("BigDecimal.toString(): " + bd.toString());
+ df->format(d, sb, fp);
+ if (sb != "10000000.0000000100") {
+ errln("DecimalFormat.format(): " + sb);
+ }
+*/
+}
+
+/* @bug 4090504
+ * DecimalFormat.format() loses precision
+ */
+void NumberFormatRegressionTest::Test4090504 (void)
+{
+ double d = 1;
+ logln(UnicodeString("d = ") + d);
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ UnicodeString sb;
+ FieldPosition fp(FieldPosition::DONT_CARE);
+ //try {
+ for (int i = 17; i <= 20; i++) {
+ df->setMaximumFractionDigits(i);
+ //sb = new StringBuffer("");
+ fp.setField(0);
+ logln(" getMaximumFractionDigits() = " + i);
+ logln(" formated: " + df->format(d, sb, fp));
+ }
+ /*} catch (Exception foo) {
+ errln("Bug 4090504 regression test failed. Message : " + foo.getMessage());
+ }*/
+
+ delete df;
+}
+/* @bug 4095713
+ * DecimalFormat.parse(String str, ParsePosition pp) loses precision
+ */
+void NumberFormatRegressionTest::Test4095713 (void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ UnicodeString str("0.1234");
+ double d1 = 0.1234;
+ //Double d1 = new Double(str);
+ //Double d2 = (Double) df.parse(str, new ParsePosition(0));
+ Formattable d2;
+ ParsePosition pp(0);
+ df->parse(str, d2, pp);
+ logln(UnicodeString("") + d1);
+ if (d2.getDouble() != d1)
+ errln(UnicodeString("Bug 4095713 test failed, new double value : ") + d2.getDouble());
+ delete df;
+}
+
+/* @bug 4092561
+ * DecimalFormat.parse() fails when multiplier is not set to 1
+ */
+// {sfb} not sure what to do with this one
+void NumberFormatRegressionTest::Test4092561 (void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+
+ // {sfb} going to cheat here and use sprintf ??
+
+ /*UnicodeString str = Long.toString(Long.MIN_VALUE);
+ logln("Long.MIN_VALUE : " + df.parse(str, new ParsePosition(0)).toString());
+ df.setMultiplier(100);
+ Number num = df.parse(str, new ParsePosition(0));
+ if (num.doubleValue() != -9.223372036854776E16)
+ errln("Bug 4092561 test failed when multiplier is set to not 1.");
+*/
+ delete df;
+}
+
+/* @bug 4092480
+ * DecimalFormat: Negative format ignored.
+ */
+void NumberFormatRegressionTest::Test4092480 (void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *dfFoo = new DecimalFormat(UnicodeString("000"), status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete dfFoo;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+
+ //try {
+ dfFoo->applyPattern("0000;-000", status);
+ failure(status, "dfFoo->applyPattern");
+ UnicodeString temp;
+ if (dfFoo->toPattern(temp) != UnicodeString("#0000"))
+ errln("dfFoo.toPattern : " + dfFoo->toPattern(temp));
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ logln(dfFoo->format((int32_t)42, temp, pos));
+ logln(dfFoo->format((int32_t)-42, temp, pos));
+ dfFoo->applyPattern("000;-000", status);
+ failure(status, "dfFoo->applyPattern");
+ if (dfFoo->toPattern(temp) != UnicodeString("#000"))
+ errln("dfFoo.toPattern : " + dfFoo->toPattern(temp));
+ logln(dfFoo->format((int32_t)42,temp, pos));
+ logln(dfFoo->format((int32_t)-42, temp, pos));
+
+ dfFoo->applyPattern("000;-0000", status);
+ failure(status, "dfFoo->applyPattern");
+ if (dfFoo->toPattern(temp) != UnicodeString("#000"))
+ errln("dfFoo.toPattern : " + dfFoo->toPattern(temp));
+ logln(dfFoo->format((int32_t)42, temp, pos));
+ logln(dfFoo->format((int32_t)-42, temp, pos));
+
+ dfFoo->applyPattern("0000;-000", status);
+ failure(status, "dfFoo->applyPattern");
+ if (dfFoo->toPattern(temp) != UnicodeString("#0000"))
+ errln("dfFoo.toPattern : " + dfFoo->toPattern(temp));
+ logln(dfFoo->format((int32_t)42, temp, pos));
+ logln(dfFoo->format((int32_t)-42, temp, pos));
+ /*} catch (Exception foo) {
+ errln("Message " + foo.getMessage());
+ }*/
+
+ delete dfFoo;
+}
+/* @bug 4087244
+ * NumberFormat.getCurrencyInstance() produces format that uses
+ * decimal separator instead of monetary decimal separator.
+ *
+ * Rewrote this test not to depend on the actual pattern. Pattern should
+ * never contain the monetary separator! Decimal separator in pattern is
+ * interpreted as monetary separator if currency symbol is seen!
+ */
+void NumberFormatRegressionTest::Test4087244 (void) {
+ UErrorCode status = U_ZERO_ERROR;
+ char loc[256] = {0};
+ uloc_canonicalize("pt_PT_PREEURO", loc, 256, &status);
+ Locale *de = new Locale(loc);
+ NumberFormat *nf = NumberFormat::createCurrencyInstance(*de, status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete nf;
+ return;
+ }
+ if (nf->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ errln("expected DecimalFormat!");
+ return;
+ }
+ DecimalFormat *df = (DecimalFormat*) nf;
+ const DecimalFormatSymbols *sym = df->getDecimalFormatSymbols();
+ UnicodeString decSep = sym->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ UnicodeString monSep = sym->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
+ if (decSep == monSep) {
+ errln("ERROR in test: want decimal sep != monetary sep");
+ return;
+ }
+ df->setMinimumIntegerDigits(1);
+ df->setMinimumFractionDigits(2);
+ UnicodeString str;
+ FieldPosition pos;
+ df->format(1.23, str, pos);
+ UnicodeString monStr("1x23");
+ monStr.replace((int32_t)1, 1, monSep);
+ UnicodeString decStr("1x23");
+ decStr.replace((int32_t)1, 1, decSep);
+ if (str.indexOf(monStr) >= 0 && str.indexOf(decStr) < 0) {
+ logln(UnicodeString("OK: 1.23 -> \"") + str + "\" contains \"" +
+ monStr + "\" and not \"" + decStr + '"');
+ } else {
+ errln(UnicodeString("FAIL: 1.23 -> \"") + str + "\", should contain \"" +
+ monStr +
+ "\" and not \"" + decStr + '"');
+ }
+ delete de;
+ delete nf;
+}
+/* @bug 4070798
+ * Number format data rounding errors for locale FR
+ */
+void NumberFormatRegressionTest::Test4070798 (void)
+{
+ NumberFormat *formatter;
+ UnicodeString tempString;
+
+ /* User error :
+ String expectedDefault = "-5\u00a0789,987";
+ String expectedCurrency = "5\u00a0789,98 F";
+ String expectedPercent = "-578\u00a0998%";
+ */
+ UChar chars1 [] = {
+ 0x2d, 0x35, 0x00a0, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x38, 0x38
+ };
+ UChar chars2 [] = {
+ 0x35, 0x00a0, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x39, 0x20, 0x46
+ };
+ UChar chars3 [] = {
+ 0x2d, 0x35, 0x37, 0x38, 0x00a0, 0x39, 0x39, 0x39, 0x00a0, 0x25
+ };
+ UnicodeString expectedDefault(chars1, 10, 10);
+ UnicodeString expectedCurrency(chars2, 10, 10);
+ UnicodeString expectedPercent(chars3, 10, 10);
+
+ UErrorCode status = U_ZERO_ERROR;
+ char loc[256]={0};
+ int len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);
+ formatter = NumberFormat::createInstance(Locale(loc), status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete formatter;
+ return;
+ }
+ failure(status, "NumberFormat::createNumberInstance", loc);
+ tempString = formatter->format (-5789.9876, tempString);
+
+ if (tempString == expectedDefault) {
+ logln ("Bug 4070798 default test passed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedDefault +
+ " Received " + tempString );
+ }
+ delete formatter;
+ len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);
+ formatter = NumberFormat::createCurrencyInstance(loc, status);
+ failure(status, "NumberFormat::createCurrencyInstance", loc);
+ tempString.remove();
+ tempString = formatter->format( 5789.9876, tempString );
+
+ if (tempString == expectedCurrency) {
+ logln ("Bug 4070798 currency test passed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedCurrency +
+ " Received " + tempString );
+ }
+ delete formatter;
+
+ uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);
+ formatter = NumberFormat::createPercentInstance(Locale(loc), status);
+ failure(status, "NumberFormat::createPercentInstance", loc);
+ tempString.remove();
+ tempString = formatter->format (-5789.9876, tempString);
+
+ if (tempString == expectedPercent) {
+ logln ("Bug 4070798 percentage test passed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedPercent +
+ " Received " + tempString );
+ }
+
+ delete formatter;
+}
+/* @bug 4071005
+ * Data rounding errors for French (Canada) locale
+ */
+void NumberFormatRegressionTest::Test4071005 (void)
+{
+ NumberFormat *formatter;
+ UnicodeString tempString;
+ /* User error :
+ String expectedDefault = "-5\u00a0789,987";
+ String expectedCurrency = "5\u00a0789,98 $";
+ String expectedPercent = "-578\u00a0998%";
+ */
+ UChar chars1 [] = {
+ 0x2d, 0x35, 0x00a0, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x38, 0x38
+ };
+ UChar chars2 [] = {
+ 0x35, 0x00a0, 0x37, 0x38, 0x39, 0x2c, 0x39, 0x39, 0x20, 0x24
+ };
+ UChar chars3 [] = {
+ 0x2d, 0x35, 0x37, 0x38, 0x00a0, 0x39, 0x39, 0x39, 0x00a0, 0x25
+ };
+ UnicodeString expectedDefault(chars1, 10, 10);
+ UnicodeString expectedCurrency(chars2, 10, 10);
+ UnicodeString expectedPercent(chars3, 10, 10);
+
+ UErrorCode status = U_ZERO_ERROR;
+ formatter = NumberFormat::createInstance(Locale::getCanadaFrench(), status);
+ if (failure(status, "NumberFormat::createNumberInstance", Locale::getCanadaFrench())){
+ delete formatter;
+ return;
+ };
+ tempString = formatter->format (-5789.9876, tempString);
+
+ if (tempString == expectedDefault) {
+ logln ("Bug 4071005 default test passed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedDefault +
+ " Received " + tempString );
+ }
+ delete formatter;
+
+ formatter = NumberFormat::createCurrencyInstance(Locale::getCanadaFrench(), status);
+ failure(status, "NumberFormat::createCurrencyInstance", Locale::getCanadaFrench());
+ tempString.remove();
+ tempString = formatter->format( 5789.9876, tempString );
+
+ if (tempString == expectedCurrency) {
+ logln ("Bug 4071005 currency test assed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedCurrency +
+ " Received " + tempString );
+ }
+ delete formatter;
+
+ formatter = NumberFormat::createPercentInstance(Locale::getCanadaFrench(), status);
+ failure(status, "NumberFormat::createPercentInstance", Locale::getCanadaFrench());
+ tempString.remove();
+ tempString = formatter->format (-5789.9876, tempString);
+
+ if (tempString == expectedPercent) {
+ logln ("Bug 4071005 percentage test passed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedPercent +
+ " Received " + tempString );
+ }
+
+ delete formatter;
+}
+
+/* @bug 4071014
+ * Data rounding errors for German (Germany) locale
+ */
+void NumberFormatRegressionTest::Test4071014 (void)
+{
+ NumberFormat *formatter;
+ UnicodeString tempString;
+ /* user error :
+ String expectedDefault = "-5.789,987";
+ String expectedCurrency = "5.789,98 DM";
+ String expectedPercent = "-578.998%";
+ */
+ UnicodeString expectedDefault("-5.789,988");
+ UnicodeString expectedCurrency("5.789,99 DM");
+ UnicodeString expectedPercent("-578.999 %");
+
+ UErrorCode status = U_ZERO_ERROR;
+ char loc[256]={0};
+ uloc_canonicalize("de_DE_PREEURO", loc, 256, &status);
+ formatter = NumberFormat::createInstance(Locale(loc), status);
+ if (failure(status, "NumberFormat::createNumberInstance", loc)){
+ delete formatter;
+ return;
+ }
+ tempString.remove();
+ tempString = formatter->format (-5789.9876, tempString);
+
+ if (tempString == expectedDefault) {
+ logln ("Bug 4071014 default test passed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedDefault +
+ " Received " + tempString );
+ }
+ delete formatter;
+ uloc_canonicalize("de_DE_PREEURO", loc, 256, &status);
+ formatter = NumberFormat::createCurrencyInstance(Locale(loc), status);
+ failure(status, "NumberFormat::createCurrencyInstance", loc);
+ tempString.remove();
+ tempString = formatter->format( 5789.9876, tempString );
+
+ if (tempString == expectedCurrency) {
+ logln ("Bug 4071014 currency test assed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedCurrency +
+ " Received " + tempString );
+ }
+ delete formatter;
+
+ formatter = NumberFormat::createPercentInstance(Locale::getGermany(), status);
+ failure(status, "NumberFormat::createPercentInstance", Locale::getGermany());
+ tempString.remove();
+ tempString = formatter->format (-5789.9876, tempString);
+
+ if (tempString == expectedPercent) {
+ logln ("Bug 4071014 percentage test passed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedPercent +
+ " Received " + tempString );
+ }
+
+ delete formatter;
+}
+/* @bug 4071859
+ * Data rounding errors for Italian locale number formats
+ */
+void NumberFormatRegressionTest::Test4071859 (void)
+{
+ NumberFormat *formatter;
+ UnicodeString tempString;
+ /* user error :
+ String expectedDefault = "-5.789,987";
+ String expectedCurrency = "-L. 5.789,98";
+ String expectedPercent = "-578.998%";
+ */
+ UnicodeString expectedDefault("-5.789,988");
+ UnicodeString expectedCurrency("-\\u20A4 5.790");
+ UnicodeString expectedPercent("-578.999%");
+ expectedCurrency = expectedCurrency.unescape();
+
+ UErrorCode status = U_ZERO_ERROR;
+ char loc[256]={0};
+ uloc_canonicalize("it_IT_PREEURO", loc, 256, &status);
+ formatter = NumberFormat::createInstance(Locale(loc), status);
+ if (failure(status, "NumberFormat::createNumberInstance")){
+ delete formatter;
+ return;
+ };
+ tempString = formatter->format (-5789.9876, tempString);
+
+ if (tempString == expectedDefault) {
+ logln ("Bug 4071859 default test passed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedDefault +
+ " Received " + tempString );
+ }
+ delete formatter;
+ uloc_canonicalize("it_IT_PREEURO", loc, 256, &status);
+ formatter = NumberFormat::createCurrencyInstance(Locale(loc), status);
+ failure(status, "NumberFormat::createCurrencyInstance");
+ tempString.remove();
+ tempString = formatter->format( -5789.9876, tempString );
+
+ if (tempString == expectedCurrency) {
+ logln ("Bug 4071859 currency test assed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedCurrency +
+ " Received " + tempString );
+ }
+ delete formatter;
+ uloc_canonicalize("it_IT_PREEURO", loc, 256, &status);
+ formatter = NumberFormat::createPercentInstance(Locale(loc), status);
+ failure(status, "NumberFormat::createPercentInstance");
+ tempString.remove();
+ tempString = formatter->format (-5789.9876, tempString);
+
+ if (tempString == expectedPercent) {
+ logln ("Bug 4071859 percentage test passed.");
+ } else {
+ errln(UnicodeString("Failed:") +
+ " Expected " + expectedPercent +
+ " Received " + tempString );
+ }
+
+ delete formatter;
+}
+/* @bug 4071859
+ * Test rounding for nearest even.
+ */
+void NumberFormatRegressionTest::Test4093610(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat("#0.#", status);
+ failure(status, "new DecimalFormat");
+ UnicodeString s("12.4");
+ roundingTest(df, 12.35, s);
+ roundingTest(df, 12.45, s);
+ s = "12.5";
+ roundingTest(df, 12.452,s);
+ s = "12.6";
+ roundingTest(df, 12.55, s);
+ roundingTest(df, 12.65, s);
+ s = "12.7";
+ roundingTest(df, 12.652,s);
+ s = "12.8";
+ roundingTest(df, 12.75, s);
+ roundingTest(df, 12.752,s);
+ roundingTest(df, 12.85, s);
+ s = "12.9";
+ roundingTest(df, 12.852,s);
+ s = "13";
+ roundingTest(df, 12.95, s);
+ roundingTest(df, 12.952,s);
+
+ delete df;
+}
+
+void NumberFormatRegressionTest::roundingTest(DecimalFormat *df, double x, UnicodeString& expected)
+{
+ UnicodeString out;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ out = df->format(x, out, pos);
+ logln(UnicodeString("") + x + " formats with 1 fractional digits to " + out);
+ if (out != expected)
+ errln("FAIL: Expected " + expected);
+}
+/* @bug 4098741
+ * Tests the setMaximumFractionDigits limit.
+ */
+void NumberFormatRegressionTest::Test4098741(void)
+{
+ //try {
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *fmt = NumberFormat::createPercentInstance(status);
+ if (U_FAILURE(status)) {
+ dataerrln("Error calling NumberFormat::createPercentInstance");
+ delete fmt;
+ return;
+ }
+
+ fmt->setMaximumFractionDigits(20);
+ UnicodeString temp;
+ logln(fmt->format(.001, temp));
+ /*} catch (Exception foo) {
+ errln("Bug 4098471 failed with exception thrown : " + foo.getMessage());
+ }*/
+ delete fmt;
+}
+/* @bug 4074454
+ * Tests illegal pattern exception.
+ * Fix comment : HShih A31 Part1 will not be fixed and javadoc needs to be updated.
+ * Part2 has been fixed.
+ */
+void NumberFormatRegressionTest::Test4074454(void)
+{
+ //try {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *fmt = new DecimalFormat("#,#00.00;-#.#", status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete fmt;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ logln("Inconsistent negative pattern is fine.");
+ DecimalFormat *newFmt = new DecimalFormat("#,#00.00 p''ieces;-#,#00.00 p''ieces", status);
+ failure(status, "new DecimalFormat");
+ UnicodeString tempString;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ tempString = newFmt->format(3456.78, tempString, pos);
+ if (tempString != UnicodeString("3,456.78 p'ieces"))
+ errln("Failed! 3456.78 p'ieces expected, but got : " + tempString);
+ /*} catch (Exception foo) {
+ errln("An exception was thrown for any inconsistent negative pattern.");
+ }*/
+
+ delete fmt;
+ delete newFmt;
+}
+/* @bug 4099404
+ * Tests all different comments.
+ * Response to some comments :
+ * [1] DecimalFormat.parse API documentation is more than just one line.
+ * This is not a reproducable doc error in 116 source code.
+ * [2] See updated javadoc.
+ * [3] Fixed.
+ * [4] NumberFormat.parse(String, ParsePosition) : If parsing fails,
+ * a null object will be returned. The unchanged parse position also
+ * reflects an error.
+ * NumberFormat.parse(String) : If parsing fails, an ParseException
+ * will be thrown.
+ * See updated javadoc for more details.
+ * [5] See updated javadoc.
+ * [6] See updated javadoc.
+ * [7] This is a correct behavior if the DateFormat object is linient.
+ * Otherwise, an IllegalArgumentException will be thrown when formatting
+ * "January 35". See GregorianCalendar class javadoc for more details.
+ */
+void NumberFormatRegressionTest::Test4099404(void)
+{
+ //try {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *fmt = new DecimalFormat(UnicodeString("000.0#0"), status);
+ if(! U_FAILURE(status))
+ errln(UnicodeString("Bug 4099404 failed applying illegal pattern \"000.0#0\""));
+ /*} catch (Exception foo) {
+ logln("Bug 4099404 pattern \"000.0#0\" passed");
+ }*/
+ delete fmt;
+ fmt = 0;
+ //try {
+ fmt = new DecimalFormat(UnicodeString("0#0.000"), status);
+ if( !U_FAILURE(status))
+ errln("Bug 4099404 failed applying illegal pattern \"0#0.000\"");
+ /*} catch (Exception foo) {
+ logln("Bug 4099404 pattern \"0#0.000\" passed");
+ }*/
+
+ delete fmt;
+}
+/* @bug 4101481
+ * DecimalFormat.applyPattern doesn't set minimum integer digits
+ */
+void NumberFormatRegressionTest::Test4101481(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *sdf = new DecimalFormat(UnicodeString("#,##0"), status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete sdf;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ if (sdf->getMinimumIntegerDigits() != 1)
+ errln("Minimum integer digits : " + sdf->getMinimumIntegerDigits());
+ delete sdf;
+}
+/* @bug 4052223 (API addition request A27)
+ * Tests ParsePosition.setErrorPosition() and ParsePosition.getErrorPosition().
+ */
+void NumberFormatRegressionTest::Test4052223(void)
+{
+ //try {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *fmt = new DecimalFormat(UnicodeString("#,#00.00"), status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete fmt;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ Formattable num;
+ fmt->parse(UnicodeString("abc3"), num, status);
+ if(! U_FAILURE(status))
+ errln(UnicodeString("Bug 4052223 failed : can't parse string \"a\". Got ") /*+ num*/);
+ /*} catch (ParseException foo) {
+ logln("Caught expected ParseException : " + foo.getMessage() + " at index : " + foo.getErrorOffset());
+ }*/
+ delete fmt;
+}
+/* @bug 4061302
+ * API tests for API addition request A9.
+ */
+void NumberFormatRegressionTest::Test4061302(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols *fmt = new DecimalFormatSymbols(status);
+ failure(status, "new DecimalFormatSymbols");
+ UnicodeString currency(fmt->getSymbol(DecimalFormatSymbols::kCurrencySymbol));
+ UnicodeString intlCurrency(fmt->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol));
+ UnicodeString monDecSeparator(fmt->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol));
+ if (currency == UnicodeString("") ||
+ intlCurrency == UnicodeString("") ||
+ monDecSeparator == UnicodeString(""))
+ {
+ errln("getCurrencySymbols failed, got empty string.");
+ }
+ UnicodeString monDecSeparatorStr;
+ monDecSeparatorStr.append(monDecSeparator);
+ logln((UnicodeString)"Before set ==> Currency : " + currency +(UnicodeString)" Intl Currency : " + intlCurrency + (UnicodeString)" Monetary Decimal Separator : " + monDecSeparatorStr);
+ fmt->setSymbol(DecimalFormatSymbols::kCurrencySymbol, UnicodeString("XYZ"));
+ fmt->setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, UnicodeString("ABC"));
+ fmt->setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, UnicodeString((UChar)0x002A/*'*'*/));
+ currency = fmt->getSymbol(DecimalFormatSymbols::kCurrencySymbol);
+ intlCurrency = fmt->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
+ monDecSeparator = fmt->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
+ if (currency != UnicodeString("XYZ") ||
+ intlCurrency != UnicodeString("ABC") ||
+ monDecSeparator != UnicodeString((UChar)0x002A/*'*'*/)) {
+ errln("setCurrencySymbols failed.");
+ }
+ monDecSeparatorStr.remove();
+ monDecSeparatorStr.append(monDecSeparator);
+ logln("After set ==> Currency : " + currency + " Intl Currency : " + intlCurrency + " Monetary Decimal Separator : " + monDecSeparatorStr);
+
+ delete fmt;
+}
+/* @bug 4062486
+ * API tests for API addition request A23. FieldPosition.getBeginIndex and
+ * FieldPosition.getEndIndex.
+ */
+void NumberFormatRegressionTest::Test4062486(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *fmt = new DecimalFormat(UnicodeString("#,##0.00"), status);
+ failure(status, "new DecimalFormat");
+ UnicodeString formatted;
+ FieldPosition field(0);
+ double num = 1234.5;
+ fmt->format(num, formatted, field);
+ if (field.getBeginIndex() != 0 && field.getEndIndex() != 5)
+ errln(UnicodeString("Format 1234.5 failed. Begin index: ") /*+ field.getBeginIndex() + " End index: " + field.getEndIndex()*/);
+ field.setBeginIndex(7);
+ field.setEndIndex(4);
+ if (field.getBeginIndex() != 7 && field.getEndIndex() != 4)
+ errln("Set begin/end field indexes failed. Begin index: " /*+ field.getBeginIndex() + " End index: " + field.getEndIndex()*/);
+
+ delete fmt;
+}
+
+/* @bug 4108738
+ * DecimalFormat.parse incorrectly works with a group separator.
+ */
+void NumberFormatRegressionTest::Test4108738(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale::getUS(), status);
+ failure(status, "new DecimalFormatSymbols");
+ DecimalFormat *df = new DecimalFormat("#,##0.###", syms, status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ UnicodeString text("1.222,111");
+ Formattable num;
+ ParsePosition pp(0);
+ df->parse(text, num, pp);
+
+ // {sfb} how to do this (again) ?
+ // shouldn't just be another round-trip test, should it?
+ UnicodeString temp;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ temp = df->format(num.getDouble(), temp, pos);
+ //if (!num.toString().equals("1.222"))
+ if (temp != UnicodeString("1.222"))
+ //errln("\"" + text + "\" is parsed as " + num);
+ errln("\"" + text + "\" is parsed as " + temp);
+ text = UnicodeString("1.222x111");
+ pp = ParsePosition(0);
+ df->parse(text, num, pp);
+ temp.remove();
+ temp = df->format(num.getDouble(), temp, pos);
+ //if (!num.toString().equals("1.222"))
+ if (temp != UnicodeString("1.222"))
+ errln("\"" + text + "\" is parsed as " + temp);
+
+ delete df;
+}
+
+/* @bug 4106658
+ * DecimalFormat.format() incorrectly formats negative doubles.
+ */
+void NumberFormatRegressionTest::Test4106658(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status); // Corrected; see 4147706
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ volatile double d1 = 0.0; // volatile to prevent code optimization
+ double d2 = -0.0001;
+ UnicodeString buffer;
+ UnicodeString temp;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+
+#if defined(U_HPUX)
+ d1 = 0.0 * -1.0; // old HPUX compiler ignores volatile keyword
+#else
+ d1 *= -1.0; // Some compilers have a problem with defining -0.0
+#endif
+ logln("pattern: \"" + df->toPattern(temp) + "\"");
+ df->format(d1, buffer, pos);
+ if (buffer != UnicodeString("-0")) // Corrected; see 4147706
+ errln(UnicodeString("") + d1 + " is formatted as " + buffer);
+ buffer.remove();
+ df->format(d2, buffer, pos);
+ if (buffer != UnicodeString("-0")) // Corrected; see 4147706
+ errln(UnicodeString("") + d2 + " is formatted as " + buffer);
+
+ delete df;
+}
+
+/* @bug 4106662
+ * DecimalFormat.parse returns 0 if string parameter is incorrect.
+ */
+void NumberFormatRegressionTest::Test4106662(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ UnicodeString text("x");
+ ParsePosition pos1(0), pos2(0);
+
+ UnicodeString temp;
+ logln("pattern: \"" + df->toPattern(temp) + "\"");
+ Formattable num;
+ df->parse(text, num, pos1);
+ if (pos1 == ParsePosition(0)/*num != null*/) {
+ errln(UnicodeString("Test Failed: \"") + text + "\" is parsed as " /*+ num*/);
+ }
+ delete df;
+ df = new DecimalFormat(UnicodeString("$###.00"), status);
+ failure(status, "new DecimalFormat");
+ df->parse(UnicodeString("$"), num, pos2);
+ if (pos2 == ParsePosition(0) /*num != null*/){
+ errln(UnicodeString("Test Failed: \"$\" is parsed as ") /*+ num*/);
+ }
+
+ delete df;
+}
+
+/* @bug 4114639 (duplicate of 4106662)
+ * NumberFormat.parse doesn't return null
+ */
+void NumberFormatRegressionTest::Test4114639(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *format = NumberFormat::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete format;
+ return;
+ }
+ failure(status, "NumberFormat::createInstance");
+ UnicodeString text("time 10:x");
+ ParsePosition pos(8);
+ Formattable result;
+ format->parse(text, result, pos);
+ if (/*result != null*/pos.getErrorIndex() != 8)
+ errln(UnicodeString("Should return null but got : ") /*+ result*/); // Should be null; it isn't
+
+ delete format;
+}
+
+/* @bug 4106664
+ * TODO: this test does not work because we need to use a 64 bit number and a
+ * a double only MAY only have 52 bits of precision.
+ * DecimalFormat.format(long n) fails if n * multiplier > MAX_LONG.
+ */
+void NumberFormatRegressionTest::Test4106664(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ // {sfb} long in java is 64 bits
+ /*long*/double n = 1234567890123456.0;
+ /*int*/int32_t m = 12345678;
+ // {sfb} will this work?
+ //BigInteger bigN = BigInteger.valueOf(n);
+ //bigN = bigN.multiply(BigInteger.valueOf(m));
+ double bigN = n * m;
+ df->setMultiplier(m);
+ df->setGroupingUsed(FALSE);
+ UnicodeString temp;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ logln("formated: " +
+ df->format(n, temp, pos));
+
+ char buf [128];
+ sprintf(buf, "%g", bigN);
+ //logln("expected: " + bigN.toString());
+ logln(UnicodeString("expected: ") + buf);
+
+ delete df;
+}
+/* @bug 4106667 (duplicate of 4106658)
+ * DecimalFormat.format incorrectly formats -0.0.
+ */
+void NumberFormatRegressionTest::Test4106667(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete df;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ UChar foo [] = { 0x002B };
+ UnicodeString bar(foo, 1, 1);
+ volatile double d = 0.0; // volatile to prevent code optimization
+ UnicodeString temp;
+ UnicodeString buffer;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+
+ logln("pattern: \"" + df->toPattern(temp) + "\"");
+#if defined(U_HPUX)
+ d = 0.0 * -1.0; // old HPUX compiler ignores volatile keyword
+#else
+ d *= -1.0; // Some compilers have a problem with defining -0.0
+#endif
+ df->setPositivePrefix(/*"+"*/bar);
+ df->format(d, buffer, pos);
+ if (buffer != UnicodeString("-0")) // Corrected; see 4147706
+ errln(/*d + */UnicodeString(" is formatted as ") + buffer);
+
+ delete df;
+}
+
+/* @bug 4110936
+ * DecimalFormat.setMaximumIntegerDigits() works incorrectly.
+ */
+#ifdef OS390
+# define MAX_INT_DIGITS 70
+#else
+# define MAX_INT_DIGITS 128
+#endif
+
+void NumberFormatRegressionTest::Test4110936(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nf = NumberFormat::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete nf;
+ return;
+ }
+ failure(status, "NumberFormat::createInstance");
+ nf->setMaximumIntegerDigits(MAX_INT_DIGITS);
+ logln("setMaximumIntegerDigits(MAX_INT_DIGITS)");
+ if (nf->getMaximumIntegerDigits() != MAX_INT_DIGITS)
+ errln("getMaximumIntegerDigits() returns " +
+ nf->getMaximumIntegerDigits());
+
+ delete nf;
+}
+
+/* @bug 4122840
+ * Locale data should use generic currency symbol
+ *
+ * 1) Make sure that all currency formats use the generic currency symbol.
+ * 2) Make sure we get the same results using the generic symbol or a
+ * hard-coded one.
+ */
+void NumberFormatRegressionTest::Test4122840(void)
+{
+ int32_t count = 0;
+ const Locale *locales = Locale::getAvailableLocales(count);
+
+ for (int i = 0; i < count; i++) {
+ UErrorCode status = U_ZERO_ERROR;
+ ResourceBundle *rb = new ResourceBundle(
+ NULL/*"java.text.resources.LocaleElements"*/,
+ locales[i], status);
+ failure(status, "new ResourceBundle");
+ ResourceBundle numPat = rb->get("NumberPatterns", status);
+ failure(status, "new ResourceBundle(NumberPatterns)");
+ //
+ // Get the currency pattern for this locale. We have to fish it
+ // out of the ResourceBundle directly, since DecimalFormat.toPattern
+ // will return the localized symbol, not \00a4
+ //
+ UnicodeString pattern = numPat.getStringEx(1, status);
+ failure(status, "rb->getStringArray");
+
+ UChar fo[] = { 0x00A4 };
+ UnicodeString foo(fo, 1, 1);
+
+ //if (pattern.indexOf("\u00A4") == -1 ) {
+ if (pattern.indexOf(foo) == -1 ) {
+ errln(UnicodeString("Currency format for ") + UnicodeString(locales[i].getName()) +
+ " does not contain generic currency symbol:" +
+ pattern );
+ }
+
+ // Create a DecimalFormat using the pattern we got and format a number
+ DecimalFormatSymbols *symbols = new DecimalFormatSymbols(locales[i], status);
+ failure(status, "new DecimalFormatSymbols");
+ DecimalFormat *fmt1 = new DecimalFormat(pattern, *symbols, status);
+ failure(status, "new DecimalFormat");
+
+ UnicodeString result1;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ result1 = fmt1->format(1.111, result1, pos);
+
+ //
+ // Now substitute in the locale's currency symbol and create another
+ // pattern. We have to skip locales where the currency symbol
+ // contains decimal separators, because that confuses things
+ //
+ UChar ba[] = { 0x002E/*'.'*/ };
+ UnicodeString bar(ba, 1, 1);
+
+ if (symbols->getSymbol(DecimalFormatSymbols::kCurrencySymbol).indexOf(bar) == -1) {
+ // {sfb} Also, switch the decimal separator to the monetary decimal
+ // separator to mimic the behavior of a currency format
+ symbols->setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol,
+ symbols->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol));
+
+ UnicodeString buf(pattern);
+ for (int j = 0; j < buf.length(); j++) {
+ if (buf[j] == 0x00a4 ) {
+ if(buf[j + 1] == 0x00a4) {
+ // {sfb} added to support double currency marker (intl currency sign)
+ buf.replace(j, /*j+*/2, symbols->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol));
+ j += symbols->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol).length();
+ }
+ else {
+ buf.replace(j, /*j+*/1, symbols->getSymbol(DecimalFormatSymbols::kCurrencySymbol));
+ j += symbols->getSymbol(DecimalFormatSymbols::kCurrencySymbol).length() - 1;
+ }
+ }
+ }
+
+ DecimalFormat *fmt2 = new DecimalFormat(buf, *symbols, status);
+ failure(status, "new DecimalFormat");
+
+ // Get the currency (if there is one) so we can set the rounding and fraction
+ const UChar *currency = fmt1->getCurrency();
+ if (*currency != 0) {
+ double rounding = ucurr_getRoundingIncrement(currency, &status);
+ int32_t frac = ucurr_getDefaultFractionDigits(currency, &status);
+ if (U_SUCCESS(status)) {
+ fmt2->setRoundingIncrement(rounding);
+ fmt2->setMinimumFractionDigits(frac);
+ fmt2->setMaximumFractionDigits(frac);
+ }
+ else {
+ failure(status, "Fetching currency rounding/fractions");
+ }
+ }
+
+ UnicodeString result2;
+ fmt2->format(1.111, result2, pos);
+
+ if (result1 != result2) {
+ errln("Results for " + (UnicodeString)(locales[i].getName()) + " differ: " +
+ result1 + " vs " + result2);
+ }
+
+ delete fmt2;
+ }
+
+ delete rb;
+ delete fmt1;
+ delete symbols;
+ }
+}
+
+/* @bug 4125885
+ * DecimalFormat.format() delivers wrong string.
+ */
+void NumberFormatRegressionTest::Test4125885(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ double rate = 12.34;
+ DecimalFormat *formatDec = new DecimalFormat ("000.00", status);
+ if(U_FAILURE(status)) {
+ errln("Error creating DecimalFormat: %s", u_errorName(status));
+ delete formatDec;
+ return;
+ }
+ failure(status, "new DecimalFormat");
+ UnicodeString temp;
+ logln("toPattern: " + formatDec->toPattern(temp));
+ UnicodeString rateString;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ rateString = formatDec->format(rate, rateString, pos);
+ if (rateString != UnicodeString("012.34"))
+ errln("result : " + rateString + " expected : 012.34");
+ rate = 0.1234;
+ delete formatDec;// = null;
+ formatDec = new DecimalFormat ("+000.00%;-000.00%", status);
+ failure(status, "new DecimalFormat");
+ logln("toPattern: " + formatDec->toPattern(temp));
+ rateString.remove();
+ rateString = formatDec->format(rate, rateString, pos);
+ if (rateString != UnicodeString("+012.34%"))
+ errln("result : " + rateString + " expected : +012.34%");
+
+ delete formatDec;
+}
+
+/**
+ * @bug 4134034
+ * DecimalFormat produces extra zeros when formatting numbers.
+ */
+void NumberFormatRegressionTest::Test4134034(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *nf = new DecimalFormat("##,###,###.00", status);
+ failure(status, "new DecimalFormat");
+
+ UnicodeString f;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ f = nf->format(9.02, f, pos);
+ if (f == UnicodeString("9.02"))
+ logln(f + " ok");
+ else
+ errln("9.02 -> " + f + "; want 9.02");
+
+ f.remove();
+ f = nf->format((int32_t)0, f, pos);
+ if (f == UnicodeString(".00"))
+ logln(f + " ok");
+ else
+ errln("0 -> " + f + "; want .00");
+
+ delete nf;
+}
+
+/**
+ * @bug 4134300
+ * CANNOT REPRODUCE - This bug could not be reproduced. It may be
+ * a duplicate of 4134034.
+ *
+ * JDK 1.1.6 Bug, did NOT occur in 1.1.5
+ * Possibly related to bug 4125885.
+ *
+ * This class demonstrates a regression in version 1.1.6
+ * of DecimalFormat class.
+ *
+ * 1.1.6 Results
+ * Value 1.2 Format #.00 Result '01.20' !!!wrong
+ * Value 1.2 Format 0.00 Result '001.20' !!!wrong
+ * Value 1.2 Format 00.00 Result '0001.20' !!!wrong
+ * Value 1.2 Format #0.0# Result '1.2'
+ * Value 1.2 Format #0.00 Result '001.20' !!!wrong
+ *
+ * 1.1.5 Results
+ * Value 1.2 Format #.00 Result '1.20'
+ * Value 1.2 Format 0.00 Result '1.20'
+ * Value 1.2 Format 00.00 Result '01.20'
+ * Value 1.2 Format #0.0# Result '1.2'
+ * Value 1.2 Format #0.00 Result '1.20'
+ */
+void NumberFormatRegressionTest::Test4134300(void) {
+ UnicodeString DATA [] = {
+ // Pattern Expected string
+ UnicodeString("#.00"), UnicodeString("1.20"),
+ UnicodeString("0.00"), UnicodeString("1.20"),
+ UnicodeString("00.00"), UnicodeString("01.20"),
+ UnicodeString("#0.0#"), UnicodeString("1.2"),
+ UnicodeString("#0.00"), UnicodeString("1.20")
+ };
+
+ for (int i=0; i< 10; i+=2) {
+ UnicodeString result;
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(DATA[i], status);
+ failure(status, "new DecimalFormat");
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ result = df->format(1.2, result, pos);
+ if (result != DATA[i+1]) {
+ errln("Fail: 1.2 x " + DATA[i] + " = " + result +
+ "; want " + DATA[i+1]);
+ }
+ else {
+ logln("Ok: 1.2 x " + DATA[i] + " = " + result);
+ }
+
+ delete df;
+ }
+}
+
+/**
+ * @bug 4140009
+ * Empty pattern produces double negative prefix.
+ */
+void NumberFormatRegressionTest::Test4140009(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale::getEnglish(), status);
+ failure(status, "new DecimalFormatSymbols");
+ DecimalFormat *f = new DecimalFormat(UnicodeString(""), syms, status);
+ failure(status, "new DecimalFormat");
+ UnicodeString s;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ s = f->format(123.456, s, pos);
+ if (s != UnicodeString("123.456"))
+ errln("Fail: Format empty pattern x 123.456 => " + s);
+ s.remove();
+ s = f->format(-123.456, s, pos);
+ if (s != UnicodeString("-123.456"))
+ errln("Fail: Format empty pattern x -123.456 => " + s);
+ delete f;
+}
+
+/**
+ * @bug 4141750
+ * BigDecimal numbers get their fractions truncated by NumberFormat.
+ */
+// {sfb} not pertinent in C++ ??
+void NumberFormatRegressionTest::Test4141750(void) {
+ /*try {
+ UnicodeString str("12345.67");
+ BigDecimal bd = new BigDecimal(str);
+ String sd = NumberFormat.getInstance(Locale.US).format(bd);
+ if (!sd.endsWith("67")) errln("Fail: " + str + " x format -> " + sd);
+ }
+ catch (Exception e) {
+ errln(e.toString());
+ e.printStackTrace();
+ }*/
+}
+
+/**
+ * @bug 4145457
+ * DecimalFormat toPattern() doesn't quote special characters or handle
+ * single quotes.
+ */
+void NumberFormatRegressionTest::Test4145457() {
+ //try {
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nff = NumberFormat::createInstance(status);
+ if (failure(status, "NumberFormat::createInstance")){
+ delete nff;
+ return;
+ };
+ if(nff->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ errln("DecimalFormat needed to continue");
+ return;
+ }
+
+ DecimalFormat *nf = (DecimalFormat*)nff;
+ DecimalFormatSymbols *sym = (DecimalFormatSymbols*) nf->getDecimalFormatSymbols();
+ sym->setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, (UChar)/*'\''*/0x0027);
+ nf->setDecimalFormatSymbols(*sym);
+ double pi = 3.14159;
+
+ UnicodeString PATS [] = {
+ UnicodeString("#.00 'num''ber'"), UnicodeString("''#.00''")
+ };
+
+ for (int32_t i=0; i<2; ++i) {
+ nf->applyPattern(PATS[i], status);
+ failure(status, "nf->applyPattern");
+ UnicodeString out;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ out = nf->format(pi, out, pos);
+ UnicodeString pat;
+ pat = nf->toPattern(pat);
+ Formattable num;
+ ParsePosition pp(0);
+ nf->parse(out, num, pp);
+ double val = num.getDouble();
+
+ nf->applyPattern(pat, status);
+ failure(status, "nf->applyPattern");
+ UnicodeString out2;
+ out2 = nf->format(pi, out2, pos);
+ UnicodeString pat2;
+ pat2 = nf->toPattern(pat2);
+ nf->parse(out2, num, pp);
+ double val2 = num.getDouble();
+
+ if (pat != pat2)
+ errln("Fail with \"" + PATS[i] + "\": Patterns should concur, \"" +
+ pat + "\" vs. \"" + pat2 + "\"");
+ else
+ logln("Ok \"" + PATS[i] + "\" toPattern() -> \"" + pat + '"');
+
+ if (val == val2 && out == out2) {
+ logln(UnicodeString("Ok ") + pi + " x \"" + PATS[i] + "\" -> \"" +
+ out + "\" -> " + val + " -> \"" +
+ out2 + "\" -> " + val2);
+ }
+ else {
+ errln(UnicodeString("Fail ") + pi + " x \"" + PATS[i] + "\" -> \"" +
+ out + "\" -> " + val + " -> \"" +
+ out2 + "\" -> " + val2);
+ }
+ }
+ /*}
+ catch (ParseException e) {
+ errln("Fail: " + e);
+ e.printStackTrace();
+ }*/
+
+ delete nff;
+}
+
+/**
+ * @bug 4147295
+ * DecimalFormat.applyPattern() sets minimum integer digits incorrectly.
+ * CANNOT REPRODUCE
+ * This bug is a duplicate of 4139344, which is a duplicate of 4134300
+ */
+void NumberFormatRegressionTest::Test4147295(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *sdf = new DecimalFormat(status);
+ UnicodeString pattern("#,###");
+ logln("Applying pattern \"" + pattern + "\"");
+ sdf->applyPattern(pattern, status);
+ failure(status, "sdf->applyPattern");
+ int minIntDig = sdf->getMinimumIntegerDigits();
+ if (minIntDig != 0) {
+ errln("Test failed");
+ errln(" Minimum integer digits : " + minIntDig);
+ UnicodeString temp;
+ errln(" new pattern: " + sdf->toPattern(temp));
+ } else {
+ logln("Test passed");
+ logln(" Minimum integer digits : " + minIntDig);
+ }
+ delete sdf;
+}
+
+/**
+ * @bug 4147706
+ * DecimalFormat formats -0.0 as +0.0
+ * See also older related bug 4106658, 4106667
+ */
+void NumberFormatRegressionTest::Test4147706(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat("#,##0.0##", status);
+ failure(status, "new DecimalFormat");
+ DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale::getEnglish(), status);
+ failure(status, "new DecimalFormatSymbols");
+ UnicodeString f1;
+ UnicodeString f2, temp;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ volatile double d1 = 0.0; // volatile to prevent code optimization
+ double d2 = -0.0001;
+
+#if defined(U_HPUX)
+ d1 = 0.0 * -1.0; // old HPUX compiler ignores volatile keyword
+#else
+ d1 *= -1.0; // Some compilers have a problem with defining -0.0
+#endif
+ df->adoptDecimalFormatSymbols(syms);
+ f1 = df->format(d1, f1, pos);
+ f2 = df->format(d2, f2, pos);
+ if (f1 != UnicodeString("-0.0")) {
+ errln(UnicodeString("") + d1 + UnicodeString(" x \"") + df->toPattern(temp) + "\" is formatted as \"" + f1 + '"');
+ }
+ if (f2 != UnicodeString("-0.0")) {
+ errln(UnicodeString("") + d2 + UnicodeString(" x \"") + df->toPattern(temp) + "\" is formatted as \"" + f2 + '"');
+ }
+
+ delete df;
+}
+
+
+// Not applicable, since no serialization in C++
+/*class myformat implements Serializable
+{
+DateFormat _dateFormat = DateFormat.getDateInstance();
+
+public String Now()
+{
+ GregorianCalendar calendar = new GregorianCalendar();
+ Date t = calendar.getTime();
+ String nowStr = _dateFormat.format(t);
+ return nowStr;
+}
+}*/
+
+/**
+ * @bug 4162198
+ * NumberFormat cannot format Double.MAX_VALUE
+ */
+// TODO: make this test actually test something
+void
+NumberFormatRegressionTest::Test4162198(void)
+{
+ // for some reason, DBL_MAX will not round trip. (bug in sprintf/atof)
+ double dbl = INT32_MAX * 1000.0;
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *f = NumberFormat::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create number format");
+ return;
+ }
+ f->setMaximumFractionDigits(INT32_MAX);
+ f->setMaximumIntegerDigits(INT32_MAX);
+ UnicodeString s;
+ f->format(dbl,s);
+ logln(UnicodeString("The number ") + dbl + " formatted to " + s);
+ Formattable n;
+ //try {
+ f->parse(s, n, status);
+ if(U_FAILURE(status))
+ errln("Couldn't parse!");
+ //} catch (java.text.ParseException e) {
+ // errln("Caught a ParseException:");
+ // e.printStackTrace();
+ //}
+
+ //logln("The string " + s + " parsed as " + n);
+
+ // {dlf} The old code assumes n is a double, but it isn't any more...
+ // Formattable apparently does not and never did interconvert... too bad.
+ //if(n.getDouble() != dbl) {
+ // errln("Round trip failure");
+ //}
+ if (n.getInt64() != dbl) {
+ errln("Round trip failure");
+ }
+
+ delete f;
+}
+
+/**
+ * @bug 4162852
+ * NumberFormat does not parse negative zero.
+ */
+void
+NumberFormatRegressionTest::Test4162852(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ for(int32_t i=0; i < 2; ++i) {
+ NumberFormat *f = (i == 0) ? NumberFormat::createInstance(status)
+ : NumberFormat::createPercentInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't create number format");
+ return;
+ }
+ double d = 0.0;
+ d *= -1.0;
+ UnicodeString s;
+ f->format(d, s);
+ Formattable n;
+ f->parse(s, n, status);
+ if(U_FAILURE(status))
+ errln("Couldn't parse!");
+ double e = n.getDouble();
+ logln(UnicodeString("") +
+ d + " -> " +
+ '"' + s + '"' + " -> " + e);
+#if (defined(OS390) && !defined(IEEE_754)) || defined(OS400)
+ if (e != 0.0) {
+#else
+ if (e != 0.0 || 1.0/e > 0.0) {
+#endif
+ logln("Failed to parse negative zero");
+ }
+ delete f;
+ }
+}
+
+static double _u_abs(double a) { return a<0?-a:a; }
+
+/**
+ * May 17 1999 sync up - liu
+ * @bug 4167494
+ * NumberFormat truncates data
+ */
+void NumberFormatRegressionTest::Test4167494(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *fmt = NumberFormat::createInstance(Locale::getUS(), status);
+ if (failure(status, "NumberFormat::createInstance")){
+ delete fmt;
+ return;
+ };
+
+ double a = DBL_MAX * 0.99; // DBL_MAX itself overflows to +Inf
+ UnicodeString s;
+ fmt->format(a, s);
+ Formattable num;
+ fmt->parse(s, num, status);
+ failure(status, "Parse");
+ if (num.getType() == Formattable::kDouble &&
+ _u_abs(num.getDouble() - a) / a < 0.01) { // RT within 1%
+ logln(UnicodeString("") + a + " -> \"" + s + "\" -> " +
+ toString(num) + " ok");
+ } else {
+ errln(UnicodeString("") + a + " -> \"" + s + "\" -> " +
+ toString(num) + " FAIL");
+ }
+
+ // We don't test Double.MIN_VALUE because the locale data for the US
+ // currently doesn't specify enough digits to display Double.MIN_VALUE.
+ // This is correct for now; however, we leave this here as a reminder
+ // in case we want to address this later.
+
+ delete fmt;
+}
+
+/**
+ * May 17 1999 sync up - liu
+ * @bug 4170798
+ * DecimalFormat.parse() fails when ParseIntegerOnly set to true
+ */
+void NumberFormatRegressionTest::Test4170798(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nf = NumberFormat::createInstance(Locale::getUS(), status);
+ if (failure(status, "NumberFormat::createInstance")){
+ delete nf;
+ return;
+ };
+ if(nf->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ errln("DecimalFormat needed to continue");
+ return;
+ }
+ DecimalFormat *df = (DecimalFormat*) nf;
+ df->setParseIntegerOnly(TRUE);
+ Formattable n;
+ ParsePosition pos(0);
+ df->parse("-0.0", n, pos);
+ if (n.getType() != Formattable::kLong
+ || n.getLong() != 0) {
+ errln(UnicodeString("FAIL: parse(\"-0.0\") returns ") + toString(n));
+ }
+ delete nf;
+}
+
+/**
+ * May 17 1999 sync up - liu
+ * toPattern only puts the first grouping separator in.
+ */
+void NumberFormatRegressionTest::Test4176114(void) {
+ const char* DATA[] = {
+ "00", "#00",
+ "000", "#000", // No grouping
+ "#000", "#000", // No grouping
+ "#,##0", "#,##0",
+ "#,000", "#,000",
+ "0,000", "#0,000",
+ "00,000", "#00,000",
+ "000,000", "#,000,000",
+ "0,000,000,000,000.0000", "#0,000,000,000,000.0000", // Reported
+ };
+ int DATA_length = (int)(sizeof(DATA) / sizeof(DATA[0]));
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString s;
+ for (int i=0; i<DATA_length; i+=2) {
+ DecimalFormat df(DATA[i], status);
+ failure(status, "DecimalFormat constructor");
+ df.toPattern(s);
+ UnicodeString exp(DATA[i+1]);
+ if (s != exp) {
+ errln(UnicodeString("FAIL: ") + DATA[i] + " -> " +
+ s + ", want " + exp);
+ }
+ }
+}
+
+/**
+ * May 17 1999 sync up - liu
+ * @bug 4179818
+ * DecimalFormat is incorrectly rounding numbers like 1.2501 to 1.2
+ */
+void NumberFormatRegressionTest::Test4179818(void) {
+ const char* DATA[] = {
+ // Input Pattern Expected output
+ "1.2511", "#.#", "1.3",
+ "1.2501", "#.#", "1.3",
+ "0.9999", "#", "1",
+ };
+ int DATA_length = (int)(sizeof(DATA) / sizeof(DATA[0]));
+ double DOUBLE[] = {
+ 1.2511,
+ 1.2501,
+ 0.9999,
+ };
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols sym(Locale::getUS(), status);
+ failure(status, "Construct DecimalFormatSymbols");
+ DecimalFormat fmt("#", sym, status);
+ failure(status, "Construct DecimalFormat");
+ for (int i=0; i<DATA_length; i+=3) {
+ double in = DOUBLE[i/3];
+ UnicodeString pat(DATA[i+1]);
+ UnicodeString exp(DATA[i+2]);
+ fmt.applyPattern(pat, status);
+ failure(status, "applyPattern");
+ UnicodeString out;
+ FieldPosition pos;
+ fmt.format(in, out, pos);
+ if (out == exp) {
+ logln(UnicodeString("Ok: ") + in + " x " + pat + " = " + out);
+ } else {
+ errln(UnicodeString("FAIL: ") + in + " x " + pat + " = " + out +
+ ", expected " + exp);
+ }
+ }
+}
+
+/**
+ * May 17 1999 sync up - liu
+ * Some DecimalFormatSymbols changes are not picked up by DecimalFormat.
+ * This includes the minus sign, currency symbol, international currency
+ * symbol, percent, and permille. This is filed as bugs 4212072 and
+ * 4212073.
+ */
+void NumberFormatRegressionTest::Test4212072(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols sym(Locale::getUS(), status);
+
+ failure(status, "DecimalFormatSymbols ct", Locale::getUS());
+ DecimalFormat fmt(UnicodeString("#"), sym, status);
+ failure(status, "DecimalFormat ct", Locale::getUS());
+
+ UnicodeString s;
+ FieldPosition pos;
+
+ sym.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, (UChar)0x5e);
+ fmt.setDecimalFormatSymbols(sym);
+ s.remove();
+ if (fmt.format((int32_t)-1, s, pos) != UNICODE_STRING("^1", 2)) {
+ errln(UnicodeString("FAIL: -1 x (minus=^) -> ") + s +
+ ", exp ^1");
+ }
+ s.remove();
+ if (fmt.getNegativePrefix(s) != UnicodeString((UChar)0x5e)) {
+ errln(UnicodeString("FAIL: (minus=^).getNegativePrefix -> ") +
+ s + ", exp ^");
+ }
+ sym.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, (UChar)0x2d);
+
+ fmt.applyPattern(UnicodeString("#%"), status);
+ failure(status, "applyPattern percent");
+ sym.setSymbol(DecimalFormatSymbols::kPercentSymbol, (UChar)0x5e);
+ fmt.setDecimalFormatSymbols(sym);
+ s.remove();
+ if (fmt.format(0.25, s, pos) != UNICODE_STRING("25^", 3)) {
+ errln(UnicodeString("FAIL: 0.25 x (percent=^) -> ") + s +
+ ", exp 25^");
+ }
+ s.remove();
+ if (fmt.getPositiveSuffix(s) != UnicodeString((UChar)0x5e)) {
+ errln(UnicodeString("FAIL: (percent=^).getPositiveSuffix -> ") +
+ s + ", exp ^");
+ }
+ sym.setSymbol(DecimalFormatSymbols::kPercentSymbol, (UChar)0x25);
+
+ fmt.applyPattern(str("#\\u2030"), status);
+ failure(status, "applyPattern permill");
+ sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, (UChar)0x5e);
+ fmt.setDecimalFormatSymbols(sym);
+ s.remove();
+ if (fmt.format(0.25, s, pos) != UNICODE_STRING("250^", 4)) {
+ errln(UnicodeString("FAIL: 0.25 x (permill=^) -> ") + s +
+ ", exp 250^");
+ }
+ s.remove();
+ if (fmt.getPositiveSuffix(s) != UnicodeString((UChar)0x5e)) {
+ errln(UnicodeString("FAIL: (permill=^).getPositiveSuffix -> ") +
+ s + ", exp ^");
+ }
+ sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, (UChar)0x2030);
+
+ fmt.applyPattern(str("\\u00A4#.00"), status);
+ failure(status, "applyPattern currency");
+ sym.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "usd");
+ fmt.setDecimalFormatSymbols(sym);
+ s.remove();
+ if (fmt.format(12.5, s, pos) != UnicodeString("usd12.50")) {
+ errln(UnicodeString("FAIL: 12.5 x (currency=usd) -> ") + s +
+ ", exp usd12.50");
+ }
+ s.remove();
+ if (fmt.getPositivePrefix(s) != UnicodeString("usd")) {
+ errln(UnicodeString("FAIL: (currency=usd).getPositivePrefix -> ") +
+ s + ", exp usd");
+ }
+ sym.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "$");
+
+ fmt.applyPattern(str("\\u00A4\\u00A4#.00"), status);
+ failure(status, "applyPattern intl currency");
+ sym.setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, "DOL");
+ fmt.setDecimalFormatSymbols(sym);
+ s.remove();
+ if (fmt.format(12.5, s, pos) != UnicodeString("DOL12.50")) {
+ errln(UnicodeString("FAIL: 12.5 x (intlcurrency=DOL) -> ") + s +
+ ", exp DOL12.50");
+ }
+ s.remove();
+ if (fmt.getPositivePrefix(s) != UnicodeString("DOL")) {
+ errln(UnicodeString("FAIL: (intlcurrency=DOL).getPositivePrefix -> ") +
+ s + ", exp DOL");
+ }
+ sym.setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, "USD");
+
+ // Since the pattern logic has changed, make sure that patterns round
+ // trip properly. Test stream in/out integrity too.
+ int32_t n;
+ const Locale* avail = NumberFormat::getAvailableLocales(n);
+ static const char* type[] = {
+ "",
+ "$ ",
+ "% ",
+ };
+ for (int i=0; i<n; ++i) {
+ for (int j=0; j<3; ++j) {
+ status = U_ZERO_ERROR;
+ NumberFormat *nf;
+ switch (j) {
+ case 0:
+ nf = NumberFormat::createInstance(avail[i], status);
+ failure(status, "createInstance", avail[i]);
+ break;
+ case 1:
+ nf = NumberFormat::createCurrencyInstance(avail[i], status);
+ failure(status, "createCurrencyInstance", avail[i]);
+ break;
+ default:
+ nf = NumberFormat::createPercentInstance(avail[i], status);
+ failure(status, "createPercentInstance", avail[i]);
+ break;
+ }
+ if (U_FAILURE(status)) {
+ continue;
+ }
+ DecimalFormat *df = (DecimalFormat*) nf;
+
+ // Test toPattern/applyPattern round trip
+ UnicodeString pat;
+ df->toPattern(pat);
+ DecimalFormatSymbols symb(avail[i], status);
+ failure(status, "Construct DecimalFormatSymbols", avail[i]);
+ DecimalFormat f2(pat, symb, status);
+ if (failure(status,
+ UnicodeString("Construct DecimalFormat(") + pat + ")")) {
+ continue;
+ }
+ if (*df != f2) {
+ UnicodeString l, p;
+ errln(UnicodeString("FAIL: ") + type[j] + avail[i].getDisplayName(l) +
+ " -> \"" + pat +
+ "\" -> \"" + f2.toPattern(p) + "\"");
+ }
+
+ // Test toLocalizedPattern/applyLocalizedPattern round trip
+ df->toLocalizedPattern(pat);
+ f2.applyLocalizedPattern(pat, status);
+ failure(status,
+ UnicodeString("applyLocalizedPattern(") + pat + ")", avail[i]);
+ if (U_FAILURE(status)) {
+ continue;
+ }
+
+ // Make sure we set the currency attributes appropriately
+ if (j == 1) { // Currency format
+ f2.setCurrency(f2.getCurrency(), status);
+ }
+ failure(status,
+ UnicodeString("setCurrency() for (") + pat + ")", avail[i]);
+ if (U_FAILURE(status)) {
+ continue;
+ }
+
+ if (*df != f2) {
+ UnicodeString l, p;
+ errln(UnicodeString("FAIL: ") + type[j] + avail[i].getDisplayName(l) +
+ " -> localized \"" + pat +
+ "\" -> \"" + f2.toPattern(p) + "\"");
+ }
+
+ delete nf;
+
+ // Test writeObject/readObject round trip
+ // NOT ON ICU -- Java only
+ }
+ }
+}
+
+/**
+ * May 17 1999 sync up - liu
+ * DecimalFormat.parse() fails for mulipliers 2^n.
+ */
+void NumberFormatRegressionTest::Test4216742(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *fmt = (DecimalFormat*) NumberFormat::createInstance(Locale::getUS(), status);
+ if (failure(status, "createInstance", Locale::getUS())){
+ delete fmt;
+ return;
+ };
+ int32_t DATA[] = { INT32_MIN, INT32_MAX, -100000000, 100000000 };
+ int DATA_length = (int)(sizeof(DATA) / sizeof(DATA[0]));
+ for (int i=0; i<DATA_length; ++i) {
+ UnicodeString str((UnicodeString)"" + DATA[i]);
+ for (int m = 1; m <= 100; m++) {
+ fmt->setMultiplier(m);
+ Formattable num;
+ fmt->parse(str, num, status);
+ failure(status, "parse", Locale::getUS());
+ if (num.getType() != Formattable::kLong &&
+ num.getType() != Formattable::kDouble) {
+ errln(UnicodeString("FAIL: Wanted number, got ") +
+ toString(num));
+ } else {
+ double d = num.getType() == Formattable::kDouble ?
+ num.getDouble() : (double) num.getLong();
+ if (d > 0 != DATA[i] > 0) {
+ errln(UnicodeString("\"") + str + "\" parse(x " +
+ fmt->getMultiplier() +
+ ") => " + toString(num));
+ }
+ }
+ }
+ }
+ delete fmt;
+}
+
+/**
+ * May 17 1999 sync up - liu
+ * DecimalFormat formats 1.001 to "1.00" instead of "1" with 2 fraction
+ * digits.
+ */
+void NumberFormatRegressionTest::Test4217661(void) {
+ const double D[] = { 0.001, 1.001, 0.006, 1.006 };
+ const char* S[] = { "0", "1", "0.01", "1.01" };
+ int D_length = (int)(sizeof(D) / sizeof(D[0]));
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *fmt = NumberFormat::createInstance(Locale::getUS(), status);
+ if (failure(status, "createInstance", Locale::getUS())){
+ delete fmt;
+ return;
+ };
+ fmt->setMaximumFractionDigits(2);
+ for (int i=0; i<D_length; i++) {
+ UnicodeString s;
+ fmt->format(D[i], s);
+ if (s != UnicodeString(S[i])) {
+ errln(UnicodeString("FAIL: Got ") + s + ", exp " + S[i]);
+ }
+ }
+ delete fmt;
+}
+
+/**
+ * alphaWorks upgrade
+ */
+void NumberFormatRegressionTest::Test4161100(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nf = NumberFormat::createInstance(Locale::getUS(), status);
+ if (failure(status, "createInstance", Locale::getUS())){
+ delete nf;
+ return;
+ };
+ nf->setMinimumFractionDigits(1);
+ nf->setMaximumFractionDigits(1);
+ double a = -0.09;
+ UnicodeString s;
+ nf->format(a, s);
+ UnicodeString pat;
+ logln(UnicodeString() + a + " x " +
+ ((DecimalFormat*) nf)->toPattern(pat) + " = " + s);
+ if (s != UnicodeString("-0.1")) {
+ errln("FAIL");
+ }
+ delete nf;
+}
+
+/**
+ * June 16 1999 sync up - liu
+ * Formatting .5 rounds to "1" instead of "0". (Regression in 1.2.2 RC1)
+ */
+void NumberFormatRegressionTest::Test4243011(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols sym(Locale::getUS(), status);
+ failure(status, "DecimalFormatSymbols ct", Locale::getUS());
+ DecimalFormat fmt(UnicodeString("0."), sym, status);
+ failure(status, "DecimalFormat ct", Locale::getUS());
+
+ const double NUM[] = { -2.5, -1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5 };
+ const char* STR[] = { "-2.", "-2.", "-0.", "0.", "2.", "2.", "4.", "4." };
+ int32_t N = (int32_t)(sizeof(NUM) / sizeof(NUM[0]));
+
+ for (int32_t i=0; i<N; ++i) {
+ UnicodeString str;
+ UnicodeString exp(STR[i]);
+ FieldPosition pos;
+ fmt.format(NUM[i], str, pos);
+ if (str == exp) {
+ logln(UnicodeString("Ok ") + NUM[i] + " x 0. = " + str);
+ } else {
+ errln(UnicodeString("FAIL ") + NUM[i] + " x 0. = " + str +
+ ", want " + exp);
+ }
+ }
+}
+
+/**
+ * June 16 1999 sync up - liu
+ * format(0.0) gives "0.1" if preceded by parse("99.99").
+ * (Regression in 1.2.2 RC1)
+ */
+void NumberFormatRegressionTest::Test4243108(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols sym(Locale::getUS(), status);
+ failure(status, "DecimalFormatSymbols ct", Locale::getUS());
+ DecimalFormat fmt(UnicodeString("#.#"), sym, status);
+ failure(status, "DecimalFormat ct", Locale::getUS());
+
+ UnicodeString str;
+ FieldPosition pos;
+
+ fmt.format(0.0, str, pos);
+ UnicodeString exp("0");
+ if (str == exp) {
+ logln(UnicodeString("Ok 0.0 x #.# = ") + str);
+ } else {
+ errln(UnicodeString("FAIL 0.0 x #.# = ") + str +
+ ", want " + exp);
+ }
+
+ str = "99.99";
+ Formattable val;
+ fmt.parse(str, val, status);
+ failure(status, "DecimalFormat.parse(99.99)", Locale::getUS());
+ if (val.getType() == Formattable::kDouble &&
+ val.getDouble() == 99.99) {
+ logln(UnicodeString("Ok 99.99 / #.# = ") + toString(val));
+ } else {
+ errln(UnicodeString("FAIL 99.99 / #.# = ") + toString(val) +
+ ", want " + 99.99);
+ }
+
+ str.remove();
+ fmt.format(0.0, str, pos);
+ if (str == exp) {
+ logln(UnicodeString("Ok 0.0 x #.# = ") + str);
+ } else {
+ errln(UnicodeString("FAIL 0.0 x #.# = ") + str +
+ ", want " + exp);
+ }
+}
+
+
+/**
+ * DateFormat should call setIntegerParseOnly(TRUE) on adopted
+ * NumberFormat objects.
+ */
+void NumberFormatRegressionTest::TestJ691(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ Locale loc("fr", "CH");
+
+ // set up the input date string & expected output
+ UnicodeString udt("11.10.2000", "");
+ UnicodeString exp("11.10.00", "");
+
+ // create a Calendar for this locale
+ Calendar *cal = Calendar::createInstance(loc, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Calendar::createInstance() returned " + (UnicodeString)u_errorName(status));
+ return;
+ }
+
+ // create a NumberFormat for this locale
+ NumberFormat *nf = NumberFormat::createInstance(loc, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: NumberFormat::createInstance() returned " + (UnicodeString)u_errorName(status));
+ return;
+ }
+
+ // *** Here's the key: We don't want to have to do THIS:
+ // nf->setParseIntegerOnly(TRUE);
+
+ // create the DateFormat
+ DateFormat *df = DateFormat::createDateInstance(DateFormat::kShort, loc);
+ if (U_FAILURE(status)) {
+ errln("FAIL: DateFormat::createInstance() returned " + (UnicodeString)u_errorName(status));
+ return;
+ }
+
+ df->adoptCalendar(cal);
+ df->adoptNumberFormat(nf);
+
+ // set parsing to lenient & parse
+ df->setLenient(TRUE);
+ UDate ulocdat = df->parse(udt, status);
+
+ // format back to a string
+ UnicodeString outString;
+ df->format(ulocdat, outString);
+
+ if (outString != exp) {
+ errln("FAIL: " + udt + " => " + outString);
+ }
+
+ delete df;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/numrgts.h b/Build/source/libs/icu/icu-xetex/test/intltest/numrgts.h
new file mode 100644
index 00000000000..e20141cd2a4
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/numrgts.h
@@ -0,0 +1,103 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2004, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#ifndef _NUMBERFORMATREGRESSIONTEST_
+#define _NUMBERFORMATREGRESSIONTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/numfmt.h"
+#include "unicode/decimfmt.h"
+#include "intltest.h"
+
+/**
+ * Performs regression test for MessageFormat
+ **/
+class NumberFormatRegressionTest: public IntlTest {
+
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+
+ void Test4075713(void);
+ void Test4074620(void) ;
+ void Test4088161 (void);
+ void Test4087245 (void);
+ void Test4087535 (void);
+ void Test4088503 (void);
+ void Test4066646 (void);
+ float assignFloatValue(float returnfloat);
+ void Test4059870(void);
+ void Test4083018 (void);
+ void Test4071492 (void);
+ void Test4086575(void);
+ void Test4068693(void);
+ void Test4069754(void);
+ void Test4087251 (void);
+ void Test4090489 (void);
+ void Test4090504 (void);
+ void Test4095713 (void);
+ void Test4092561 (void);
+ void Test4092480 (void);
+ void Test4087244 (void);
+ void Test4070798 (void);
+ void Test4071005 (void);
+ void Test4071014 (void);
+ void Test4071859 (void);
+ void Test4093610(void);
+ void roundingTest(DecimalFormat *df, double x, UnicodeString& expected);
+ void Test4098741(void);
+ void Test4074454(void);
+ void Test4099404(void);
+ void Test4101481(void);
+ void Test4052223(void);
+ void Test4061302(void);
+ void Test4062486(void);
+ void Test4108738(void);
+ void Test4106658(void);
+ void Test4106662(void);
+ void Test4114639(void);
+ void Test4106664(void);
+ void Test4106667(void);
+ void Test4110936(void);
+ void Test4122840(void);
+ void Test4125885(void);
+ void Test4134034(void);
+ void Test4134300(void);
+ void Test4140009(void);
+ void Test4141750(void);
+ void Test4145457(void);
+ void Test4147295(void);
+ void Test4147706(void);
+
+ void Test4162198(void);
+ void Test4162852(void);
+
+ void Test4167494(void);
+ void Test4170798(void);
+ void Test4176114(void);
+ void Test4179818(void);
+ void Test4212072(void);
+ void Test4216742(void);
+ void Test4217661(void);
+ void Test4161100(void);
+ void Test4243011(void);
+ void Test4243108(void);
+ void TestJ691(void);
+
+protected:
+ UBool failure(UErrorCode status, const UnicodeString& msg);
+ UBool failure(UErrorCode status, const UnicodeString& msg, const char *l);
+ UBool failure(UErrorCode status, const UnicodeString& msg, const Locale& l);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _NUMBERFORMATREGRESSIONTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/pptest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/pptest.cpp
new file mode 100644
index 00000000000..2159183b17a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/pptest.cpp
@@ -0,0 +1,227 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "pptest.h"
+
+#include "unicode/numfmt.h"
+#include "unicode/decimfmt.h"
+
+// *****************************************************************************
+// class ParsePositionTest
+// *****************************************************************************
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
+
+void ParsePositionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite ParsePositionTest");
+ switch (index) {
+ CASE(0, TestParsePosition)
+ CASE(1, TestFieldPosition)
+ CASE(2, TestFieldPosition_example)
+ CASE(3, Test4109023)
+
+ default: name = ""; break;
+ }
+}
+
+UBool
+ParsePositionTest::failure(UErrorCode status, const char* msg)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void ParsePositionTest::TestParsePosition()
+{
+ ParsePosition pp1(0);
+ if (pp1.getIndex() == 0) {
+ logln("PP constructor() tested.");
+ }else{
+ errln("*** PP getIndex or constructor() result");
+ }
+
+ {
+ int to = 5;
+ ParsePosition pp2( to );
+ if (pp2.getIndex() == 5) {
+ logln("PP getIndex and constructor(int32_t) tested.");
+ }else{
+ errln("*** PP getIndex or constructor(int32_t) result");
+ }
+ pp2.setIndex( 3 );
+ if (pp2.getIndex() == 3) {
+ logln("PP setIndex tested.");
+ }else{
+ errln("*** PP getIndex or setIndex result");
+ }
+ }
+
+ ParsePosition pp2(3), pp3(5);
+ //pp2 = new ParsePosition( 3 );
+ //pp3 = new ParsePosition( 5 );
+ ParsePosition pp4(5);
+ if ( pp2 != pp3) {
+ logln("PP not equals tested.");
+ }else{
+ errln("*** PP not equals fails");
+ }
+ if (pp3 == pp4) {
+ logln("PP equals tested.");
+ }else{
+ errln(UnicodeString("*** PP equals fails (") + pp3.getIndex() + " != " + pp4.getIndex() + ")");
+ }
+
+ ParsePosition pp5;
+ pp5 = pp4;
+ if (pp4 == pp5) {
+ logln("PP operator= tested.");
+ }else{
+ errln("*** PP operator= operator== or operator != result");
+ }
+
+ ParsePosition *ppp = pp5.clone();
+ if(ppp == &pp5 || *ppp != pp5) {
+ errln("ParsePosition.clone() failed");
+ }
+ delete ppp;
+}
+
+void ParsePositionTest::TestFieldPosition()
+{
+ FieldPosition fp( 7 );
+
+ if (fp.getField() == 7) {
+ logln("FP constructor(int) and getField tested.");
+ }else{
+ errln("*** FP constructor(int) or getField");
+ }
+
+ FieldPosition fpc(fp);
+ if (fpc.getField() == 7) {
+ logln("FP Constructor(FP&) passed");
+ } else {
+ errln("*** FP Constructor(FP&)");
+ }
+
+ FieldPosition fph( 3 );
+ if ( fph.getField() != 3)
+ errln("*** FP getField or heap constr.");
+
+ UBool err1 = FALSE;
+ UBool err2 = FALSE;
+ UBool err3 = FALSE;
+// for (long i = -50; i < 50; i++ ) {
+// fp.setField( i+8 );
+// fp.setBeginIndex( i+6 );
+// fp.setEndIndex( i+7 );
+// if (fp.getField() != i+8) err1 = TRUE;
+// if (fp.getBeginIndex() != i+6) err2 = TRUE;
+// if (fp.getEndIndex() != i+7) err3 = TRUE;
+// }
+ if (!err1) {
+ logln("FP setField and getField tested.");
+ }else{
+ errln("*** FP setField or getField");
+ }
+ if (!err2) {
+ logln("FP setBeginIndex and getBeginIndex tested.");
+ }else{
+ errln("*** FP setBeginIndex or getBeginIndex");
+ }
+ if (!err3) {
+ logln("FP setEndIndex and getEndIndex tested.");
+ }else{
+ errln("*** FP setEndIndex or getEndIndex");
+ }
+
+ logln("");
+
+ FieldPosition *pfp = fp.clone();
+ if(pfp == &fp || *pfp != fp) {
+ errln("FieldPosition.clone() failed");
+ }
+ delete pfp;
+}
+
+void ParsePositionTest::TestFieldPosition_example()
+{
+ //***** no error detection yet !!!!!!!
+ //***** this test is for compiler checks and visual verification only.
+ double doubleNum[] = {
+ 123456789.0,
+ -12345678.9,
+ 1234567.89,
+ -123456.789,
+ 12345.6789,
+ -1234.56789,
+ 123.456789,
+ -12.3456789,
+ 1.23456789};
+ int dNumSize = 9;
+
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *nf = NumberFormat::createInstance(status);
+ if (failure(status, "NumberFormat::createInstance")){
+ delete nf;
+ return;
+ };
+
+ if(nf->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
+ errln("NumberFormat::createInstance returned unexpected class type");
+ return;
+ }
+ DecimalFormat *fmt = (DecimalFormat*) nf;
+ fmt->setDecimalSeparatorAlwaysShown(TRUE);
+
+ const int tempLen = 20;
+ UnicodeString temp;
+
+ for (int i=0; i < dNumSize; i++) {
+ temp.remove();
+ //temp = new StringBuffer(); // Get new buffer
+
+ FieldPosition pos(NumberFormat::INTEGER_FIELD);
+ UnicodeString buf;// = new StringBuffer();
+ //char fmtText[tempLen];
+ //ToCharString(fmt->format(doubleNum[i], buf, pos), fmtText);
+ UnicodeString res;
+ res = fmt->format(doubleNum[i], buf, pos);
+ int tempOffset = (tempLen <= (tempLen - pos.getEndIndex())) ?
+ tempLen : (tempLen - pos.getEndIndex());
+ for (int j=0; j<tempOffset; j++)
+ temp += UnicodeString("="/*'='*/); // initialize
+ logln("FP " + temp + res);
+ }
+
+ logln("");
+ delete nf;
+}
+
+/* @bug 4109023
+ * Need to override ParsePosition.equals and FieldPosition.equals.
+ */
+void ParsePositionTest::Test4109023()
+{
+ ParsePosition p(3);
+ ParsePosition p2(3);
+ if (p != p2)
+ errln("Error : ParsePosition.equals() failed");
+ FieldPosition fp(2);
+ FieldPosition fp2(2);
+ if (fp != fp2)
+ errln("Error : FieldPosition.equals() failed");
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/pptest.h b/Build/source/libs/icu/icu-xetex/test/intltest/pptest.h
new file mode 100644
index 00000000000..5bad9b1dc63
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/pptest.h
@@ -0,0 +1,37 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _PARSEPOSITIONIONTEST_
+#define _PARSEPOSITIONIONTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+
+/**
+ * Performs test for ParsePosition
+ **/
+class ParsePositionTest: public IntlTest {
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+
+ void TestParsePosition(void);
+ void TestFieldPosition(void);
+ void TestFieldPosition_example(void);
+ void Test4109023(void);
+
+protected:
+ UBool failure(UErrorCode status, const char* msg);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _PARSEPOSITIONIONTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/punyref.c b/Build/source/libs/icu/icu-xetex/test/intltest/punyref.c
new file mode 100644
index 00000000000..c61a8b61371
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/punyref.c
@@ -0,0 +1,302 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2003-2005, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: punyref.h
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2003feb1
+ * created by: Ram Viswanadha
+ */
+
+/*
+Disclaimer and license
+
+ Regarding this entire document or any portion of it (including
+ the pseudocode and C code), the author makes no guarantees and
+ is not responsible for any damage resulting from its use. The
+ author grants irrevocable permission to anyone to use, modify,
+ and distribute it in any way that does not diminish the rights
+ of anyone else to use, modify, and distribute it, provided that
+ redistributed derivative works do not contain misleading author or
+ version information. Derivative works need not be licensed under
+ similar terms.
+
+punycode.c 0.4.0 (2001-Nov-17-Sat)
+http://www.cs.berkeley.edu/~amc/idn/
+Adam M. Costello
+http://www.nicemice.net/amc/
+*/
+
+/**********************************************************/
+/* Implementation (would normally go in its own .c file): */
+
+#include <string.h>
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+#include "punyref.h"
+
+/*** Bootstring parameters for Punycode ***/
+
+enum { base = 36, tmin = 1, tmax = 26, skew = 38, damp = 700,
+ initial_bias = 72, initial_n = 0x80, delimiter = 0x2D };
+
+/* basic(cp) tests whether cp is a basic code point: */
+#define basic(cp) ((punycode_uint)(cp) < 0x80)
+
+/* delim(cp) tests whether cp is a delimiter: */
+#define delim(cp) ((cp) == delimiter)
+
+U_CDECL_BEGIN
+/* decode_digit(cp) returns the numeric value of a basic code */
+/* point (for use in representing integers) in the range 0 to */
+/* base-1, or base if cp is does not represent a value. */
+
+static punycode_uint decode_digit(punycode_uint cp)
+{
+ return cp - 48 < 10 ? cp - 22 : cp - 65 < 26 ? cp - 65 :
+ cp - 97 < 26 ? cp - 97 : base;
+}
+
+/* encode_digit(d,flag) returns the basic code point whose value */
+/* (when used for representing integers) is d, which needs to be in */
+/* the range 0 to base-1. The lowercase form is used unless flag is */
+/* nonzero, in which case the uppercase form is used. The behavior */
+/* is undefined if flag is nonzero and digit d has no uppercase form. */
+
+static char encode_digit(punycode_uint d, int flag)
+{
+ return (char) d + 22 + 75 * (d < 26) - ((flag != 0) << 5);
+ /* 0..25 map to ASCII a..z or A..Z */
+ /* 26..35 map to ASCII 0..9 */
+}
+
+/* flagged(bcp) tests whether a basic code point is flagged */
+/* (uppercase). The behavior is undefined if bcp is not a */
+/* basic code point. */
+
+#define flagged(bcp) ((punycode_uint)(bcp) - 65 < 26)
+
+/* encode_basic(bcp,flag) forces a basic code point to lowercase */
+/* if flag is zero, uppercase if flag is nonzero, and returns */
+/* the resulting code point. The code point is unchanged if it */
+/* is caseless. The behavior is undefined if bcp is not a basic */
+/* code point. */
+
+static char encode_basic(punycode_uint bcp, int flag)
+{
+ bcp -= (bcp - 97 < 26) << 5;
+ return (char) bcp + ((!flag && (bcp - 65 < 26)) << 5);
+}
+
+/*** Platform-specific constants ***/
+
+/* maxint is the maximum value of a punycode_uint variable: */
+static const punycode_uint maxint = (punycode_uint) (-1);
+/* Because maxint is unsigned, -1 becomes the maximum value. */
+
+/*** Bias adaptation function ***/
+
+static punycode_uint adapt(
+ punycode_uint delta, punycode_uint numpoints, int firsttime )
+{
+ punycode_uint k;
+
+ delta = firsttime ? delta / damp : delta >> 1;
+ /* delta >> 1 is a faster way of doing delta / 2 */
+ delta += delta / numpoints;
+
+ for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base) {
+ delta /= base - tmin;
+ }
+
+ return k + (base - tmin + 1) * delta / (delta + skew);
+}
+
+/*** Main encode function ***/
+
+enum punycode_status punycode_encode(
+ punycode_uint input_length,
+ const punycode_uint input[],
+ const unsigned char case_flags[],
+ punycode_uint *output_length,
+ char output[] )
+{
+ punycode_uint n, delta, h, b, out, max_out, bias, j, m, q, k, t;
+
+ /* Initialize the state: */
+
+ n = initial_n;
+ delta = out = 0;
+ max_out = *output_length;
+ bias = initial_bias;
+
+ /* Handle the basic code points: */
+
+ for (j = 0; j < input_length; ++j) {
+ if (basic(input[j])) {
+ if (max_out - out < 2) return punycode_big_output;
+ output[out++] = (char)
+ (case_flags ? encode_basic(input[j], case_flags[j]) : input[j]);
+ }
+ /* else if (input[j] < n) return punycode_bad_input; */
+ /* (not needed for Punycode with unsigned code points) */
+ }
+
+ h = b = out;
+
+ /* h is the number of code points that have been handled, b is the */
+ /* number of basic code points, and out is the number of characters */
+ /* that have been output. */
+
+ if (b > 0) output[out++] = delimiter;
+
+ /* Main encoding loop: */
+
+ while (h < input_length) {
+ /* All non-basic code points < n have been */
+ /* handled already. Find the next larger one: */
+
+ for (m = maxint, j = 0; j < input_length; ++j) {
+ /* if (basic(input[j])) continue; */
+ /* (not needed for Punycode) */
+ if (input[j] >= n && input[j] < m) m = input[j];
+ }
+
+ /* Increase delta enough to advance the decoder's */
+ /* <n,i> state to <m,0>, but guard against overflow: */
+
+ if (m - n > (maxint - delta) / (h + 1)) return punycode_overflow;
+ delta += (m - n) * (h + 1);
+ n = m;
+
+ for (j = 0; j < input_length; ++j) {
+ /* Punycode does not need to check whether input[j] is basic: */
+ if (input[j] < n /* || basic(input[j]) */ ) {
+ if (++delta == 0) return punycode_overflow;
+ }
+
+ if (input[j] == n) {
+ /* Represent delta as a generalized variable-length integer: */
+
+ for (q = delta, k = base; ; k += base) {
+ if (out >= max_out) return punycode_big_output;
+ t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */
+ k >= bias + tmax ? tmax : k - bias;
+ if (q < t) break;
+ output[out++] = encode_digit(t + (q - t) % (base - t), 0);
+ q = (q - t) / (base - t);
+ }
+
+ output[out++] = encode_digit(q, case_flags && case_flags[j]);
+ bias = adapt(delta, h + 1, h == b);
+ delta = 0;
+ ++h;
+ }
+ }
+
+ ++delta, ++n;
+ }
+
+ *output_length = out;
+ return punycode_success;
+}
+
+/*** Main decode function ***/
+
+enum punycode_status punycode_decode(
+ punycode_uint input_length,
+ const char input[],
+ punycode_uint *output_length,
+ punycode_uint output[],
+ unsigned char case_flags[] )
+{
+ punycode_uint n, out, i, max_out, bias,
+ b, j, in, oldi, w, k, digit, t;
+
+ /* Initialize the state: */
+
+ n = initial_n;
+ out = i = 0;
+ max_out = *output_length;
+ bias = initial_bias;
+
+ /* Handle the basic code points: Let b be the number of input code */
+ /* points before the last delimiter, or 0 if there is none, then */
+ /* copy the first b code points to the output. */
+
+ for (b = j = 0; j < input_length; ++j) if (delim(input[j])) b = j;
+ if (b > max_out) return punycode_big_output;
+
+ for (j = 0; j < b; ++j) {
+ if (case_flags) case_flags[out] = flagged(input[j]);
+ if (!basic(input[j])) return punycode_bad_input;
+ output[out++] = input[j];
+ }
+
+ /* Main decoding loop: Start just after the last delimiter if any */
+ /* basic code points were copied; start at the beginning otherwise. */
+
+ for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) {
+
+ /* in is the index of the next character to be consumed, and */
+ /* out is the number of code points in the output array. */
+
+ /* Decode a generalized variable-length integer into delta, */
+ /* which gets added to i. The overflow checking is easier */
+ /* if we increase i as we go, then subtract off its starting */
+ /* value at the end to obtain delta. */
+
+ for (oldi = i, w = 1, k = base; ; k += base) {
+ if (in >= input_length) return punycode_bad_input;
+ digit = decode_digit(input[in++]);
+ if (digit >= base) return punycode_bad_input;
+ if (digit > (maxint - i) / w) return punycode_overflow;
+ i += digit * w;
+ t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */
+ k >= bias + tmax ? tmax : k - bias;
+ if (digit < t) break;
+ if (w > maxint / (base - t)) return punycode_overflow;
+ w *= (base - t);
+ }
+
+ bias = adapt(i - oldi, out + 1, oldi == 0);
+
+ /* i was supposed to wrap around from out+1 to 0, */
+ /* incrementing n each time, so we'll fix that now: */
+
+ if (i / (out + 1) > maxint - n) return punycode_overflow;
+ n += i / (out + 1);
+ i %= (out + 1);
+
+ /* Insert n at position i of the output: */
+
+ /* not needed for Punycode: */
+ /* if (decode_digit(n) <= base) return punycode_invalid_input; */
+ if (out >= max_out) return punycode_big_output;
+
+ if (case_flags) {
+ memmove(case_flags + i + 1, case_flags + i, out - i);
+ /* Case of last character determines uppercase flag: */
+ case_flags[i] = flagged(input[in - 1]);
+ }
+
+ memmove(output + i + 1, output + i, (out - i) * sizeof *output);
+ output[i++] = n;
+ }
+
+ *output_length = out;
+ return punycode_success;
+}
+
+U_CDECL_END
+
+#endif /* #if !UCONFIG_NO_IDNA */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/punyref.h b/Build/source/libs/icu/icu-xetex/test/intltest/punyref.h
new file mode 100644
index 00000000000..138446bcc06
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/punyref.h
@@ -0,0 +1,116 @@
+/*
+ ******************************************************************************
+ *
+ * Copyright (C) 2003, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ ******************************************************************************
+ */
+/*
+punycode.c from draft-ietf-idn-punycode-03
+http://www.nicemice.net/idn/
+Adam M. Costello
+http://www.nicemice.net/amc/
+
+This is ANSI C code (C89) implementing
+Punycode (draft-ietf-idn-punycode-03).
+
+Disclaimer and license
+
+ Regarding this entire document or any portion of it (including
+ the pseudocode and C code), the author makes no guarantees and
+ is not responsible for any damage resulting from its use. The
+ author grants irrevocable permission to anyone to use, modify,
+ and distribute it in any way that does not diminish the rights
+ of anyone else to use, modify, and distribute it, provided that
+ redistributed derivative works do not contain misleading author or
+ version information. Derivative works need not be licensed under
+ similar terms.
+
+*/
+#ifndef _PUNYREF_H
+#define _PUNYREF_H
+
+/************************************************************/
+/* Public interface (would normally go in its own .h file): */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA
+
+enum punycode_status {
+ punycode_success,
+ punycode_bad_input, /* Input is invalid. */
+ punycode_big_output, /* Output would exceed the space provided. */
+ punycode_overflow /* Input needs wider integers to process. */
+};
+
+
+typedef uint32_t punycode_uint;
+
+U_CDECL_BEGIN
+
+enum punycode_status punycode_encode(
+ punycode_uint input_length,
+ const punycode_uint input[],
+ const unsigned char case_flags[],
+ punycode_uint *output_length,
+ char output[] );
+
+ /* punycode_encode() converts Unicode to Punycode. The input */
+ /* is represented as an array of Unicode code points (not code */
+ /* units; surrogate pairs are not allowed), and the output */
+ /* will be represented as an array of ASCII code points. The */
+ /* output string is *not* null-terminated; it will contain */
+ /* zeros if and only if the input contains zeros. (Of course */
+ /* the caller can leave room for a terminator and add one if */
+ /* needed.) The input_length is the number of code points in */
+ /* the input. The output_length is an in/out argument: the */
+ /* caller passes in the maximum number of code points that it */
+ /* can receive, and on successful return it will contain the */
+ /* number of code points actually output. The case_flags array */
+ /* holds input_length boolean values, where nonzero suggests that */
+ /* the corresponding Unicode character be forced to uppercase */
+ /* after being decoded (if possible), and zero suggests that */
+ /* it be forced to lowercase (if possible). ASCII code points */
+ /* are encoded literally, except that ASCII letters are forced */
+ /* to uppercase or lowercase according to the corresponding */
+ /* uppercase flags. If case_flags is a null pointer then ASCII */
+ /* letters are left as they are, and other code points are */
+ /* treated as if their uppercase flags were zero. The return */
+ /* value can be any of the punycode_status values defined above */
+ /* except punycode_bad_input; if not punycode_success, then */
+ /* output_size and output might contain garbage. */
+
+enum punycode_status punycode_decode(
+ punycode_uint input_length,
+ const char input[],
+ punycode_uint *output_length,
+ punycode_uint output[],
+ unsigned char case_flags[] );
+
+ /* punycode_decode() converts Punycode to Unicode. The input is */
+ /* represented as an array of ASCII code points, and the output */
+ /* will be represented as an array of Unicode code points. The */
+ /* input_length is the number of code points in the input. The */
+ /* output_length is an in/out argument: the caller passes in */
+ /* the maximum number of code points that it can receive, and */
+ /* on successful return it will contain the actual number of */
+ /* code points output. The case_flags array needs room for at */
+ /* least output_length values, or it can be a null pointer if the */
+ /* case information is not needed. A nonzero flag suggests that */
+ /* the corresponding Unicode character be forced to uppercase */
+ /* by the caller (if possible), while zero suggests that it be */
+ /* forced to lowercase (if possible). ASCII code points are */
+ /* output already in the proper case, but their flags will be set */
+ /* appropriately so that applying the flags would be harmless. */
+ /* The return value can be any of the punycode_status values */
+ /* defined above; if not punycode_success, then output_length, */
+ /* output, and case_flags might contain garbage. On success, the */
+ /* decoder will never need to write an output_length greater than */
+ /* input_length, because of how the encoding is defined. */
+U_CDECL_END
+
+#endif /* #if !UCONFIG_NO_IDNA */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/rbbiapts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/rbbiapts.cpp
new file mode 100644
index 00000000000..36305991862
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/rbbiapts.cpp
@@ -0,0 +1,1118 @@
+/********************************************************************
+ * Copyright (c) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************
+ * Date Name Description
+ * 12/14/99 Madhu Creation.
+ * 01/12/2000 Madhu updated for changed API
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/uchar.h"
+#include "intltest.h"
+#include "unicode/rbbi.h"
+#include "unicode/schriter.h"
+#include "rbbiapts.h"
+#include "rbbidata.h"
+#include "cstring.h"
+#include "ubrkimpl.h"
+#include "unicode/ustring.h"
+#include "unicode/utext.h"
+
+/**
+ * API Test the RuleBasedBreakIterator class
+ */
+
+
+#define TEST_ASSERT_SUCCESS(status) {if (U_FAILURE(status)) {\
+errln("Failure at file %s, line %d, error = %s", __FILE__, __LINE__, u_errorName(status));}}
+
+#define TEST_ASSERT(expr) {if ((expr)==FALSE) { \
+errln("Test Failure at file %s, line %d", __FILE__, __LINE__);}}
+
+void RBBIAPITest::TestCloneEquals()
+{
+
+ UErrorCode status=U_ZERO_ERROR;
+ RuleBasedBreakIterator* bi1 = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ RuleBasedBreakIterator* biequal = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ RuleBasedBreakIterator* bi3 = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ RuleBasedBreakIterator* bi2 = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createWordInstance(Locale::getDefault(), status);
+ if(U_FAILURE(status)){
+ errln((UnicodeString)"FAIL : in construction");
+ return;
+ }
+
+
+ UnicodeString testString="Testing word break iterators's clone() and equals()";
+ bi1->setText(testString);
+ bi2->setText(testString);
+ biequal->setText(testString);
+
+ bi3->setText("hello");
+
+ logln((UnicodeString)"Testing equals()");
+
+ logln((UnicodeString)"Testing == and !=");
+ UBool b = (*bi1 != *biequal);
+ b |= *bi1 == *bi2;
+ b |= *bi1 == *bi3;
+ if (b) {
+ errln((UnicodeString)"ERROR:1 RBBI's == and != operator failed.");
+ }
+
+ if(*bi2 == *biequal || *bi2 == *bi1 || *biequal == *bi3)
+ errln((UnicodeString)"ERROR:2 RBBI's == and != operator failed.");
+
+
+ // Quick test of RulesBasedBreakIterator assignment -
+ // Check that
+ // two different iterators are !=
+ // they are == after assignment
+ // source and dest iterator produce the same next() after assignment.
+ // deleting one doesn't disable the other.
+ logln("Testing assignment");
+ RuleBasedBreakIterator *bix = (RuleBasedBreakIterator *)BreakIterator::createLineInstance(Locale::getDefault(), status);
+ if(U_FAILURE(status)){
+ errln((UnicodeString)"FAIL : in construction");
+ return;
+ }
+
+ RuleBasedBreakIterator biDefault, biDefault2;
+ if(U_FAILURE(status)){
+ errln((UnicodeString)"FAIL : in construction of default iterator");
+ return;
+ }
+ if (biDefault == *bix) {
+ errln((UnicodeString)"ERROR: iterators should not compare ==");
+ return;
+ }
+ if (biDefault != biDefault2) {
+ errln((UnicodeString)"ERROR: iterators should compare ==");
+ return;
+ }
+
+
+ UnicodeString HelloString("Hello Kitty");
+ bix->setText(HelloString);
+ if (*bix == *bi2) {
+ errln(UnicodeString("ERROR: strings should not be equal before assignment."));
+ }
+ *bix = *bi2;
+ if (*bix != *bi2) {
+ errln(UnicodeString("ERROR: strings should be equal before assignment."));
+ }
+
+ int bixnext = bix->next();
+ int bi2next = bi2->next();
+ if (! (bixnext == bi2next && bixnext == 7)) {
+ errln(UnicodeString("ERROR: iterators behaved differently after assignment."));
+ }
+ delete bix;
+ if (bi2->next() != 8) {
+ errln(UnicodeString("ERROR: iterator.next() failed after deleting copy."));
+ }
+
+
+
+ logln((UnicodeString)"Testing clone()");
+ RuleBasedBreakIterator* bi1clone=(RuleBasedBreakIterator*)bi1->clone();
+ RuleBasedBreakIterator* bi2clone=(RuleBasedBreakIterator*)bi2->clone();
+
+ if(*bi1clone != *bi1 || *bi1clone != *biequal ||
+ *bi1clone == *bi3 || *bi1clone == *bi2)
+ errln((UnicodeString)"ERROR:1 RBBI's clone() method failed");
+
+ if(*bi2clone == *bi1 || *bi2clone == *biequal ||
+ *bi2clone == *bi3 || *bi2clone != *bi2)
+ errln((UnicodeString)"ERROR:2 RBBI's clone() method failed");
+
+ if(bi1->getText() != bi1clone->getText() ||
+ bi2clone->getText() != bi2->getText() ||
+ *bi2clone == *bi1clone )
+ errln((UnicodeString)"ERROR: RBBI's clone() method failed");
+
+ delete bi1clone;
+ delete bi2clone;
+ delete bi1;
+ delete bi3;
+ delete bi2;
+ delete biequal;
+}
+
+void RBBIAPITest::TestBoilerPlate()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ BreakIterator* a = BreakIterator::createWordInstance(Locale("hi"), status);
+ BreakIterator* b = BreakIterator::createWordInstance(Locale("hi_IN"),status);
+ if (U_FAILURE(status)) {
+ errln("Creation of break iterator failed %s", u_errorName(status));
+ return;
+ }
+ if(*a!=*b){
+ errln("Failed: boilerplate method operator!= does not return correct results");
+ }
+ BreakIterator* c = BreakIterator::createWordInstance(Locale("ja"),status);
+ if(a && c){
+ if(*c==*a){
+ errln("Failed: boilerplate method opertator== does not return correct results");
+ }
+ }else{
+ errln("creation of break iterator failed");
+ }
+ delete a;
+ delete b;
+ delete c;
+}
+
+void RBBIAPITest::TestgetRules()
+{
+ UErrorCode status=U_ZERO_ERROR;
+
+ RuleBasedBreakIterator* bi1=(RuleBasedBreakIterator*)RuleBasedBreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ RuleBasedBreakIterator* bi2=(RuleBasedBreakIterator*)RuleBasedBreakIterator::createWordInstance(Locale::getDefault(), status);
+ if(U_FAILURE(status)){
+ errln((UnicodeString)"FAIL: in construction");
+ delete bi1;
+ delete bi2;
+ return;
+ }
+
+
+
+ logln((UnicodeString)"Testing toString()");
+
+ bi1->setText((UnicodeString)"Hello there");
+
+ RuleBasedBreakIterator* bi3 =(RuleBasedBreakIterator*)bi1->clone();
+
+ UnicodeString temp=bi1->getRules();
+ UnicodeString temp2=bi2->getRules();
+ UnicodeString temp3=bi3->getRules();
+ if( temp2.compare(temp3) ==0 || temp.compare(temp2) == 0 || temp.compare(temp3) != 0)
+ errln((UnicodeString)"ERROR: error in getRules() method");
+
+ delete bi1;
+ delete bi2;
+ delete bi3;
+}
+void RBBIAPITest::TestHashCode()
+{
+ UErrorCode status=U_ZERO_ERROR;
+ RuleBasedBreakIterator* bi1 = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ RuleBasedBreakIterator* bi3 = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ RuleBasedBreakIterator* bi2 = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createWordInstance(Locale::getDefault(), status);
+ if(U_FAILURE(status)){
+ errln((UnicodeString)"FAIL : in construction");
+ delete bi1;
+ delete bi2;
+ delete bi3;
+ return;
+ }
+
+
+ logln((UnicodeString)"Testing hashCode()");
+
+ bi1->setText((UnicodeString)"Hash code");
+ bi2->setText((UnicodeString)"Hash code");
+ bi3->setText((UnicodeString)"Hash code");
+
+ RuleBasedBreakIterator* bi1clone= (RuleBasedBreakIterator*)bi1->clone();
+ RuleBasedBreakIterator* bi2clone= (RuleBasedBreakIterator*)bi2->clone();
+
+ if(bi1->hashCode() != bi1clone->hashCode() || bi1->hashCode() != bi3->hashCode() ||
+ bi1clone->hashCode() != bi3->hashCode() || bi2->hashCode() != bi2clone->hashCode())
+ errln((UnicodeString)"ERROR: identical objects have different hashcodes");
+
+ if(bi1->hashCode() == bi2->hashCode() || bi2->hashCode() == bi3->hashCode() ||
+ bi1clone->hashCode() == bi2clone->hashCode() || bi1clone->hashCode() == bi2->hashCode())
+ errln((UnicodeString)"ERROR: different objects have same hashcodes");
+
+ delete bi1clone;
+ delete bi2clone;
+ delete bi1;
+ delete bi2;
+ delete bi3;
+
+}
+void RBBIAPITest::TestGetSetAdoptText()
+{
+ logln((UnicodeString)"Testing getText setText ");
+ UErrorCode status=U_ZERO_ERROR;
+ UnicodeString str1="first string.";
+ UnicodeString str2="Second string.";
+ RuleBasedBreakIterator* charIter1 = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ RuleBasedBreakIterator* wordIter1 = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createWordInstance(Locale::getDefault(), status);
+ if(U_FAILURE(status)){
+ errln((UnicodeString)"FAIL : in construction");
+ return;
+ }
+
+
+ CharacterIterator* text1= new StringCharacterIterator(str1);
+ CharacterIterator* text1Clone = text1->clone();
+ CharacterIterator* text2= new StringCharacterIterator(str2);
+ CharacterIterator* text3= new StringCharacterIterator(str2, 3, 10, 3); // "ond str"
+
+ wordIter1->setText(str1);
+ CharacterIterator *tci = &wordIter1->getText();
+ UnicodeString tstr;
+ tci->getText(tstr);
+ TEST_ASSERT(tstr == str1);
+ if(wordIter1->current() != 0)
+ errln((UnicodeString)"ERROR:1 setText did not set the iteration position to the beginning of the text, it is" + wordIter1->current() + (UnicodeString)"\n");
+
+ wordIter1->next(2);
+
+ wordIter1->setText(str2);
+ if(wordIter1->current() != 0)
+ errln((UnicodeString)"ERROR:2 setText did not reset the iteration position to the beginning of the text, it is" + wordIter1->current() + (UnicodeString)"\n");
+
+
+ charIter1->adoptText(text1Clone);
+ TEST_ASSERT(wordIter1->getText() != charIter1->getText());
+ tci = &wordIter1->getText();
+ tci->getText(tstr);
+ TEST_ASSERT(tstr == str2);
+ tci = &charIter1->getText();
+ tci->getText(tstr);
+ TEST_ASSERT(tstr == str1);
+
+
+ RuleBasedBreakIterator* rb=(RuleBasedBreakIterator*)wordIter1->clone();
+ rb->adoptText(text1);
+ if(rb->getText() != *text1)
+ errln((UnicodeString)"ERROR:1 error in adoptText ");
+ rb->adoptText(text2);
+ if(rb->getText() != *text2)
+ errln((UnicodeString)"ERROR:2 error in adoptText ");
+
+ // Adopt where iterator range is less than the entire orignal source string.
+ // (With the change of the break engine to working with UText internally,
+ // CharacterIterators starting at positions other than zero are not supported)
+ rb->adoptText(text3);
+ TEST_ASSERT(rb->preceding(2) == 0);
+ TEST_ASSERT(rb->following(11) == BreakIterator::DONE);
+ //if(rb->preceding(2) != 3) {
+ // errln((UnicodeString)"ERROR:3 error in adoptText ");
+ //}
+ //if(rb->following(11) != BreakIterator::DONE) {
+ // errln((UnicodeString)"ERROR:4 error in adoptText ");
+ //}
+
+ // UText API
+ //
+ // Quick test to see if UText is working at all.
+ //
+ const char *s1 = "\x68\x65\x6C\x6C\x6F\x20\x77\x6F\x72\x6C\x64"; /* "hello world" in UTF-8 */
+ const char *s2 = "\x73\x65\x65\x20\x79\x61"; /* "see ya" in UTF-8 */
+ // 012345678901
+
+ status = U_ZERO_ERROR;
+ UText *ut = utext_openUTF8(NULL, s1, -1, &status);
+ wordIter1->setText(ut, status);
+ TEST_ASSERT_SUCCESS(status);
+
+ int32_t pos;
+ pos = wordIter1->first();
+ TEST_ASSERT(pos==0);
+ pos = wordIter1->next();
+ TEST_ASSERT(pos==5);
+ pos = wordIter1->next();
+ TEST_ASSERT(pos==6);
+ pos = wordIter1->next();
+ TEST_ASSERT(pos==11);
+ pos = wordIter1->next();
+ TEST_ASSERT(pos==UBRK_DONE);
+
+ status = U_ZERO_ERROR;
+ UText *ut2 = utext_openUTF8(NULL, s2, -1, &status);
+ TEST_ASSERT_SUCCESS(status);
+ wordIter1->setText(ut2, status);
+ TEST_ASSERT_SUCCESS(status);
+
+ pos = wordIter1->first();
+ TEST_ASSERT(pos==0);
+ pos = wordIter1->next();
+ TEST_ASSERT(pos==3);
+ pos = wordIter1->next();
+ TEST_ASSERT(pos==4);
+
+ pos = wordIter1->last();
+ TEST_ASSERT(pos==6);
+ pos = wordIter1->previous();
+ TEST_ASSERT(pos==4);
+ pos = wordIter1->previous();
+ TEST_ASSERT(pos==3);
+ pos = wordIter1->previous();
+ TEST_ASSERT(pos==0);
+ pos = wordIter1->previous();
+ TEST_ASSERT(pos==UBRK_DONE);
+
+ status = U_ZERO_ERROR;
+ UnicodeString sEmpty;
+ UText *gut2 = utext_openUnicodeString(NULL, &sEmpty, &status);
+ wordIter1->getUText(gut2, status);
+ TEST_ASSERT_SUCCESS(status);
+ utext_close(gut2);
+
+ utext_close(ut);
+ utext_close(ut2);
+
+ delete wordIter1;
+ delete charIter1;
+ delete rb;
+
+ }
+
+
+void RBBIAPITest::TestIteration()
+{
+ // This test just verifies that the API is present.
+ // Testing for correct operation of the break rules happens elsewhere.
+
+ UErrorCode status=U_ZERO_ERROR;
+ RuleBasedBreakIterator* bi = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ if (U_FAILURE(status) || bi == NULL) {
+ errln("Failure creating character break iterator. Status = %s", u_errorName(status));
+ }
+ delete bi;
+
+ status=U_ZERO_ERROR;
+ bi = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createWordInstance(Locale::getDefault(), status);
+ if (U_FAILURE(status) || bi == NULL) {
+ errln("Failure creating Word break iterator. Status = %s", u_errorName(status));
+ }
+ delete bi;
+
+ status=U_ZERO_ERROR;
+ bi = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createLineInstance(Locale::getDefault(), status);
+ if (U_FAILURE(status) || bi == NULL) {
+ errln("Failure creating Line break iterator. Status = %s", u_errorName(status));
+ }
+ delete bi;
+
+ status=U_ZERO_ERROR;
+ bi = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createSentenceInstance(Locale::getDefault(), status);
+ if (U_FAILURE(status) || bi == NULL) {
+ errln("Failure creating Sentence break iterator. Status = %s", u_errorName(status));
+ }
+ delete bi;
+
+ status=U_ZERO_ERROR;
+ bi = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createTitleInstance(Locale::getDefault(), status);
+ if (U_FAILURE(status) || bi == NULL) {
+ errln("Failure creating Title break iterator. Status = %s", u_errorName(status));
+ }
+ delete bi;
+
+ status=U_ZERO_ERROR;
+ bi = (RuleBasedBreakIterator*)RuleBasedBreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ if (U_FAILURE(status) || bi == NULL) {
+ errln("Failure creating character break iterator. Status = %s", u_errorName(status));
+ return; // Skip the rest of these tests.
+ }
+
+
+ UnicodeString testString="0123456789";
+ bi->setText(testString);
+
+ int32_t i;
+ i = bi->first();
+ if (i != 0) {
+ errln("Incorrect value from bi->first(). Expected 0, got %d.", i);
+ }
+
+ i = bi->last();
+ if (i != 10) {
+ errln("Incorrect value from bi->last(). Expected 10, got %d", i);
+ }
+
+ //
+ // Previous
+ //
+ bi->last();
+ i = bi->previous();
+ if (i != 9) {
+ errln("Incorrect value from bi->last() at line %d. Expected 9, got %d", __LINE__, i);
+ }
+
+
+ bi->first();
+ i = bi->previous();
+ if (i != BreakIterator::DONE) {
+ errln("Incorrect value from bi->previous() at line %d. Expected DONE, got %d", __LINE__, i);
+ }
+
+ //
+ // next()
+ //
+ bi->first();
+ i = bi->next();
+ if (i != 1) {
+ errln("Incorrect value from bi->next() at line %d. Expected 1, got %d", __LINE__, i);
+ }
+
+ bi->last();
+ i = bi->next();
+ if (i != BreakIterator::DONE) {
+ errln("Incorrect value from bi->next() at line %d. Expected DONE, got %d", __LINE__, i);
+ }
+
+
+ //
+ // current()
+ //
+ bi->first();
+ i = bi->current();
+ if (i != 0) {
+ errln("Incorrect value from bi->previous() at line %d. Expected 0, got %d", __LINE__, i);
+ }
+
+ bi->next();
+ i = bi->current();
+ if (i != 1) {
+ errln("Incorrect value from bi->previous() at line %d. Expected 1, got %d", __LINE__, i);
+ }
+
+ bi->last();
+ bi->next();
+ i = bi->current();
+ if (i != 10) {
+ errln("Incorrect value from bi->previous() at line %d. Expected 10, got %d", __LINE__, i);
+ }
+
+ bi->first();
+ bi->previous();
+ i = bi->current();
+ if (i != 0) {
+ errln("Incorrect value from bi->previous() at line %d. Expected 0, got %d", __LINE__, i);
+ }
+
+
+ //
+ // Following()
+ //
+ i = bi->following(4);
+ if (i != 5) {
+ errln("Incorrect value from bi->following() at line %d. Expected 5, got %d", __LINE__, i);
+ }
+
+ i = bi->following(9);
+ if (i != 10) {
+ errln("Incorrect value from bi->following() at line %d. Expected 10, got %d", __LINE__, i);
+ }
+
+ i = bi->following(10);
+ if (i != BreakIterator::DONE) {
+ errln("Incorrect value from bi->following() at line %d. Expected DONE, got %d", __LINE__, i);
+ }
+
+
+ //
+ // Preceding
+ //
+ i = bi->preceding(4);
+ if (i != 3) {
+ errln("Incorrect value from bi->preceding() at line %d. Expected 3, got %d", __LINE__, i);
+ }
+
+ i = bi->preceding(10);
+ if (i != 9) {
+ errln("Incorrect value from bi->preceding() at line %d. Expected 9, got %d", __LINE__, i);
+ }
+
+ i = bi->preceding(1);
+ if (i != 0) {
+ errln("Incorrect value from bi->preceding() at line %d. Expected 0, got %d", __LINE__, i);
+ }
+
+ i = bi->preceding(0);
+ if (i != BreakIterator::DONE) {
+ errln("Incorrect value from bi->preceding() at line %d. Expected DONE, got %d", __LINE__, i);
+ }
+
+
+ //
+ // isBoundary()
+ //
+ bi->first();
+ if (bi->isBoundary(3) != TRUE) {
+ errln("Incorrect value from bi->isBoudary() at line %d. Expected TRUE, got FALSE", __LINE__, i);
+ }
+ i = bi->current();
+ if (i != 3) {
+ errln("Incorrect value from bi->current() at line %d. Expected 3, got %d", __LINE__, i);
+ }
+
+
+ if (bi->isBoundary(11) != FALSE) {
+ errln("Incorrect value from bi->isBoudary() at line %d. Expected FALSE, got TRUE", __LINE__, i);
+ }
+ i = bi->current();
+ if (i != 10) {
+ errln("Incorrect value from bi->current() at line %d. Expected 10, got %d", __LINE__, i);
+ }
+
+ //
+ // next(n)
+ //
+ bi->first();
+ i = bi->next(4);
+ if (i != 4) {
+ errln("Incorrect value from bi->next() at line %d. Expected 4, got %d", __LINE__, i);
+ }
+
+ i = bi->next(6);
+ if (i != 10) {
+ errln("Incorrect value from bi->next() at line %d. Expected 10, got %d", __LINE__, i);
+ }
+
+ bi->first();
+ i = bi->next(11);
+ if (i != BreakIterator::DONE) {
+ errln("Incorrect value from bi->next() at line %d. Expected BreakIterator::DONE, got %d", __LINE__, i);
+ }
+
+ delete bi;
+
+}
+
+
+
+
+
+
+void RBBIAPITest::TestBuilder() {
+ UnicodeString rulesString1 = "$Letters = [:L:];\n"
+ "$Numbers = [:N:];\n"
+ "$Letters+;\n"
+ "$Numbers+;\n"
+ "[^$Letters $Numbers];\n"
+ "!.*;\n";
+ UnicodeString testString1 = "abc123..abc";
+ // 01234567890
+ int32_t bounds1[] = {0, 3, 6, 7, 8, 11};
+ UErrorCode status=U_ZERO_ERROR;
+ UParseError parseError;
+
+ RuleBasedBreakIterator *bi = new RuleBasedBreakIterator(rulesString1, parseError, status);
+ if(U_FAILURE(status)) {
+ errln("FAIL : in construction");
+ } else {
+ bi->setText(testString1);
+ doBoundaryTest(*bi, testString1, bounds1);
+ }
+ delete bi;
+}
+
+
+//
+// TestQuoteGrouping
+// Single quotes within rules imply a grouping, so that a modifier
+// following the quoted text (* or +) applies to all of the quoted chars.
+//
+void RBBIAPITest::TestQuoteGrouping() {
+ UnicodeString rulesString1 = "#Here comes the rule...\n"
+ "'$@!'*;\n" // (\$\@\!)*
+ ".;\n";
+
+ UnicodeString testString1 = "$@!$@!X$@!!X";
+ // 0123456789012
+ int32_t bounds1[] = {0, 6, 7, 10, 11, 12};
+ UErrorCode status=U_ZERO_ERROR;
+ UParseError parseError;
+
+ RuleBasedBreakIterator *bi = new RuleBasedBreakIterator(rulesString1, parseError, status);
+ if(U_FAILURE(status)) {
+ errln("FAIL : in construction");
+ } else {
+ bi->setText(testString1);
+ doBoundaryTest(*bi, testString1, bounds1);
+ }
+ delete bi;
+}
+
+//
+// TestRuleStatus
+// Test word break rule status constants.
+//
+void RBBIAPITest::TestRuleStatus() {
+ UChar str[30];
+ u_unescape("plain word 123.45 \\u9160\\u9161 \\u30a1\\u30a2 \\u3041\\u3094",
+ // 012345678901234567 8 9 0 1 2 3 4 5 6
+ // Ideographic Katakana Hiragana
+ str, 30);
+ UnicodeString testString1(str);
+ int32_t bounds1[] = {0, 5, 6, 10, 11, 17, 18, 19, 20, 21, 23, 24, 25, 26};
+ int32_t tag_lo[] = {UBRK_WORD_NONE, UBRK_WORD_LETTER, UBRK_WORD_NONE, UBRK_WORD_LETTER,
+ UBRK_WORD_NONE, UBRK_WORD_NUMBER, UBRK_WORD_NONE,
+ UBRK_WORD_IDEO, UBRK_WORD_IDEO, UBRK_WORD_NONE,
+ UBRK_WORD_KANA, UBRK_WORD_NONE, UBRK_WORD_KANA, UBRK_WORD_KANA};
+
+ int32_t tag_hi[] = {UBRK_WORD_NONE_LIMIT, UBRK_WORD_LETTER_LIMIT, UBRK_WORD_NONE_LIMIT, UBRK_WORD_LETTER_LIMIT,
+ UBRK_WORD_NONE_LIMIT, UBRK_WORD_NUMBER_LIMIT, UBRK_WORD_NONE_LIMIT,
+ UBRK_WORD_IDEO_LIMIT, UBRK_WORD_IDEO_LIMIT, UBRK_WORD_NONE_LIMIT,
+ UBRK_WORD_KANA_LIMIT, UBRK_WORD_NONE_LIMIT, UBRK_WORD_KANA_LIMIT, UBRK_WORD_KANA_LIMIT};
+
+ UErrorCode status=U_ZERO_ERROR;
+
+ RuleBasedBreakIterator *bi = (RuleBasedBreakIterator *)BreakIterator::createWordInstance(Locale::getEnglish(), status);
+ if(U_FAILURE(status)) {
+ errln("FAIL : in construction");
+ } else {
+ bi->setText(testString1);
+ // First test that the breaks are in the right spots.
+ doBoundaryTest(*bi, testString1, bounds1);
+
+ // Then go back and check tag values
+ int32_t i = 0;
+ int32_t pos, tag;
+ for (pos = bi->first(); pos != BreakIterator::DONE; pos = bi->next(), i++) {
+ if (pos != bounds1[i]) {
+ errln("FAIL: unexpected word break at postion %d", pos);
+ break;
+ }
+ tag = bi->getRuleStatus();
+ if (tag < tag_lo[i] || tag >= tag_hi[i]) {
+ errln("FAIL: incorrect tag value %d at position %d", tag, pos);
+ break;
+ }
+
+ // Check that we get the same tag values from getRuleStatusVec()
+ int32_t vec[10];
+ int t = bi->getRuleStatusVec(vec, 10, status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(t==1);
+ TEST_ASSERT(vec[0] == tag);
+ }
+ }
+ delete bi;
+
+ // Now test line break status. This test mostly is to confirm that the status constants
+ // are correctly declared in the header.
+ testString1 = "test line. \n";
+ // break type s s h
+
+ bi = (RuleBasedBreakIterator *)
+ BreakIterator::createLineInstance(Locale::getEnglish(), status);
+ if(U_FAILURE(status)) {
+ errln("failed to create word break iterator.");
+ } else {
+ int32_t i = 0;
+ int32_t pos, tag;
+ UBool success;
+
+ bi->setText(testString1);
+ pos = bi->current();
+ tag = bi->getRuleStatus();
+ for (i=0; i<3; i++) {
+ switch (i) {
+ case 0:
+ success = pos==0 && tag==UBRK_LINE_SOFT; break;
+ case 1:
+ success = pos==5 && tag==UBRK_LINE_SOFT; break;
+ case 2:
+ success = pos==12 && tag==UBRK_LINE_HARD; break;
+ default:
+ success = FALSE; break;
+ }
+ if (success == FALSE) {
+ errln("Fail: incorrect word break status or position. i=%d, pos=%d, tag=%d",
+ i, pos, tag);
+ break;
+ }
+ pos = bi->next();
+ tag = bi->getRuleStatus();
+ }
+ if (UBRK_LINE_SOFT >= UBRK_LINE_SOFT_LIMIT ||
+ UBRK_LINE_HARD >= UBRK_LINE_HARD_LIMIT ||
+ UBRK_LINE_HARD > UBRK_LINE_SOFT && UBRK_LINE_HARD < UBRK_LINE_SOFT_LIMIT ) {
+ errln("UBRK_LINE_* constants from header are inconsistent.");
+ }
+ }
+ delete bi;
+
+}
+
+
+//
+// TestRuleStatusVec
+// Test the vector form of break rule status.
+//
+void RBBIAPITest::TestRuleStatusVec() {
+ UnicodeString rulesString = "[A-N]{100}; \n"
+ "[a-w]{200}; \n"
+ "[\\p{L}]{300}; \n"
+ "[\\p{N}]{400}; \n"
+ "[0-5]{500}; \n"
+ "!.*;\n";
+ UnicodeString testString1 = "Aapz5?";
+ int32_t statusVals[10];
+ int32_t numStatuses;
+ int32_t pos;
+
+ UErrorCode status=U_ZERO_ERROR;
+ UParseError parseError;
+
+ RuleBasedBreakIterator *bi = new RuleBasedBreakIterator(rulesString, parseError, status);
+ TEST_ASSERT_SUCCESS(status);
+ if (U_SUCCESS(status)) {
+ bi->setText(testString1);
+
+ // A
+ pos = bi->next();
+ TEST_ASSERT(pos==1);
+ numStatuses = bi->getRuleStatusVec(statusVals, 10, status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(numStatuses == 2);
+ TEST_ASSERT(statusVals[0] == 100);
+ TEST_ASSERT(statusVals[1] == 300);
+
+ // a
+ pos = bi->next();
+ TEST_ASSERT(pos==2);
+ numStatuses = bi->getRuleStatusVec(statusVals, 10, status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(numStatuses == 2);
+ TEST_ASSERT(statusVals[0] == 200);
+ TEST_ASSERT(statusVals[1] == 300);
+
+ // p
+ pos = bi->next();
+ TEST_ASSERT(pos==3);
+ numStatuses = bi->getRuleStatusVec(statusVals, 10, status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(numStatuses == 2);
+ TEST_ASSERT(statusVals[0] == 200);
+ TEST_ASSERT(statusVals[1] == 300);
+
+ // z
+ pos = bi->next();
+ TEST_ASSERT(pos==4);
+ numStatuses = bi->getRuleStatusVec(statusVals, 10, status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(numStatuses == 1);
+ TEST_ASSERT(statusVals[0] == 300);
+
+ // 5
+ pos = bi->next();
+ TEST_ASSERT(pos==5);
+ numStatuses = bi->getRuleStatusVec(statusVals, 10, status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(numStatuses == 2);
+ TEST_ASSERT(statusVals[0] == 400);
+ TEST_ASSERT(statusVals[1] == 500);
+
+ // ?
+ pos = bi->next();
+ TEST_ASSERT(pos==6);
+ numStatuses = bi->getRuleStatusVec(statusVals, 10, status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(numStatuses == 1);
+ TEST_ASSERT(statusVals[0] == 0);
+
+ //
+ // Check buffer overflow error handling. Char == A
+ //
+ bi->first();
+ pos = bi->next();
+ TEST_ASSERT(pos==1);
+ memset(statusVals, -1, sizeof(statusVals));
+ numStatuses = bi->getRuleStatusVec(statusVals, 0, status);
+ TEST_ASSERT(status == U_BUFFER_OVERFLOW_ERROR);
+ TEST_ASSERT(numStatuses == 2);
+ TEST_ASSERT(statusVals[0] == -1);
+
+ status = U_ZERO_ERROR;
+ memset(statusVals, -1, sizeof(statusVals));
+ numStatuses = bi->getRuleStatusVec(statusVals, 1, status);
+ TEST_ASSERT(status == U_BUFFER_OVERFLOW_ERROR);
+ TEST_ASSERT(numStatuses == 2);
+ TEST_ASSERT(statusVals[0] == 100);
+ TEST_ASSERT(statusVals[1] == -1);
+
+ status = U_ZERO_ERROR;
+ memset(statusVals, -1, sizeof(statusVals));
+ numStatuses = bi->getRuleStatusVec(statusVals, 2, status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(numStatuses == 2);
+ TEST_ASSERT(statusVals[0] == 100);
+ TEST_ASSERT(statusVals[1] == 300);
+ TEST_ASSERT(statusVals[2] == -1);
+ }
+ delete bi;
+
+}
+
+//
+// Bug 2190 Regression test. Builder crash on rule consisting of only a
+// $variable reference
+void RBBIAPITest::TestBug2190() {
+ UnicodeString rulesString1 = "$aaa = abcd;\n"
+ "$bbb = $aaa;\n"
+ "$bbb;\n";
+ UnicodeString testString1 = "abcdabcd";
+ // 01234567890
+ int32_t bounds1[] = {0, 4, 8};
+ UErrorCode status=U_ZERO_ERROR;
+ UParseError parseError;
+
+ RuleBasedBreakIterator *bi = new RuleBasedBreakIterator(rulesString1, parseError, status);
+ if(U_FAILURE(status)) {
+ errln("FAIL : in construction");
+ } else {
+ bi->setText(testString1);
+ doBoundaryTest(*bi, testString1, bounds1);
+ }
+ delete bi;
+}
+
+
+void RBBIAPITest::TestRegistration() {
+#if !UCONFIG_NO_SERVICE
+ UErrorCode status = U_ZERO_ERROR;
+ BreakIterator* ja_word = BreakIterator::createWordInstance("ja_JP", status);
+
+ // ok to not delete these if we exit because of error?
+ BreakIterator* ja_char = BreakIterator::createCharacterInstance("ja_JP", status);
+ BreakIterator* root_word = BreakIterator::createWordInstance("", status);
+ BreakIterator* root_char = BreakIterator::createCharacterInstance("", status);
+
+ URegistryKey key = BreakIterator::registerInstance(ja_word, "xx", UBRK_WORD, status);
+ {
+ if (ja_word && *ja_word == *root_word) {
+ errln("japan not different from root");
+ }
+ }
+
+ {
+ BreakIterator* result = BreakIterator::createWordInstance("xx_XX", status);
+ UBool fail = TRUE;
+ if(result){
+ fail = *result != *ja_word;
+ }
+ delete result;
+ if (fail) {
+ errln("bad result for xx_XX/word");
+ }
+ }
+
+ {
+ BreakIterator* result = BreakIterator::createCharacterInstance("ja_JP", status);
+ UBool fail = TRUE;
+ if(result){
+ fail = *result != *ja_char;
+ }
+ delete result;
+ if (fail) {
+ errln("bad result for ja_JP/char");
+ }
+ }
+
+ {
+ BreakIterator* result = BreakIterator::createCharacterInstance("xx_XX", status);
+ UBool fail = TRUE;
+ if(result){
+ fail = *result != *root_char;
+ }
+ delete result;
+ if (fail) {
+ errln("bad result for xx_XX/char");
+ }
+ }
+
+ {
+ StringEnumeration* avail = BreakIterator::getAvailableLocales();
+ UBool found = FALSE;
+ const UnicodeString* p;
+ while ((p = avail->snext(status))) {
+ if (p->compare("xx") == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+ delete avail;
+ if (!found) {
+ errln("did not find test locale");
+ }
+ }
+
+ {
+ UBool unreg = BreakIterator::unregister(key, status);
+ if (!unreg) {
+ errln("unable to unregister");
+ }
+ }
+
+ {
+ BreakIterator* result = BreakIterator::createWordInstance("en_US", status);
+ BreakIterator* root = BreakIterator::createWordInstance("", status);
+ UBool fail = TRUE;
+ if(root){
+ fail = *root != *result;
+ }
+ delete root;
+ delete result;
+ if (fail) {
+ errln("did not get root break");
+ }
+ }
+
+ {
+ StringEnumeration* avail = BreakIterator::getAvailableLocales();
+ UBool found = FALSE;
+ const UnicodeString* p;
+ while ((p = avail->snext(status))) {
+ if (p->compare("xx") == 0) {
+ found = TRUE;
+ break;
+ }
+ }
+ delete avail;
+ if (found) {
+ errln("found test locale");
+ }
+ }
+
+ {
+ int32_t count;
+ UBool foundLocale = FALSE;
+ const Locale *avail = BreakIterator::getAvailableLocales(count);
+ for (int i=0; i<count; i++) {
+ if (avail[i] == Locale::getEnglish()) {
+ foundLocale = TRUE;
+ break;
+ }
+ }
+ if (foundLocale == FALSE) {
+ errln("BreakIterator::getAvailableLocales(&count), failed to find EN.");
+ }
+ }
+
+
+ // ja_word was adopted by factory
+ delete ja_char;
+ delete root_word;
+ delete root_char;
+#endif
+}
+
+void RBBIAPITest::RoundtripRule(const char *dataFile) {
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ parseError.line = 0;
+ parseError.offset = 0;
+ UDataMemory *data = udata_open(U_ICUDATA_BRKITR, "brk", dataFile, &status);
+ uint32_t length;
+ const UChar *builtSource;
+ const uint8_t *rbbiRules;
+ const uint8_t *builtRules;
+
+ if (U_FAILURE(status)) {
+ errln("Can't open \"%s\"", dataFile);
+ return;
+ }
+
+ builtRules = (const uint8_t *)udata_getMemory(data);
+ builtSource = (const UChar *)(builtRules + ((RBBIDataHeader*)builtRules)->fRuleSource);
+ RuleBasedBreakIterator *brkItr = new RuleBasedBreakIterator(builtSource, parseError, status);
+ if (U_FAILURE(status)) {
+ errln("createRuleBasedBreakIterator: ICU Error \"%s\" at line %d, column %d\n",
+ u_errorName(status), parseError.line, parseError.offset);
+ return;
+ };
+ rbbiRules = brkItr->getBinaryRules(length);
+ logln("Comparing \"%s\" len=%d", dataFile, length);
+ if (memcmp(builtRules, rbbiRules, (int32_t)length) != 0) {
+ errln("Built rules and rebuilt rules are different %s", dataFile);
+ return;
+ }
+ delete brkItr;
+ udata_close(data);
+}
+
+void RBBIAPITest::TestRoundtripRules() {
+ RoundtripRule("word");
+ RoundtripRule("title");
+ RoundtripRule("sent");
+ RoundtripRule("line");
+ RoundtripRule("char");
+ if (!quick) {
+ RoundtripRule("word_ja");
+ RoundtripRule("word_POSIX");
+ }
+}
+
+//---------------------------------------------
+// runIndexedTest
+//---------------------------------------------
+
+void RBBIAPITest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln((UnicodeString)"TestSuite RuleBasedBreakIterator API ");
+ switch (index) {
+ // case 0: name = "TestConstruction"; if (exec) TestConstruction(); break;
+ case 0: name = "TestCloneEquals"; if (exec) TestCloneEquals(); break;
+ case 1: name = "TestgetRules"; if (exec) TestgetRules(); break;
+ case 2: name = "TestHashCode"; if (exec) TestHashCode(); break;
+ case 3: name = "TestGetSetAdoptText"; if (exec) TestGetSetAdoptText(); break;
+ case 4: name = "TestIteration"; if (exec) TestIteration(); break;
+ case 5: name = "TestBuilder"; if (exec) TestBuilder(); break;
+ case 6: name = "TestQuoteGrouping"; if (exec) TestQuoteGrouping(); break;
+ case 7: name = "TestRuleStatus"; if (exec) TestRuleStatus(); break;
+ case 8: name = "TestRuleStatusVec"; if (exec) TestRuleStatusVec(); break;
+ case 9: name = "TestBug2190"; if (exec) TestBug2190(); break;
+ case 10: name = "TestRegistration"; if (exec) TestRegistration(); break;
+ case 11: name = "TestBoilerPlate"; if (exec) TestBoilerPlate(); break;
+ case 12: name = "TestRoundtripRules"; if (exec) TestRoundtripRules(); break;
+
+ default: name = ""; break; // needed to end loop
+ }
+}
+
+//---------------------------------------------
+//Internal subroutines
+//---------------------------------------------
+
+void RBBIAPITest::doBoundaryTest(RuleBasedBreakIterator& bi, UnicodeString& text, int32_t *boundaries){
+ logln((UnicodeString)"testIsBoundary():");
+ int32_t p = 0;
+ UBool isB;
+ for (int32_t i = 0; i < text.length(); i++) {
+ isB = bi.isBoundary(i);
+ logln((UnicodeString)"bi.isBoundary(" + i + ") -> " + isB);
+
+ if (i == boundaries[p]) {
+ if (!isB)
+ errln((UnicodeString)"Wrong result from isBoundary() for " + i + (UnicodeString)": expected true, got false");
+ p++;
+ }
+ else {
+ if (isB)
+ errln((UnicodeString)"Wrong result from isBoundary() for " + i + (UnicodeString)": expected false, got true");
+ }
+ }
+}
+void RBBIAPITest::doTest(UnicodeString& testString, int32_t start, int32_t gotoffset, int32_t expectedOffset, const char* expectedString){
+ UnicodeString selected;
+ UnicodeString expected=CharsToUnicodeString(expectedString);
+
+ if(gotoffset != expectedOffset)
+ errln((UnicodeString)"ERROR:****returned #" + gotoffset + (UnicodeString)" instead of #" + expectedOffset);
+ if(start <= gotoffset){
+ testString.extractBetween(start, gotoffset, selected);
+ }
+ else{
+ testString.extractBetween(gotoffset, start, selected);
+ }
+ if(selected.compare(expected) != 0)
+ errln(prettify((UnicodeString)"ERROR:****selected \"" + selected + "\" instead of \"" + expected + "\""));
+ else
+ logln(prettify("****selected \"" + selected + "\""));
+}
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/rbbiapts.h b/Build/source/libs/icu/icu-xetex/test/intltest/rbbiapts.h
new file mode 100644
index 00000000000..ae759248cea
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/rbbiapts.h
@@ -0,0 +1,97 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1999-2004, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/************************************************************************
+* Date Name Description
+* 12/14/99 Madhu Creation.
+************************************************************************/
+
+
+
+#ifndef RBBIAPITEST_H
+#define RBBIAPITEST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "intltest.h"
+#include "unicode/rbbi.h"
+
+/**
+ * API Test the RuleBasedBreakIterator class
+ */
+class RBBIAPITest: public IntlTest {
+public:
+
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+ /**
+ * Tests Constructor behaviour of RuleBasedBreakIterator
+ **/
+ // void TestConstruction(void);
+ /**
+ * Tests clone() and equals() methods of RuleBasedBreakIterator
+ **/
+ void TestCloneEquals();
+ /**
+ * Tests toString() method of RuleBasedBreakIterator
+ **/
+ void TestgetRules();
+ /**
+ * Tests the method hashCode() of RuleBasedBreakIterator
+ **/
+ void TestHashCode();
+ /**
+ * Tests the methods getText() and setText() of RuleBasedBreakIterator
+ **/
+ void TestGetSetAdoptText();
+ /**
+ * Testing the iteration methods of RuleBasedBreakIterator
+ **/
+ void TestIteration(void);
+
+
+ /**
+ * Tests creating RuleBasedBreakIterator from rules strings.
+ **/
+ void TestBuilder(void);
+
+ void TestRoundtripRules(void);
+
+ void RoundtripRule(const char *dataFile);
+
+ /**
+ * Tests grouping effect of 'single quotes' in rules.
+ **/
+ void TestQuoteGrouping();
+
+ /**
+ * Tests word break status returns.
+ */
+ void TestRuleStatus();
+ void TestRuleStatusVec();
+
+ void TestBug2190();
+
+ void TestBoilerPlate();
+
+ void TestRegistration();
+
+ /**
+ *Internal subroutines
+ **/
+ /* Internal subroutine used by TestIsBoundary() */
+ void doBoundaryTest(RuleBasedBreakIterator& bi, UnicodeString& text, int32_t *boundaries);
+
+ /*Internal subroutine used for comparision of expected and acquired results */
+ void doTest(UnicodeString& testString, int32_t start, int32_t gotoffset, int32_t expectedOffset, const char* expected);
+
+
+};
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/rbbitst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/rbbitst.cpp
new file mode 100644
index 00000000000..4a2453f0b5a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/rbbitst.cpp
@@ -0,0 +1,4287 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1999-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/************************************************************************
+* Date Name Description
+* 12/15/99 Madhu Creation.
+* 01/12/2000 Madhu Updated for changed API and added new tests
+************************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "unicode/utypes.h"
+#include "unicode/brkiter.h"
+#include "unicode/rbbi.h"
+#include "unicode/uchar.h"
+#include "unicode/utf16.h"
+#include "unicode/ucnv.h"
+#include "unicode/schriter.h"
+#include "unicode/uniset.h"
+#include "unicode/regex.h" // TODO: make conditional on regexp being built.
+#include "unicode/ustring.h"
+#include "unicode/utext.h"
+#include "intltest.h"
+#include "rbbitst.h"
+#include <string.h>
+#include "uvector.h"
+#include "uvectr32.h"
+#include "triedict.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define TEST_ASSERT(x) {if (!(x)) { \
+ errln("Failure in file %s, line %d", __FILE__, __LINE__);}}
+
+#define TEST_ASSERT_SUCCESS(errcode) {if (U_FAILURE(errcode)) { \
+ errln("Failure in file %s, line %d, status = \"%s\"", __FILE__, __LINE__, u_errorName(errcode));}}
+
+
+//---------------------------------------------
+// runIndexedTest
+//---------------------------------------------
+
+void RBBITest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* params )
+{
+ if (exec) logln("TestSuite RuleBasedBreakIterator: ");
+
+ switch (index) {
+ case 0: name = "TestBug4153072";
+ if(exec) TestBug4153072(); break;
+ case 1: name = "TestJapaneseLineBreak";
+ if(exec) TestJapaneseLineBreak(); break;
+ case 2: name = "TestStatusReturn";
+ if(exec) TestStatusReturn(); break;
+ case 3: name = "TestUnicodeFiles";
+ if(exec) TestUnicodeFiles(); break;
+ case 4: name = "TestEmptyString";
+ if(exec) TestEmptyString(); break;
+
+ case 5: name = "TestGetAvailableLocales";
+ if(exec) TestGetAvailableLocales(); break;
+
+ case 6: name = "TestGetDisplayName";
+ if(exec) TestGetDisplayName(); break;
+
+ case 7: name = "TestEndBehaviour";
+ if(exec) TestEndBehaviour(); break;
+ case 8: name = "TestMixedThaiLineBreak";
+ if(exec) TestMixedThaiLineBreak(); break;
+ case 9: name = "TestThaiLineBreak";
+ if(exec) TestThaiLineBreak(); break;
+ case 10: name = "TestMaiyamok";
+ if(exec) TestMaiyamok(); break;
+ case 11: name = "TestWordBreaks";
+ if(exec) TestWordBreaks(); break;
+ case 12: name = "TestWordBoundary";
+ if(exec) TestWordBoundary(); break;
+ case 13: name = "TestLineBreaks";
+ if(exec) TestLineBreaks(); break;
+ case 14: name = "TestSentBreaks";
+ if(exec) TestSentBreaks(); break;
+ case 15: name = "TestExtended";
+ if(exec) TestExtended(); break;
+ case 16: name = "TestMonkey";
+ if(exec) {
+ #if !UCONFIG_NO_REGULAR_EXPRESSIONS
+ TestMonkey(params);
+ #else
+ logln("skipping TestMonkey (UCONFIG_NO_REGULAR_EXPRESSIONS)");
+ #endif
+ }
+ break;
+ case 17: name = "TestBug3818";
+ if(exec) TestBug3818(); break;
+ case 18: name = "TestJapaneseWordBreak";
+ if(exec) TestJapaneseWordBreak(); break;
+ case 19: name = "TestDebug";
+ if(exec) TestDebug(); break;
+ case 20: name = "TestTrieDict";
+ if(exec) TestTrieDict(); break;
+ case 21: name = "TestBug5775";
+ if (exec) TestBug5775(); break;
+
+ default: name = ""; break; //needed to end loop
+ }
+}
+
+
+//---------------------------------------------------------------------------
+//
+// class BITestData Holds a set of Break iterator test data and results
+// Includes
+// - the string data to be broken
+// - a vector of the expected break positions.
+// - a vector of source line numbers for the data,
+// (to help see where errors occured.)
+// - The expected break tag values.
+// - Vectors of actual break positions and tag values.
+// - Functions for comparing actual with expected and
+// reporting errors.
+//
+//----------------------------------------------------------------------------
+class BITestData {
+public:
+ UnicodeString fDataToBreak;
+ UVector fExpectedBreakPositions;
+ UVector fExpectedTags;
+ UVector fLineNum;
+ UVector fActualBreakPositions; // Test Results.
+ UVector fActualTags;
+
+ BITestData(UErrorCode &status);
+ void addDataChunk(const char *data, int32_t tag, int32_t lineNum, UErrorCode status);
+ void checkResults(const char *heading, RBBITest *test);
+ void err(const char *heading, RBBITest *test, int32_t expectedIdx, int32_t actualIdx);
+ void clearResults();
+};
+
+//
+// Constructor.
+//
+BITestData::BITestData(UErrorCode &status)
+: fExpectedBreakPositions(status), fExpectedTags(status), fLineNum(status), fActualBreakPositions(status),
+ fActualTags(status)
+{
+}
+
+//
+// addDataChunk. Add a section (non-breaking) piece if data to the test data.
+// The macro form collects the line number, which is helpful
+// when tracking down failures.
+//
+// A null data item is inserted at the start of each test's data
+// to put the starting zero into the data list. The position saved for
+// each non-null item is its ending position.
+//
+#define ADD_DATACHUNK(td, data, tag, status) td.addDataChunk(data, tag, __LINE__, status);
+void BITestData::addDataChunk(const char *data, int32_t tag, int32_t lineNum, UErrorCode status) {
+ if (U_FAILURE(status)) {return;}
+ if (data != NULL) {
+ fDataToBreak.append(CharsToUnicodeString(data));
+ }
+ fExpectedBreakPositions.addElement(fDataToBreak.length(), status);
+ fExpectedTags.addElement(tag, status);
+ fLineNum.addElement(lineNum, status);
+}
+
+
+//
+// checkResults. Compare the actual and expected break positions, report any differences.
+//
+void BITestData::checkResults(const char *heading, RBBITest *test) {
+ int32_t expectedIndex = 0;
+ int32_t actualIndex = 0;
+
+ for (;;) {
+ // If we've run through both the expected and actual results vectors, we're done.
+ // break out of the loop.
+ if (expectedIndex >= fExpectedBreakPositions.size() &&
+ actualIndex >= fActualBreakPositions.size()) {
+ break;
+ }
+
+
+ if (expectedIndex >= fExpectedBreakPositions.size()) {
+ err(heading, test, expectedIndex-1, actualIndex);
+ actualIndex++;
+ continue;
+ }
+
+ if (actualIndex >= fActualBreakPositions.size()) {
+ err(heading, test, expectedIndex, actualIndex-1);
+ expectedIndex++;
+ continue;
+ }
+
+ if (fActualBreakPositions.elementAti(actualIndex) != fExpectedBreakPositions.elementAti(expectedIndex)) {
+ err(heading, test, expectedIndex, actualIndex);
+ // Try to resync the positions of the indices, to avoid a rash of spurious erros.
+ if (fActualBreakPositions.elementAti(actualIndex) < fExpectedBreakPositions.elementAti(expectedIndex)) {
+ actualIndex++;
+ } else {
+ expectedIndex++;
+ }
+ continue;
+ }
+
+ if (fActualTags.elementAti(actualIndex) != fExpectedTags.elementAti(expectedIndex)) {
+ test->errln("%s, tag mismatch. Test Line = %d, expected tag=%d, got %d",
+ heading, fLineNum.elementAt(expectedIndex),
+ fExpectedTags.elementAti(expectedIndex), fActualTags.elementAti(actualIndex));
+ }
+
+ actualIndex++;
+ expectedIndex++;
+ }
+}
+
+//
+// err - An error was found. Report it, along with information about where the
+// incorrectly broken test data appeared in the source file.
+//
+void BITestData::err(const char *heading, RBBITest *test, int32_t expectedIdx, int32_t actualIdx)
+{
+ int32_t expected = fExpectedBreakPositions.elementAti(expectedIdx);
+ int32_t actual = fActualBreakPositions.elementAti(actualIdx);
+ int32_t o = 0;
+ int32_t line = fLineNum.elementAti(expectedIdx);
+ if (expectedIdx > 0) {
+ // The line numbers are off by one because a premature break occurs somewhere
+ // within the previous item, rather than at the start of the current (expected) item.
+ // We want to report the offset of the unexpected break from the start of
+ // this previous item.
+ o = actual - fExpectedBreakPositions.elementAti(expectedIdx-1);
+ }
+ if (actual < expected) {
+ test->errln("%s unexpected break at offset %d in test item from line %d", heading, o, line);
+ } else {
+ test->errln("%s Failed to find break at end of item from line %d", heading, line);
+ }
+}
+
+
+void BITestData::clearResults() {
+ fActualBreakPositions.removeAllElements();
+ fActualTags.removeAllElements();
+}
+
+
+//-----------------------------------------------------------------------------------
+//
+// Cannned Test Characters
+//
+//-----------------------------------------------------------------------------------
+
+static const UChar cannedTestArray[] = {
+ 0x0001, 0x0002, 0x0003, 0x0004, 0x0020, 0x0021, '\\', 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0028, 0x0029, 0x002b, 0x002d, 0x0030, 0x0031,
+ 0x0032, 0x0033, 0x0034, 0x003c, 0x003d, 0x003e, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x005b, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x007b,
+ 0x007d, 0x007c, 0x002c, 0x00a0, 0x00a2,
+ 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00ab, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b2, 0x00b3,
+ 0x00b4, 0x00b9, 0x00bb, 0x00bc, 0x00bd, 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x0300, 0x0301, 0x0302, 0x0303,
+ 0x0304, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x0903, 0x093e, 0x093f, 0x0940, 0x0949, 0x0f3a, 0x0f3b, 0x2000,
+ 0x2001, 0x2002, 0x200c, 0x200d, 0x200e, 0x200f, 0x2010, 0x2011, 0x2012, 0x2028, 0x2029, 0x202a, 0x203e, 0x203f,
+ 0x2040, 0x20dd, 0x20de, 0x20df, 0x20e0, 0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x0000
+};
+
+static UnicodeString* cannedTestChars = 0;
+
+#define halfNA "\\u0928\\u094d\\u200d"
+#define halfSA "\\u0938\\u094d\\u200d"
+#define halfCHA "\\u091a\\u094d\\u200d"
+#define halfKA "\\u0915\\u094d\\u200d"
+#define deadTA "\\u0924\\u094d"
+
+//--------------------------------------------------------------------------------------
+//
+// RBBITest constructor and destructor
+//
+//--------------------------------------------------------------------------------------
+
+RBBITest::RBBITest() {
+ UnicodeString temp(cannedTestArray);
+ cannedTestChars = new UnicodeString();
+ *cannedTestChars += (UChar)0x0000;
+ *cannedTestChars += temp;
+}
+
+
+RBBITest::~RBBITest() {
+ delete cannedTestChars;
+}
+
+
+static const int T_NUMBER = 100;
+static const int T_LETTER = 200;
+static const int T_H_OR_K = 300;
+static const int T_IDEO = 400;
+
+
+
+
+
+
+//--------------------------------------------------------------------
+//Testing the BreakIterator for devanagari script
+//--------------------------------------------------------------------
+
+#define deadRA "\\u0930\\u094d" /*deadform RA = devanagari RA + virama*/
+#define deadPHA "\\u092b\\u094d" /*deadform PHA = devanagari PHA + virama*/
+#define deadTTHA "\\u0920\\u094d"
+#define deadPA "\\u092a\\u094d"
+#define deadSA "\\u0938\\u094d"
+#define visarga "\\u0903" /*devanagari visarga looks like a english colon*/
+
+
+
+
+
+
+//-----------------------------------------------------------------------------------
+//
+// Test for status {tag} return value from break rules.
+// TODO: a more thorough test.
+//
+//-----------------------------------------------------------------------------------
+void RBBITest::TestStatusReturn() {
+ UnicodeString rulesString1 = "$Letters = [:L:];\n"
+ "$Numbers = [:N:];\n"
+ "$Letters+{1};\n"
+ "$Numbers+{2};\n"
+ "Help\\ {4}/me\\!;\n"
+ "[^$Letters $Numbers];\n"
+ "!.*;\n";
+ UnicodeString testString1 = "abc123..abc Help me Help me!";
+ // 01234567890123456789012345678
+ int32_t bounds1[] = {0, 3, 6, 7, 8, 11, 12, 16, 17, 19, 20, 25, 27, 28, -1};
+ int32_t brkStatus[] = {0, 1, 2, 0, 0, 1, 0, 1, 0, 1, 0, 4, 1, 0, -1};
+
+ UErrorCode status=U_ZERO_ERROR;
+ UParseError parseError;
+
+ RuleBasedBreakIterator *bi = new RuleBasedBreakIterator(rulesString1, parseError, status);
+ if(U_FAILURE(status)) {
+ errln("FAIL : in construction");
+ } else {
+ int32_t pos;
+ int32_t i = 0;
+ bi->setText(testString1);
+ for (pos=bi->first(); pos!= BreakIterator::DONE; pos=bi->next()) {
+ if (pos != bounds1[i]) {
+ errln("FAIL: expected break at %d, got %d\n", bounds1[i], pos);
+ break;
+ }
+
+ int tag = bi->getRuleStatus();
+ if (tag != brkStatus[i]) {
+ errln("FAIL: break at %d, expected tag %d, got tag %d\n", pos, brkStatus[i], tag);
+ break;
+ }
+ i++;
+ }
+ }
+ delete bi;
+}
+
+
+static void printStringBreaks(UnicodeString ustr, int expected[],
+ int expectedcount)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ char name[100];
+ printf("code alpha extend alphanum type word sent line name\n");
+ int j;
+ for (j = 0; j < ustr.length(); j ++) {
+ if (expectedcount > 0) {
+ int k;
+ for (k = 0; k < expectedcount; k ++) {
+ if (j == expected[k]) {
+ printf("------------------------------------------------ %d\n",
+ j);
+ }
+ }
+ }
+ UChar32 c = ustr.char32At(j);
+ if (c > 0xffff) {
+ j ++;
+ }
+ u_charName(c, U_UNICODE_CHAR_NAME, name, 100, &status);
+ printf("%7x %5d %6d %8d %4s %4s %4s %4s %s\n", (int)c,
+ u_isUAlphabetic(c),
+ u_hasBinaryProperty(c, UCHAR_GRAPHEME_EXTEND),
+ u_isalnum(c),
+ u_getPropertyValueName(UCHAR_GENERAL_CATEGORY,
+ u_charType(c),
+ U_SHORT_PROPERTY_NAME),
+ u_getPropertyValueName(UCHAR_WORD_BREAK,
+ u_getIntPropertyValue(c,
+ UCHAR_WORD_BREAK),
+ U_SHORT_PROPERTY_NAME),
+ u_getPropertyValueName(UCHAR_SENTENCE_BREAK,
+ u_getIntPropertyValue(c,
+ UCHAR_SENTENCE_BREAK),
+ U_SHORT_PROPERTY_NAME),
+ u_getPropertyValueName(UCHAR_LINE_BREAK,
+ u_getIntPropertyValue(c,
+ UCHAR_LINE_BREAK),
+ U_SHORT_PROPERTY_NAME),
+ name);
+ }
+}
+
+void RBBITest::TestThaiLineBreak() {
+ UErrorCode status = U_ZERO_ERROR;
+ BITestData thaiLineSelection(status);
+
+ // \u0e2f-- the Thai paiyannoi character-- isn't a letter. It's a symbol that
+ // represents elided letters at the end of a long word. It should be bound to
+ // the end of the word and not treated as an independent punctuation mark.
+
+
+ ADD_DATACHUNK(thaiLineSelection, NULL, 0, status); // Break at start of data
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e2a\\u0e16\\u0e32\\u0e19\\u0e35\\u0e2f", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e08\\u0e30", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e23\\u0e30\\u0e14\\u0e21", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e40\\u0e08\\u0e49\\u0e32", 0, status);
+// ADD_DATACHUNK(thaiLineSelection, "\\u0e2b\\u0e19\\u0e49\\u0e32", 0, status);
+// ADD_DATACHUNK(thaiLineSelection, "\\u0e17\\u0e35\\u0e48", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e2b\\u0e19\\u0e49\\u0e32\\u0e17\\u0e35\\u0e48", 0, status);
+ // the commented-out lines (I think) are the preferred result; this line is what our current dictionary is giving us
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e2d\\u0e2d\\u0e01", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e21\\u0e32", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e40\\u0e23\\u0e48\\u0e07", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e23\\u0e30\\u0e1a\\u0e32\\u0e22", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e2d\\u0e22\\u0e48\\u0e32\\u0e07", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e40\\u0e15\\u0e47\\u0e21", 0, status);
+
+ // the one time where the paiyannoi occurs somewhere other than at the end
+ // of a word is in the Thai abbrevation for "etc.", which both begins and
+ // ends with a paiyannoi
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e2f\\u0e25\\u0e2f", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e17\\u0e35\\u0e48", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e19\\u0e31\\u0e49\\u0e19", 0, status);
+
+ RuleBasedBreakIterator* e = (RuleBasedBreakIterator *)BreakIterator::createLineInstance(
+ Locale("th"), status);
+ if (U_FAILURE(status))
+ {
+ errln("Failed to create the BreakIterator for Thai locale in TestThaiLineBreak.\n");
+ return;
+ }
+
+ generalIteratorTest(*e, thaiLineSelection);
+ delete e;
+}
+
+
+
+void RBBITest::TestMixedThaiLineBreak()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ BITestData thaiLineSelection(status);
+
+ ADD_DATACHUNK(thaiLineSelection, NULL, 0, status); // Break at start of data
+
+
+ // @suwit -- Test Arabic numerals, Thai numerals, Punctuation and English characters
+ // start
+
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E1B\\u0E35", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E1E\\u0E38\\u0E17\\u0E18\\u0E28\\u0E31\\u0E01\\u0E23\\u0E32\\u0E0A ", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "2545 ", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E40\\u0E1B\\u0E47\\u0E19", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E1B\\u0E35", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E09\\u0E25\\u0E2D\\u0E07", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E04\\u0E23\\u0E1A", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E23\\u0E2D\\u0E1A ", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\"\\u0E52\\u0E52\\u0E50 ", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E1b\\u0E35\" ", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E02\\u0E2d\\u0E07", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E01\\u0E23\\u0E38\\u0E07", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E23\\u0E31\\u0E15\\u0E19\\u0E42\\u0E01\\u0E2A\\u0E34\\u0E19\\u0E17\\u0E23\\u0E4C ", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "(\\u0E01\\u0E23\\u0E38\\u0E07\\u0E40\\u0E17\\u0E1e\\u0E2F", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0E2B\\u0E23\\u0E37\\u0E2D ", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "Bangkok)", 0, status);
+
+ // @suwit - end of changes
+
+
+ RuleBasedBreakIterator* e = (RuleBasedBreakIterator *)BreakIterator::createLineInstance(Locale("th"), status);
+ if (U_FAILURE(status))
+ {
+ errln("Failed to create the BreakIterator for Thai locale in TestMixedThaiLineBreak.\n");
+ return;
+ }
+
+
+ generalIteratorTest(*e, thaiLineSelection);
+ delete e;
+}
+
+
+void RBBITest::TestMaiyamok()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ BITestData thaiLineSelection(status);
+ ADD_DATACHUNK(thaiLineSelection, NULL, 0, status); // Break at start of data
+ // the Thai maiyamok character is a shorthand symbol that means "repeat the previous
+ // word". Instead of appearing as a word unto itself, however, it's kept together
+ // with the word before it
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e44\\u0e1b\\u0e46", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e21\\u0e32\\u0e46", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e23\\u0e30\\u0e2b\\u0e27\\u0e48\\u0e32\\u0e07", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e01\\u0e23\\u0e38\\u0e07", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e40\\u0e17\\u0e1e", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e41\\u0e25\\u0e30", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e40\\u0e03\\u0e35", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e22\\u0e07", 0, status);
+ ADD_DATACHUNK(thaiLineSelection, "\\u0e43\\u0e2b\\u0e21\\u0e48", 0, status);
+
+ RuleBasedBreakIterator* e = (RuleBasedBreakIterator *)BreakIterator::createLineInstance(
+ Locale("th"), status);
+
+ if (U_FAILURE(status))
+ {
+ errln("Failed to create the BreakIterator for Thai locale in TestMaiyamok.\n");
+ return;
+ }
+ generalIteratorTest(*e, thaiLineSelection);
+ delete e;
+}
+
+
+
+void RBBITest::TestBug3818() {
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Four Thai words...
+ static const UChar thaiWordData[] = { 0x0E43,0x0E2B,0x0E0D,0x0E48, 0x0E43,0x0E2B,0x0E0D,0x0E48,
+ 0x0E43,0x0E2B,0x0E0D,0x0E48, 0x0E43,0x0E2B,0x0E0D,0x0E48, 0 };
+ UnicodeString thaiStr(thaiWordData);
+
+ RuleBasedBreakIterator* bi =
+ (RuleBasedBreakIterator *)BreakIterator::createWordInstance(Locale("th"), status);
+ if (U_FAILURE(status) || bi == NULL) {
+ errln("Fail at file %s, line %d, status = %s", __FILE__, __LINE__, u_errorName(status));
+ return;
+ }
+ bi->setText(thaiStr);
+
+ int32_t startOfSecondWord = bi->following(1);
+ if (startOfSecondWord != 4) {
+ errln("Fail at file %s, line %d expected start of word at 4, got %d",
+ __FILE__, __LINE__, startOfSecondWord);
+ }
+ startOfSecondWord = bi->following(0);
+ if (startOfSecondWord != 4) {
+ errln("Fail at file %s, line %d expected start of word at 4, got %d",
+ __FILE__, __LINE__, startOfSecondWord);
+ }
+ delete bi;
+}
+
+
+void RBBITest::TestJapaneseWordBreak() {
+ UErrorCode status = U_ZERO_ERROR;
+ BITestData japaneseWordSelection(status);
+
+ ADD_DATACHUNK(japaneseWordSelection, NULL, 0, status); // Break at start of data
+ ADD_DATACHUNK(japaneseWordSelection, "\\u4ECA\\u65E5", 400, status); //2
+ ADD_DATACHUNK(japaneseWordSelection, "\\u306F\\u3044\\u3044", 300, status); //5
+ ADD_DATACHUNK(japaneseWordSelection, "\\u5929\\u6C17", 400, status); //7
+ ADD_DATACHUNK(japaneseWordSelection, "\\u3067\\u3059\\u306D", 300, status); //10
+ ADD_DATACHUNK(japaneseWordSelection, "\\u3002", 0, status); //11
+ ADD_DATACHUNK(japaneseWordSelection, "\\u000D\\u000A", 0, status); //12
+
+ RuleBasedBreakIterator* e = (RuleBasedBreakIterator *)BreakIterator::createWordInstance(
+ Locale("ja"), status);
+ if (U_FAILURE(status))
+ {
+ errln("Failed to create the BreakIterator for Japanese locale in TestJapaneseWordBreak.\n");
+ return;
+ }
+
+ generalIteratorTest(*e, japaneseWordSelection);
+ delete e;
+}
+
+void RBBITest::TestTrieDict() {
+ UErrorCode status = U_ZERO_ERROR;
+
+ //
+ // Open and read the test data file.
+ //
+ const char *testDataDirectory = IntlTest::getSourceTestData(status);
+ char testFileName[1000];
+ if (testDataDirectory == NULL || strlen(testDataDirectory) + strlen("riwords.txt") + 10 >= sizeof(testFileName)) {
+ errln("Can't open test data. Path too long.");
+ return;
+ }
+ strcpy(testFileName, testDataDirectory);
+ strcat(testFileName, "riwords.txt");
+
+ // Items needing deleting at the end
+ MutableTrieDictionary *mutableDict = NULL;
+ CompactTrieDictionary *compactDict = NULL;
+ UnicodeSet *breaks = NULL;
+ UChar *testFile = NULL;
+ StringEnumeration *enumer1 = NULL;
+ StringEnumeration *enumer2 = NULL;
+ MutableTrieDictionary *mutable2 = NULL;
+ StringEnumeration *cloneEnum = NULL;
+ CompactTrieDictionary *compact2 = NULL;
+
+
+ const UnicodeString *originalWord = NULL;
+ const UnicodeString *cloneWord = NULL;
+ UChar *current;
+ UChar *word;
+ UChar uc;
+ int32_t wordLen;
+ int32_t wordCount;
+ int32_t testCount;
+
+ int len;
+ testFile = ReadAndConvertFile(testFileName, len, NULL, status);
+ if (U_FAILURE(status)) {
+ goto cleanup; /* something went wrong, error already output */
+ }
+
+ mutableDict = new MutableTrieDictionary(0x0E1C, status);
+ if (U_FAILURE(status)) {
+ errln("Error creating MutableTrieDictionary: %s\n", u_errorName(status));
+ goto cleanup;
+ }
+
+ breaks = new UnicodeSet;
+ breaks->add(0x000A); // Line Feed
+ breaks->add(0x000D); // Carriage Return
+ breaks->add(0x2028); // Line Separator
+ breaks->add(0x2029); // Paragraph Separator
+
+ // Now add each non-comment line of the file as a word.
+ current = testFile;
+ word = current;
+ uc = *current++;
+ wordLen = 0;
+ wordCount = 0;
+
+ while (uc) {
+ if (uc == 0x0023) { // #comment line, skip
+ while (uc && !breaks->contains(uc)) {
+ uc = *current++;
+ }
+ }
+ else while (uc && !breaks->contains(uc)) {
+ ++wordLen;
+ uc = *current++;
+ }
+ if (wordLen > 0) {
+ mutableDict->addWord(word, wordLen, status);
+ if (U_FAILURE(status)) {
+ errln("Could not add word to mutable dictionary; status %s\n", u_errorName(status));
+ goto cleanup;
+ }
+ wordCount += 1;
+ }
+
+ // Find beginning of next line
+ while (uc && breaks->contains(uc)) {
+ uc = *current++;
+ }
+ word = current-1;
+ wordLen = 0;
+ }
+
+ if (wordCount < 50) {
+ errln("Word count (%d) unreasonably small\n", wordCount);
+ goto cleanup;
+ }
+
+ enumer1 = mutableDict->openWords(status);
+ if (U_FAILURE(status)) {
+ errln("Could not open mutable dictionary enumerator: %s\n", u_errorName(status));
+ goto cleanup;
+ }
+
+ testCount = 0;
+ if (wordCount != (testCount = enumer1->count(status))) {
+ errln("MutableTrieDictionary word count (%d) differs from file word count (%d), with status %s\n",
+ testCount, wordCount, u_errorName(status));
+ goto cleanup;
+ }
+
+ // Now compact it
+ compactDict = new CompactTrieDictionary(*mutableDict, status);
+ if (U_FAILURE(status)) {
+ errln("Failed to create CompactTrieDictionary: %s\n", u_errorName(status));
+ goto cleanup;
+ }
+
+ enumer2 = compactDict->openWords(status);
+ if (U_FAILURE(status)) {
+ errln("Could not open compact trie dictionary enumerator: %s\n", u_errorName(status));
+ goto cleanup;
+ }
+
+ if (wordCount != (testCount = enumer2->count(status))) {
+ errln("CompactTrieDictionary word count (%d) differs from file word count (%d), with status %s\n",
+ testCount, wordCount, u_errorName(status));
+ goto cleanup;
+ }
+
+ if (enumer1->getDynamicClassID() == enumer2->getDynamicClassID()) {
+ errln("CompactTrieEnumeration and MutableTrieEnumeration ClassIDs are the same");
+ }
+ delete enumer1;
+ enumer1 = NULL;
+ delete enumer2;
+ enumer2 = NULL;
+
+ // Now un-compact it
+ mutable2 = compactDict->cloneMutable(status);
+ if (U_FAILURE(status)) {
+ errln("Could not clone CompactTrieDictionary to MutableTrieDictionary: %s\n", u_errorName(status));
+ goto cleanup;
+ }
+
+ cloneEnum = mutable2->openWords(status);
+ if (U_FAILURE(status)) {
+ errln("Could not create cloned mutable enumerator: %s\n", u_errorName(status));
+ goto cleanup;
+ }
+
+ if (wordCount != (testCount = cloneEnum->count(status))) {
+ errln("Cloned MutableTrieDictionary word count (%d) differs from file word count (%d), with status %s\n",
+ testCount, wordCount, u_errorName(status));
+ goto cleanup;
+ }
+
+ // Compact original dictionary to clone. Note that we can only compare the same kind of
+ // dictionary as the order of the enumerators is not guaranteed to be the same between
+ // different kinds
+ enumer1 = mutableDict->openWords(status);
+ if (U_FAILURE(status)) {
+ errln("Could not re-open mutable dictionary enumerator: %s\n", u_errorName(status));
+ goto cleanup;
+ }
+
+ originalWord = enumer1->snext(status);
+ cloneWord = cloneEnum->snext(status);
+ while (U_SUCCESS(status) && originalWord != NULL && cloneWord != NULL) {
+ if (*originalWord != *cloneWord) {
+ errln("Original and cloned MutableTrieDictionary word mismatch\n");
+ goto cleanup;
+ }
+ originalWord = enumer1->snext(status);
+ cloneWord = cloneEnum->snext(status);
+ }
+
+ if (U_FAILURE(status)) {
+ errln("Enumeration failed: %s\n", u_errorName(status));
+ goto cleanup;
+ }
+
+ if (originalWord != cloneWord) {
+ errln("Original and cloned MutableTrieDictionary ended enumeration at different points\n");
+ goto cleanup;
+ }
+
+ // Test the data copying constructor for CompactTrieDict, and the data access APIs.
+ compact2 = new CompactTrieDictionary(compactDict->data(), status);
+ if (U_FAILURE(status)) {
+ errln("CompactTrieDictionary(const void *,...) failed\n");
+ goto cleanup;
+ }
+
+ if (compact2->dataSize() == 0) {
+ errln("CompactTrieDictionary->dataSize() == 0\n");
+ goto cleanup;
+ }
+
+ // Now count the words via the second dictionary
+ delete enumer1;
+ enumer1 = compact2->openWords(status);
+ if (U_FAILURE(status)) {
+ errln("Could not open compact trie dictionary 2 enumerator: %s\n", u_errorName(status));
+ goto cleanup;
+ }
+
+ if (wordCount != (testCount = enumer1->count(status))) {
+ errln("CompactTrieDictionary 2 word count (%d) differs from file word count (%d), with status %s\n",
+ testCount, wordCount, u_errorName(status));
+ goto cleanup;
+ }
+
+cleanup:
+ delete compactDict;
+ delete mutableDict;
+ delete breaks;
+ delete[] testFile;
+ delete enumer1;
+ delete mutable2;
+ delete cloneEnum;
+ delete compact2;
+}
+
+
+//----------------------------------------------------------------------------
+//
+// generalIteratorTest Given a break iterator and a set of test data,
+// Run the tests and report the results.
+//
+//----------------------------------------------------------------------------
+void RBBITest::generalIteratorTest(RuleBasedBreakIterator& bi, BITestData &td)
+{
+
+ bi.setText(td.fDataToBreak);
+
+ testFirstAndNext(bi, td);
+
+ testLastAndPrevious(bi, td);
+
+ testFollowing(bi, td);
+ testPreceding(bi, td);
+ testIsBoundary(bi, td);
+ doMultipleSelectionTest(bi, td);
+}
+
+
+//
+// testFirstAndNext. Run the iterator forwards in the obvious first(), next()
+// kind of loop.
+//
+void RBBITest::testFirstAndNext(RuleBasedBreakIterator& bi, BITestData &td)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t p;
+ int32_t lastP = -1;
+ int32_t tag;
+
+ logln("Test first and next");
+ bi.setText(td.fDataToBreak);
+ td.clearResults();
+
+ for (p=bi.first(); p!=RuleBasedBreakIterator::DONE; p=bi.next()) {
+ td.fActualBreakPositions.addElement(p, status); // Save result.
+ tag = bi.getRuleStatus();
+ td.fActualTags.addElement(tag, status);
+ if (p <= lastP) {
+ // If the iterator is not making forward progress, stop.
+ // No need to raise an error here, it'll be detected in the normal check of results.
+ break;
+ }
+ lastP = p;
+ }
+ td.checkResults("testFirstAndNext", this);
+}
+
+
+//
+// TestLastAndPrevious. Run the iterator backwards, starting with last().
+//
+void RBBITest::testLastAndPrevious(RuleBasedBreakIterator& bi, BITestData &td)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t p;
+ int32_t lastP = 0x7ffffffe;
+ int32_t tag;
+
+ logln("Test first and next");
+ bi.setText(td.fDataToBreak);
+ td.clearResults();
+
+ for (p=bi.last(); p!=RuleBasedBreakIterator::DONE; p=bi.previous()) {
+ // Save break position. Insert it at start of vector of results, shoving
+ // already-saved results further towards the end.
+ td.fActualBreakPositions.insertElementAt(p, 0, status);
+ // bi.previous(); // TODO: Why does this fix things up????
+ // bi.next();
+ tag = bi.getRuleStatus();
+ td.fActualTags.insertElementAt(tag, 0, status);
+ if (p >= lastP) {
+ // If the iterator is not making progress, stop.
+ // No need to raise an error here, it'll be detected in the normal check of results.
+ break;
+ }
+ lastP = p;
+ }
+ td.checkResults("testLastAndPrevious", this);
+}
+
+
+void RBBITest::testFollowing(RuleBasedBreakIterator& bi, BITestData &td)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t p;
+ int32_t tag;
+ int32_t lastP = -2; // A value that will never be returned as a break position.
+ // cannot be -1; that is returned for DONE.
+ int i;
+
+ logln("testFollowing():");
+ bi.setText(td.fDataToBreak);
+ td.clearResults();
+
+ // Save the starting point, since we won't get that out of following.
+ p = bi.first();
+ td.fActualBreakPositions.addElement(p, status); // Save result.
+ tag = bi.getRuleStatus();
+ td.fActualTags.addElement(tag, status);
+
+ for (i = 0; i <= td.fDataToBreak.length()+1; i++) {
+ p = bi.following(i);
+ if (p != lastP) {
+ if (p == RuleBasedBreakIterator::DONE) {
+ break;
+ }
+ // We've reached a new break position. Save it.
+ td.fActualBreakPositions.addElement(p, status); // Save result.
+ tag = bi.getRuleStatus();
+ td.fActualTags.addElement(tag, status);
+ lastP = p;
+ }
+ }
+ // The loop normally exits by means of the break in the middle.
+ // Make sure that the index was at the correct position for the break iterator to have
+ // returned DONE.
+ if (i != td.fDataToBreak.length()) {
+ errln("testFollowing(): iterator returned DONE prematurely.");
+ }
+
+ // Full check of all results.
+ td.checkResults("testFollowing", this);
+}
+
+
+
+void RBBITest::testPreceding(RuleBasedBreakIterator& bi, BITestData &td) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t p;
+ int32_t tag;
+ int32_t lastP = 0x7ffffffe;
+ int i;
+
+ logln("testPreceding():");
+ bi.setText(td.fDataToBreak);
+ td.clearResults();
+
+ p = bi.last();
+ td.fActualBreakPositions.addElement(p, status);
+ tag = bi.getRuleStatus();
+ td.fActualTags.addElement(tag, status);
+
+ for (i = td.fDataToBreak.length(); i>=-1; i--) {
+ p = bi.preceding(i);
+ if (p != lastP) {
+ if (p == RuleBasedBreakIterator::DONE) {
+ break;
+ }
+ // We've reached a new break position. Save it.
+ td.fActualBreakPositions.insertElementAt(p, 0, status);
+ lastP = p;
+ tag = bi.getRuleStatus();
+ td.fActualTags.insertElementAt(tag, 0, status);
+ }
+ }
+ // The loop normally exits by means of the break in the middle.
+ // Make sure that the index was at the correct position for the break iterator to have
+ // returned DONE.
+ if (i != 0) {
+ errln("testPreceding(): iterator returned DONE prematurely.");
+ }
+
+ // Full check of all results.
+ td.checkResults("testPreceding", this);
+}
+
+
+
+void RBBITest::testIsBoundary(RuleBasedBreakIterator& bi, BITestData &td) {
+ UErrorCode status = U_ZERO_ERROR;
+ int i;
+ int32_t tag;
+
+ logln("testIsBoundary():");
+ bi.setText(td.fDataToBreak);
+ td.clearResults();
+
+ for (i = 0; i <= td.fDataToBreak.length(); i++) {
+ if (bi.isBoundary(i)) {
+ td.fActualBreakPositions.addElement(i, status); // Save result.
+ tag = bi.getRuleStatus();
+ td.fActualTags.addElement(tag, status);
+ }
+ }
+ td.checkResults("testIsBoundary: ", this);
+}
+
+
+
+void RBBITest::doMultipleSelectionTest(RuleBasedBreakIterator& iterator, BITestData &td)
+{
+ iterator.setText(td.fDataToBreak);
+
+ RuleBasedBreakIterator* testIterator =(RuleBasedBreakIterator*)iterator.clone();
+ int32_t offset = iterator.first();
+ int32_t testOffset;
+ int32_t count = 0;
+
+ logln("doMultipleSelectionTest text of length: %d", td.fDataToBreak.length());
+
+ if (*testIterator != iterator)
+ errln("clone() or operator!= failed: two clones compared unequal");
+
+ do {
+ testOffset = testIterator->first();
+ testOffset = testIterator->next(count);
+ if (offset != testOffset)
+ errln(UnicodeString("next(n) and next() not returning consistent results: for step ") + count + ", next(n) returned " + testOffset + " and next() had " + offset);
+
+ if (offset != RuleBasedBreakIterator::DONE) {
+ count++;
+ offset = iterator.next();
+
+ if (offset != RuleBasedBreakIterator::DONE && *testIterator == iterator) {
+ errln("operator== failed: Two unequal iterators compared equal. count=%d offset=%d", count, offset);
+ if (count > 10000 || offset == -1) {
+ errln("operator== failed too many times. Stopping test.");
+ if (offset == -1) {
+ errln("Does (RuleBasedBreakIterator::DONE == -1)?");
+ }
+ return;
+ }
+ }
+ }
+ } while (offset != RuleBasedBreakIterator::DONE);
+
+ // now do it backwards...
+ offset = iterator.last();
+ count = 0;
+
+ do {
+ testOffset = testIterator->last();
+ testOffset = testIterator->next(count); // next() with a negative arg is same as previous
+ if (offset != testOffset)
+ errln(UnicodeString("next(n) and next() not returning consistent results: for step ") + count + ", next(n) returned " + testOffset + " and next() had " + offset);
+
+ if (offset != RuleBasedBreakIterator::DONE) {
+ count--;
+ offset = iterator.previous();
+ }
+ } while (offset != RuleBasedBreakIterator::DONE);
+
+ delete testIterator;
+}
+
+
+//---------------------------------------------
+//
+// other tests
+//
+//---------------------------------------------
+void RBBITest::TestEmptyString()
+{
+ UnicodeString text = "";
+ UErrorCode status = U_ZERO_ERROR;
+
+ BITestData x(status);
+ ADD_DATACHUNK(x, "", 0, status); // Break at start of data
+ RuleBasedBreakIterator* bi = (RuleBasedBreakIterator *)BreakIterator::createLineInstance(Locale::getDefault(), status);
+ if (U_FAILURE(status))
+ {
+ errln("Failed to create the BreakIterator for default locale in TestEmptyString.\n");
+ return;
+ }
+ generalIteratorTest(*bi, x);
+ delete bi;
+}
+
+void RBBITest::TestGetAvailableLocales()
+{
+ int32_t locCount = 0;
+ const Locale* locList = BreakIterator::getAvailableLocales(locCount);
+
+ if (locCount == 0)
+ errln("getAvailableLocales() returned an empty list!");
+ // Just make sure that it's returning good memory.
+ int32_t i;
+ for (i = 0; i < locCount; ++i) {
+ logln(locList[i].getName());
+ }
+}
+
+//Testing the BreakIterator::getDisplayName() function
+void RBBITest::TestGetDisplayName()
+{
+ UnicodeString result;
+
+ BreakIterator::getDisplayName(Locale::getUS(), result);
+ if (Locale::getDefault() == Locale::getUS() && result != "English (United States)")
+ errln("BreakIterator::getDisplayName() failed: expected \"English (United States)\", got \""
+ + result);
+
+ BreakIterator::getDisplayName(Locale::getFrance(), Locale::getUS(), result);
+ if (result != "French (France)")
+ errln("BreakIterator::getDisplayName() failed: expected \"French (France)\", got \""
+ + result);
+}
+/**
+ * Test End Behaviour
+ * @bug 4068137
+ */
+void RBBITest::TestEndBehaviour()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString testString("boo.");
+ BreakIterator *wb = BreakIterator::createWordInstance(Locale::getDefault(), status);
+ if (U_FAILURE(status))
+ {
+ errln("Failed to create the BreakIterator for default locale in TestEndBehaviour.\n");
+ return;
+ }
+ wb->setText(testString);
+
+ if (wb->first() != 0)
+ errln("Didn't get break at beginning of string.");
+ if (wb->next() != 3)
+ errln("Didn't get break before period in \"boo.\"");
+ if (wb->current() != 4 && wb->next() != 4)
+ errln("Didn't get break at end of string.");
+ delete wb;
+}
+/*
+ * @bug 4153072
+ */
+void RBBITest::TestBug4153072() {
+ UErrorCode status = U_ZERO_ERROR;
+ BreakIterator *iter = BreakIterator::createWordInstance(Locale::getDefault(), status);
+ if (U_FAILURE(status))
+ {
+ errln("Failed to create the BreakIterator for default locale in TestBug4153072\n");
+ return;
+ }
+ UnicodeString str("...Hello, World!...");
+ int32_t begin = 3;
+ int32_t end = str.length() - 3;
+ UBool onBoundary;
+
+ StringCharacterIterator* textIterator = new StringCharacterIterator(str, begin, end, begin);
+ iter->adoptText(textIterator);
+ int index;
+ // Note: with the switch to UText, there is no way to restrict the
+ // iteration range to begin at an index other than zero.
+ // String character iterators created with a non-zero bound are
+ // treated by RBBI as being empty.
+ for (index = -1; index < begin + 1; ++index) {
+ onBoundary = iter->isBoundary(index);
+ if (index == 0? !onBoundary : onBoundary) {
+ errln((UnicodeString)"Didn't handle isBoundary correctly with offset = " + index +
+ " and begin index = " + begin);
+ }
+ }
+ delete iter;
+}
+
+
+//
+// Test for problem reported by Ashok Matoria on 9 July 2007
+// One.<kSoftHyphen><kSpace>Two.
+//
+// Sentence break at start (0) and then on calling next() it breaks at
+// ‘T’ of “Two”. Now, at this point if I do next() and
+// then previous(), it breaks at <kSOftHyphen> instead of ‘T’ of Two.
+//
+void RBBITest::TestBug5775() {
+ UErrorCode status = U_ZERO_ERROR;
+ BreakIterator *bi = BreakIterator::createSentenceInstance(Locale::getEnglish(), status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(bi != NULL);
+
+ if (U_FAILURE(status) || bi == NULL) {
+ // TEST_ASSERT already printed error message.
+ return;
+ }
+
+ UnicodeString s("One.\\u00ad Two.");
+ // 01234 56789
+ s = s.unescape();
+ bi->setText(s);
+ int pos = bi->next();
+ TEST_ASSERT(pos == 6);
+ pos = bi->next();
+ TEST_ASSERT(pos == 10);
+ pos = bi->previous();
+ TEST_ASSERT(pos == 6);
+ delete bi;
+}
+
+
+
+/**
+ * Test Japanese Line Break
+ * @bug 4095322
+ */
+void RBBITest::TestJapaneseLineBreak()
+{
+#if 0
+ // Test needs updating some more... Dump it for now.
+
+
+ // Change for Unicode TR 14: Punctuation characters with categories Pi and Pf do not count
+ // as opening and closing punctuation for line breaking.
+ // Also, \u30fc and \u30fe are not counted as hyphens. Remove these chars
+ // from these tests. 6-13-2002
+ //
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString testString = CharsToUnicodeString("\\u4e00x\\u4e8c");
+ UnicodeString precedingChars = CharsToUnicodeString(
+ //"([{\\u00ab$\\u00a5\\u00a3\\u00a4\\u2018\\u201a\\u201c\\u201e\\u201b\\u201f");
+ "([{$\\u00a5\\u00a3\\u00a4\\u201a\\u201e");
+ UnicodeString followingChars = CharsToUnicodeString(
+ // ")]}\\u00bb!%,.\\u3001\\u3002\\u3063\\u3083\\u3085\\u3087\\u30c3\\u30e3\\u30e5\\u30e7\\u30fc"
+ ")]}!%,.\\u3001\\u3002\\u3063\\u3083\\u3085\\u3087\\u30c3\\u30e3\\u30e5\\u30e7"
+ // ":;\\u309b\\u309c\\u3005\\u309d\\u309e\\u30fd\\u30fe\\u2019\\u201d\\u00b0\\u2032\\u2033\\u2034"
+ ":;\\u309b\\u309c\\u3005\\u309d\\u309e\\u30fd\\u00b0\\u2032\\u2033\\u2034"
+ "\\u2030\\u2031\\u2103\\u2109\\u00a2\\u0300\\u0301\\u0302");
+ BreakIterator *iter = BreakIterator::createLineInstance(Locale::getJapan(), status);
+
+ int32_t i;
+ if (U_FAILURE(status))
+ {
+ errln("Failed to create the BreakIterator for Japanese locale in TestJapaneseLineBreak.\n");
+ return;
+ }
+
+ for (i = 0; i < precedingChars.length(); i++) {
+ testString.setCharAt(1, precedingChars[i]);
+ iter->setText(testString);
+ int32_t j = iter->first();
+ if (j != 0)
+ errln("ja line break failure: failed to start at 0");
+ j = iter->next();
+ if (j != 1)
+ errln("ja line break failure: failed to stop before '" + UCharToUnicodeString(precedingChars[i])
+ + "' (" + ((int)(precedingChars[i])) + ")");
+ j = iter->next();
+ if (j != 3)
+ errln("ja line break failure: failed to skip position after '" + UCharToUnicodeString(precedingChars[i])
+ + "' (" + ((int)(precedingChars[i])) + ")");
+ }
+
+ for (i = 0; i < followingChars.length(); i++) {
+ testString.setCharAt(1, followingChars[i]);
+ iter->setText(testString);
+ int j = iter->first();
+ if (j != 0)
+ errln("ja line break failure: failed to start at 0");
+ j = iter->next();
+ if (j != 2)
+ errln("ja line break failure: failed to skip position before '" + UCharToUnicodeString(followingChars[i])
+ + "' (" + ((int)(followingChars[i])) + ")");
+ j = iter->next();
+ if (j != 3)
+ errln("ja line break failure: failed to stop after '" + UCharToUnicodeString(followingChars[i])
+ + "' (" + ((int)(followingChars[i])) + ")");
+ }
+ delete iter;
+#endif
+}
+
+
+//------------------------------------------------------------------------------
+//
+// RBBITest::Extended Run RBBI Tests from an external test data file
+//
+//------------------------------------------------------------------------------
+
+struct TestParams {
+ BreakIterator *bi;
+ UnicodeString dataToBreak;
+ UVector32 *expectedBreaks;
+ UVector32 *srcLine;
+ UVector32 *srcCol;
+};
+
+void RBBITest::executeTest(TestParams *t) {
+ int32_t bp;
+ int32_t prevBP;
+ int32_t i;
+
+ if (t->bi == NULL) {
+ return;
+ }
+
+ t->bi->setText(t->dataToBreak);
+ //
+ // Run the iterator forward
+ //
+ prevBP = -1;
+ for (bp = t->bi->first(); bp != BreakIterator::DONE; bp = t->bi->next()) {
+ if (prevBP == bp) {
+ // Fail for lack of forward progress.
+ errln("Forward Iteration, no forward progress. Break Pos=%4d File line,col=%4d,%4d",
+ bp, t->srcLine->elementAti(bp), t->srcCol->elementAti(bp));
+ break;
+ }
+
+ // Check that there were we didn't miss an expected break between the last one
+ // and this one.
+ for (i=prevBP+1; i<bp; i++) {
+ if (t->expectedBreaks->elementAti(i) != 0) {
+ int expected[] = {0, i};
+ printStringBreaks(t->dataToBreak, expected, 2);
+ errln("Forward Iteration, break expected, but not found. Pos=%4d File line,col= %4d,%4d",
+ i, t->srcLine->elementAti(i), t->srcCol->elementAti(i));
+ }
+ }
+
+ // Check that the break we did find was expected
+ if (t->expectedBreaks->elementAti(bp) == 0) {
+ int expected[] = {0, bp};
+ printStringBreaks(t->dataToBreak, expected, 2);
+ errln("Forward Iteration, break found, but not expected. Pos=%4d File line,col= %4d,%4d",
+ bp, t->srcLine->elementAti(bp), t->srcCol->elementAti(bp));
+ } else {
+ // The break was expected.
+ // Check that the {nnn} tag value is correct.
+ int32_t expectedTagVal = t->expectedBreaks->elementAti(bp);
+ if (expectedTagVal == -1) {
+ expectedTagVal = 0;
+ }
+ int32_t line = t->srcLine->elementAti(bp);
+ int32_t rs = ((RuleBasedBreakIterator *)t->bi)->getRuleStatus();
+ if (rs != expectedTagVal) {
+ errln("Incorrect status for forward break. Pos=%4d File line,col= %4d,%4d.\n"
+ " Actual, Expected status = %4d, %4d",
+ bp, line, t->srcCol->elementAti(bp), rs, expectedTagVal);
+ }
+ }
+
+
+ prevBP = bp;
+ }
+
+ // Verify that there were no missed expected breaks after the last one found
+ for (i=prevBP+1; i<t->expectedBreaks->size(); i++) {
+ if (t->expectedBreaks->elementAti(i) != 0) {
+ errln("Forward Iteration, break expected, but not found. Pos=%4d File line,col= %4d,%4d",
+ i, t->srcLine->elementAti(i), t->srcCol->elementAti(i));
+ }
+ }
+
+ //
+ // Run the iterator backwards, verify that the same breaks are found.
+ //
+ prevBP = t->dataToBreak.length()+2; // start with a phony value for the last break pos seen.
+ for (bp = t->bi->last(); bp != BreakIterator::DONE; bp = t->bi->previous()) {
+ if (prevBP == bp) {
+ // Fail for lack of progress.
+ errln("Reverse Iteration, no progress. Break Pos=%4d File line,col=%4d,%4d",
+ bp, t->srcLine->elementAti(bp), t->srcCol->elementAti(bp));
+ break;
+ }
+
+ // Check that there were we didn't miss an expected break between the last one
+ // and this one. (UVector returns zeros for index out of bounds.)
+ for (i=prevBP-1; i>bp; i--) {
+ if (t->expectedBreaks->elementAti(i) != 0) {
+ errln("Reverse Itertion, break expected, but not found. Pos=%4d File line,col= %4d,%4d",
+ i, t->srcLine->elementAti(i), t->srcCol->elementAti(i));
+ }
+ }
+
+ // Check that the break we did find was expected
+ if (t->expectedBreaks->elementAti(bp) == 0) {
+ errln("Reverse Itertion, break found, but not expected. Pos=%4d File line,col= %4d,%4d",
+ bp, t->srcLine->elementAti(bp), t->srcCol->elementAti(bp));
+ } else {
+ // The break was expected.
+ // Check that the {nnn} tag value is correct.
+ int32_t expectedTagVal = t->expectedBreaks->elementAti(bp);
+ if (expectedTagVal == -1) {
+ expectedTagVal = 0;
+ }
+ int line = t->srcLine->elementAti(bp);
+ int32_t rs = ((RuleBasedBreakIterator *)t->bi)->getRuleStatus();
+ if (rs != expectedTagVal) {
+ errln("Incorrect status for reverse break. Pos=%4d File line,col= %4d,%4d.\n"
+ " Actual, Expected status = %4d, %4d",
+ bp, line, t->srcCol->elementAti(bp), rs, expectedTagVal);
+ }
+ }
+
+ prevBP = bp;
+ }
+
+ // Verify that there were no missed breaks prior to the last one found
+ for (i=prevBP-1; i>=0; i--) {
+ if (t->expectedBreaks->elementAti(i) != 0) {
+ errln("Forward Itertion, break expected, but not found. Pos=%4d File line,col= %4d,%4d",
+ i, t->srcLine->elementAti(i), t->srcCol->elementAti(i));
+ }
+ }
+}
+
+
+void RBBITest::TestExtended() {
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+ UErrorCode status = U_ZERO_ERROR;
+ Locale locale("");
+
+ UnicodeString rules;
+ TestParams tp;
+ tp.bi = NULL;
+ tp.expectedBreaks = new UVector32(status);
+ tp.srcLine = new UVector32(status);
+ tp.srcCol = new UVector32(status);
+
+ RegexMatcher localeMatcher("<locale *([\\p{L}\\p{Nd}_]*) *>", 0, status);
+ TEST_ASSERT_SUCCESS(status);
+
+
+ //
+ // Open and read the test data file.
+ //
+ const char *testDataDirectory = IntlTest::getSourceTestData(status);
+ char testFileName[1000];
+ if (testDataDirectory == NULL || strlen(testDataDirectory) >= sizeof(testFileName)) {
+ errln("Can't open test data. Path too long.");
+ return;
+ }
+ strcpy(testFileName, testDataDirectory);
+ strcat(testFileName, "rbbitst.txt");
+
+ int len;
+ UChar *testFile = ReadAndConvertFile(testFileName, len, "UTF-8", status);
+ if (U_FAILURE(status)) {
+ return; /* something went wrong, error already output */
+ }
+
+
+
+
+ //
+ // Put the test data into a UnicodeString
+ //
+ UnicodeString testString(FALSE, testFile, len);
+
+ enum EParseState{
+ PARSE_COMMENT,
+ PARSE_TAG,
+ PARSE_DATA,
+ PARSE_NUM
+ }
+ parseState = PARSE_TAG;
+
+ EParseState savedState = PARSE_TAG;
+
+ static const UChar CH_LF = 0x0a;
+ static const UChar CH_CR = 0x0d;
+ static const UChar CH_HASH = 0x23;
+ /*static const UChar CH_PERIOD = 0x2e;*/
+ static const UChar CH_LT = 0x3c;
+ static const UChar CH_GT = 0x3e;
+ static const UChar CH_BACKSLASH = 0x5c;
+ static const UChar CH_BULLET = 0x2022;
+
+ int32_t lineNum = 1;
+ int32_t colStart = 0;
+ int32_t column = 0;
+ int32_t charIdx = 0;
+
+ int32_t tagValue = 0; // The numeric value of a <nnn> tag.
+
+ for (charIdx = 0; charIdx < len; ) {
+ status = U_ZERO_ERROR;
+ UChar c = testString.charAt(charIdx);
+ charIdx++;
+ if (c == CH_CR && charIdx<len && testString.charAt(charIdx) == CH_LF) {
+ // treat CRLF as a unit
+ c = CH_LF;
+ charIdx++;
+ }
+ if (c == CH_LF || c == CH_CR) {
+ lineNum++;
+ colStart = charIdx;
+ }
+ column = charIdx - colStart + 1;
+
+ switch (parseState) {
+ case PARSE_COMMENT:
+ if (c == 0x0a || c == 0x0d) {
+ parseState = savedState;
+ }
+ break;
+
+ case PARSE_TAG:
+ {
+ if (c == CH_HASH) {
+ parseState = PARSE_COMMENT;
+ savedState = PARSE_TAG;
+ break;
+ }
+ if (u_isUWhiteSpace(c)) {
+ break;
+ }
+ if (testString.compare(charIdx-1, 6, "<word>") == 0) {
+ delete tp.bi;
+ tp.bi = BreakIterator::createWordInstance(locale, status);
+ charIdx += 5;
+ break;
+ }
+ if (testString.compare(charIdx-1, 6, "<char>") == 0) {
+ delete tp.bi;
+ tp.bi = BreakIterator::createCharacterInstance(locale, status);
+ charIdx += 5;
+ break;
+ }
+ if (testString.compare(charIdx-1, 6, "<line>") == 0) {
+ delete tp.bi;
+ tp.bi = BreakIterator::createLineInstance(locale, status);
+ charIdx += 5;
+ break;
+ }
+ if (testString.compare(charIdx-1, 6, "<sent>") == 0) {
+ delete tp.bi;
+ tp.bi = NULL;
+ tp.bi = BreakIterator::createSentenceInstance(locale, status);
+ charIdx += 5;
+ break;
+ }
+ if (testString.compare(charIdx-1, 7, "<title>") == 0) {
+ delete tp.bi;
+ tp.bi = BreakIterator::createTitleInstance(locale, status);
+ charIdx += 6;
+ break;
+ }
+
+ // <locale loc_name>
+ localeMatcher.reset(testString);
+ if (localeMatcher.lookingAt(charIdx-1, status)) {
+ UnicodeString localeName = localeMatcher.group(1, status);
+ char localeName8[100];
+ localeName.extract(0, localeName.length(), localeName8, sizeof(localeName8), 0);
+ locale = Locale::createFromName(localeName8);
+ charIdx += localeMatcher.group(0, status).length();
+ TEST_ASSERT_SUCCESS(status);
+ break;
+ }
+ if (testString.compare(charIdx-1, 6, "<data>") == 0) {
+ parseState = PARSE_DATA;
+ charIdx += 5;
+ tp.dataToBreak = "";
+ tp.expectedBreaks->removeAllElements();
+ tp.srcCol ->removeAllElements();
+ tp.srcLine->removeAllElements();
+ break;
+ }
+
+ errln("line %d: Tag expected in test file.", lineNum);
+ parseState = PARSE_COMMENT;
+ savedState = PARSE_DATA;
+ goto end_test; // Stop the test.
+ }
+ break;
+
+ case PARSE_DATA:
+ if (c == CH_BULLET) {
+ int32_t breakIdx = tp.dataToBreak.length();
+ tp.expectedBreaks->setSize(breakIdx+1);
+ tp.expectedBreaks->setElementAt(-1, breakIdx);
+ tp.srcLine->setSize(breakIdx+1);
+ tp.srcLine->setElementAt(lineNum, breakIdx);
+ tp.srcCol ->setSize(breakIdx+1);
+ tp.srcCol ->setElementAt(column, breakIdx);
+ break;
+ }
+
+ if (testString.compare(charIdx-1, 7, "</data>") == 0) {
+ // Add final entry to mappings from break location to source file position.
+ // Need one extra because last break position returned is after the
+ // last char in the data, not at the last char.
+ tp.srcLine->addElement(lineNum, status);
+ tp.srcCol ->addElement(column, status);
+
+ parseState = PARSE_TAG;
+ charIdx += 6;
+
+ // RUN THE TEST!
+ executeTest(&tp);
+ break;
+ }
+
+ if (testString.compare(charIdx-1, 3, "\\N{") == 0) {
+ // Named character, e.g. \N{COMBINING GRAVE ACCENT}
+ // Get the code point from the name and insert it into the test data.
+ // (Damn, no API takes names in Unicode !!!
+ // we've got to take it back to char *)
+ int32_t nameEndIdx = testString.indexOf((UChar)0x7d/*'}'*/, charIdx);
+ int32_t nameLength = nameEndIdx - (charIdx+2);
+ char charNameBuf[200];
+ UChar32 theChar = -1;
+ if (nameEndIdx != -1) {
+ UErrorCode status = U_ZERO_ERROR;
+ testString.extract(charIdx+2, nameLength, charNameBuf, sizeof(charNameBuf));
+ charNameBuf[sizeof(charNameBuf)-1] = 0;
+ theChar = u_charFromName(U_UNICODE_CHAR_NAME, charNameBuf, &status);
+ if (U_FAILURE(status)) {
+ theChar = -1;
+ }
+ }
+ if (theChar == -1) {
+ errln("Error in named character in test file at line %d, col %d",
+ lineNum, column);
+ } else {
+ // Named code point was recognized. Insert it
+ // into the test data.
+ tp.dataToBreak.append(theChar);
+ while (tp.dataToBreak.length() > tp.srcLine->size()) {
+ tp.srcLine->addElement(lineNum, status);
+ tp.srcCol ->addElement(column, status);
+ }
+ }
+ if (nameEndIdx > charIdx) {
+ charIdx = nameEndIdx+1;
+
+ }
+ break;
+ }
+
+
+
+
+ if (testString.compare(charIdx-1, 2, "<>") == 0) {
+ charIdx++;
+ int32_t breakIdx = tp.dataToBreak.length();
+ tp.expectedBreaks->setSize(breakIdx+1);
+ tp.expectedBreaks->setElementAt(-1, breakIdx);
+ tp.srcLine->setSize(breakIdx+1);
+ tp.srcLine->setElementAt(lineNum, breakIdx);
+ tp.srcCol ->setSize(breakIdx+1);
+ tp.srcCol ->setElementAt(column, breakIdx);
+ break;
+ }
+
+ if (c == CH_LT) {
+ tagValue = 0;
+ parseState = PARSE_NUM;
+ break;
+ }
+
+ if (c == CH_HASH && column==3) { // TODO: why is column off so far?
+ parseState = PARSE_COMMENT;
+ savedState = PARSE_DATA;
+ break;
+ }
+
+ if (c == CH_BACKSLASH) {
+ // Check for \ at end of line, a line continuation.
+ // Advance over (discard) the newline
+ UChar32 cp = testString.char32At(charIdx);
+ if (cp == CH_CR && charIdx<len && testString.charAt(charIdx+1) == CH_LF) {
+ // We have a CR LF
+ // Need an extra increment of the input ptr to move over both of them
+ charIdx++;
+ }
+ if (cp == CH_LF || cp == CH_CR) {
+ lineNum++;
+ colStart = charIdx;
+ charIdx++;
+ break;
+ }
+
+ // Let unescape handle the back slash.
+ cp = testString.unescapeAt(charIdx);
+ if (cp != -1) {
+ // Escape sequence was recognized. Insert the char
+ // into the test data.
+ tp.dataToBreak.append(cp);
+ while (tp.dataToBreak.length() > tp.srcLine->size()) {
+ tp.srcLine->addElement(lineNum, status);
+ tp.srcCol ->addElement(column, status);
+ }
+ break;
+ }
+
+
+ // Not a recognized backslash escape sequence.
+ // Take the next char as a literal.
+ // TODO: Should this be an error?
+ c = testString.charAt(charIdx);
+ charIdx = testString.moveIndex32(charIdx, 1);
+ }
+
+ // Normal, non-escaped data char.
+ tp.dataToBreak.append(c);
+
+ // Save the mapping from offset in the data to line/column numbers in
+ // the original input file. Will be used for better error messages only.
+ // If there's an expected break before this char, the slot in the mapping
+ // vector will already be set for this char; don't overwrite it.
+ if (tp.dataToBreak.length() > tp.srcLine->size()) {
+ tp.srcLine->addElement(lineNum, status);
+ tp.srcCol ->addElement(column, status);
+ }
+ break;
+
+
+ case PARSE_NUM:
+ // We are parsing an expected numeric tag value, like <1234>,
+ // within a chunk of data.
+ if (u_isUWhiteSpace(c)) {
+ break;
+ }
+
+ if (c == CH_GT) {
+ // Finished the number. Add the info to the expected break data,
+ // and switch parse state back to doing plain data.
+ parseState = PARSE_DATA;
+ if (tagValue == 0) {
+ tagValue = -1;
+ }
+ int32_t breakIdx = tp.dataToBreak.length();
+ tp.expectedBreaks->setSize(breakIdx+1);
+ tp.expectedBreaks->setElementAt(tagValue, breakIdx);
+ tp.srcLine->setSize(breakIdx+1);
+ tp.srcLine->setElementAt(lineNum, breakIdx);
+ tp.srcCol ->setSize(breakIdx+1);
+ tp.srcCol ->setElementAt(column, breakIdx);
+ break;
+ }
+
+ if (u_isdigit(c)) {
+ tagValue = tagValue*10 + u_charDigitValue(c);
+ break;
+ }
+
+ errln("Syntax Error in test file at line %d, col %d",
+ lineNum, column);
+ parseState = PARSE_COMMENT;
+ goto end_test; // Stop the test
+ break;
+ }
+
+
+ if (U_FAILURE(status)) {
+ errln("ICU Error %s while parsing test file at line %d.",
+ u_errorName(status), lineNum);
+ status = U_ZERO_ERROR;
+ goto end_test; // Stop the test
+ }
+
+ }
+
+end_test:
+ delete tp.bi;
+ delete tp.expectedBreaks;
+ delete tp.srcLine;
+ delete tp.srcCol;
+ delete [] testFile;
+#endif
+}
+
+
+//-------------------------------------------------------------------------------
+//
+// ReadAndConvertFile Read a text data file, convert it to UChars, and
+// return the datain one big UChar * buffer, which the caller must delete.
+//
+// parameters:
+// fileName: the name of the file, with no directory part. The test data directory
+// is assumed.
+// ulen an out parameter, receives the actual length (in UChars) of the file data.
+// encoding The file encoding. If the file contains a BOM, that will override the encoding
+// specified here. The BOM, if it exists, will be stripped from the returned data.
+// Pass NULL for the system default encoding.
+// status
+// returns:
+// The file data, converted to UChar.
+// The caller must delete this when done with
+// delete [] theBuffer;
+//
+// TODO: This is a clone of RegexTest::ReadAndConvertFile.
+// Move this function to some common place.
+//
+//--------------------------------------------------------------------------------
+UChar *RBBITest::ReadAndConvertFile(const char *fileName, int &ulen, const char *encoding, UErrorCode &status) {
+ UChar *retPtr = NULL;
+ char *fileBuf = NULL;
+ UConverter* conv = NULL;
+ FILE *f = NULL;
+
+ ulen = 0;
+ if (U_FAILURE(status)) {
+ return retPtr;
+ }
+
+ //
+ // Open the file.
+ //
+ f = fopen(fileName, "rb");
+ if (f == 0) {
+ errln("Error opening test data file %s\n", fileName);
+ status = U_FILE_ACCESS_ERROR;
+ return NULL;
+ }
+ //
+ // Read it in
+ //
+ int fileSize;
+ int amt_read;
+
+ fseek( f, 0, SEEK_END);
+ fileSize = ftell(f);
+ fileBuf = new char[fileSize];
+ fseek(f, 0, SEEK_SET);
+ amt_read = fread(fileBuf, 1, fileSize, f);
+ if (amt_read != fileSize || fileSize <= 0) {
+ errln("Error reading test data file.");
+ goto cleanUpAndReturn;
+ }
+
+ //
+ // Look for a Unicode Signature (BOM) on the data just read
+ //
+ int32_t signatureLength;
+ const char * fileBufC;
+ const char* bomEncoding;
+
+ fileBufC = fileBuf;
+ bomEncoding = ucnv_detectUnicodeSignature(
+ fileBuf, fileSize, &signatureLength, &status);
+ if(bomEncoding!=NULL ){
+ fileBufC += signatureLength;
+ fileSize -= signatureLength;
+ encoding = bomEncoding;
+ }
+
+ //
+ // Open a converter to take the rule file to UTF-16
+ //
+ conv = ucnv_open(encoding, &status);
+ if (U_FAILURE(status)) {
+ goto cleanUpAndReturn;
+ }
+
+ //
+ // Convert the rules to UChar.
+ // Preflight first to determine required buffer size.
+ //
+ ulen = ucnv_toUChars(conv,
+ NULL, // dest,
+ 0, // destCapacity,
+ fileBufC,
+ fileSize,
+ &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ // Buffer Overflow is expected from the preflight operation.
+ status = U_ZERO_ERROR;
+
+ retPtr = new UChar[ulen+1];
+ ucnv_toUChars(conv,
+ retPtr, // dest,
+ ulen+1,
+ fileBufC,
+ fileSize,
+ &status);
+ }
+
+cleanUpAndReturn:
+ fclose(f);
+ delete []fileBuf;
+ ucnv_close(conv);
+ if (U_FAILURE(status)) {
+ errln("ucnv_toUChars: ICU Error \"%s\"\n", u_errorName(status));
+ delete retPtr;
+ retPtr = 0;
+ ulen = 0;
+ };
+ return retPtr;
+}
+
+
+
+//--------------------------------------------------------------------------------------------
+//
+// Run tests from each of the boundary test data files distributed by the Unicode Consortium
+//
+//-------------------------------------------------------------------------------------------
+void RBBITest::TestUnicodeFiles() {
+ RuleBasedBreakIterator *bi;
+ UErrorCode status = U_ZERO_ERROR;
+
+ bi = (RuleBasedBreakIterator *)BreakIterator::createCharacterInstance(Locale::getDefault(), status);
+ TEST_ASSERT_SUCCESS(status);
+ if (U_SUCCESS(status)) {
+ runUnicodeTestData("GraphemeBreakTest.txt", bi);
+ }
+ delete bi;
+
+ bi = (RuleBasedBreakIterator *)BreakIterator::createWordInstance(Locale::getDefault(), status);
+ TEST_ASSERT_SUCCESS(status);
+ if (U_SUCCESS(status)) {
+ runUnicodeTestData("WordBreakTest.txt", bi);
+ }
+ delete bi;
+
+ bi = (RuleBasedBreakIterator *)BreakIterator::createSentenceInstance(Locale::getDefault(), status);
+ TEST_ASSERT_SUCCESS(status);
+ if (U_SUCCESS(status)) {
+ runUnicodeTestData("SentenceBreakTest.txt", bi);
+ }
+ delete bi;
+
+ #if 0
+ bi = (RuleBasedBreakIterator *)BreakIterator::createCharInstance(Locale::getDefault(), status);
+ TEST_ASSERT_SUCCESS(status);
+ if (U_SUCCESS(status)) {
+ runUnicodeTestData("LBTest.txt", bi);
+ }
+ delete bi;
+ #endif
+
+}
+
+
+//--------------------------------------------------------------------------------------------
+//
+// Run tests from one of the boundary test data files distributed by the Unicode Consortium
+//
+//-------------------------------------------------------------------------------------------
+void RBBITest::runUnicodeTestData(const char *fileName, RuleBasedBreakIterator *bi) {
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+ UErrorCode status = U_ZERO_ERROR;
+
+ //
+ // Open and read the test data file, put it into a UnicodeString.
+ //
+ const char *testDataDirectory = IntlTest::getSourceTestData(status);
+ char testFileName[1000];
+ if (testDataDirectory == NULL || strlen(testDataDirectory) >= sizeof(testFileName)) {
+ errln("Can't open test data. Path too long.");
+ return;
+ }
+ strcpy(testFileName, testDataDirectory);
+ strcat(testFileName, fileName);
+
+ int len;
+ UChar *testFile = ReadAndConvertFile(testFileName, len, "UTF-8", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(testFile != NULL);
+ if (U_FAILURE(status) || testFile == NULL) {
+ return; /* something went wrong, error already output */
+ }
+ UnicodeString testFileAsString(TRUE, testFile, len);
+
+ //
+ // Parse the test data file using a regular expression.
+ // Each kind of token is recognized in its own capture group; what type of item was scanned
+ // is identified by which group had a match.
+ //
+ // Caputure Group # 1 2 3 4 5
+ // Parses this item: divide x hex digits comment & nl unrecognized
+ //
+ UnicodeString tokenExpr = "(?ms)\\s*(?:(\\u00F7)|(\\u00D7)|([0-9a-fA-F]+)|(#.*?$.)|(.*?$.))";
+ RegexMatcher tokenMatcher(tokenExpr, testFileAsString, 0, status);
+ UnicodeString testString;
+ UVector32 breakPositions(status);
+ int lineNumber = 1;
+ int charIndex = 0;
+ TEST_ASSERT_SUCCESS(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ //
+ // Scan through each test case, building up the string to be broken in testString,
+ // and the positions that should be boundaries in the breakPositions vector.
+ //
+ while (tokenMatcher.lookingAt(charIndex, status)) {
+ if (tokenMatcher.start(1, status) >= 0) {
+ // Scanned a divide sign, indicating a break position in the test data.
+ if (testString.length()>0) {
+ breakPositions.addElement(testString.length(), status);
+ }
+ }
+ else if (tokenMatcher.start(2, status) >= 0) {
+ // Scanned an 'x', meaning no break at this position in the test data
+ // Nothing to be done here.
+ }
+ else if (tokenMatcher.start(3, status) >= 0) {
+ // Scanned Hex digits. Convert them to binary, append to the character data string.
+ const UnicodeString &hexNumber = tokenMatcher.group(3, status);
+ int length = hexNumber.length();
+ if (length<=8) {
+ char buf[10];
+ hexNumber.extract (0, length, buf, sizeof(buf), US_INV);
+ UChar32 c = (UChar32)strtol(buf, NULL, 16);
+ if (c<=0x10ffff) {
+ testString.append(c);
+ } else {
+ errln("Error: Unicode Character value out of range. \'%s\', line %d.\n",
+ fileName, lineNumber);
+ }
+ } else {
+ errln("Syntax Error: Hex Unicode Character value must have no more than 8 digits at \'%s\', line %d.\n",
+ fileName, lineNumber);
+ }
+ }
+ else if (tokenMatcher.start(4, status) >= 0) {
+ // Scanned to end of a line, possibly skipping over a comment in the process.
+ // If the line from the file contained test data, run the test now.
+ //
+ if (testString.length() > 0) {
+ checkUnicodeTestCase(fileName, lineNumber, testString, &breakPositions, bi);
+ }
+
+ // Clear out this test case.
+ // The string and breakPositions vector will be refilled as the next
+ // test case is parsed.
+ testString.remove();
+ breakPositions.setSize(0);
+ lineNumber++;
+ } else {
+ // Scanner catchall. Something unrecognized appeared on the line.
+ char token[16];
+ UnicodeString uToken = tokenMatcher.group(0, status);
+ uToken.extract(0, uToken.length(), token, (uint32_t)sizeof(token));
+ token[sizeof(token)-1] = 0;
+ errln("Syntax error in test data file \'%s\', line %d. Scanning \"%s\"\n", fileName, lineNumber, token);
+
+ // Clean up, in preparation for continuing with the next line.
+ testString.remove();
+ breakPositions.setSize(0);
+ lineNumber++;
+ }
+ TEST_ASSERT_SUCCESS(status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ charIndex = tokenMatcher.end(status);
+ }
+
+ delete [] testFile;
+ #endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+}
+
+//--------------------------------------------------------------------------------------------
+//
+// checkUnicodeTestCase() Run one test case from one of the Unicode Consortium
+// test data files. Do only a simple, forward-only check -
+// this test is mostly to check that ICU and the Unicode
+// data agree with each other.
+//
+//--------------------------------------------------------------------------------------------
+void RBBITest::checkUnicodeTestCase(const char *testFileName, int lineNumber,
+ const UnicodeString &testString, // Text data to be broken
+ UVector32 *breakPositions, // Positions where breaks should be found.
+ RuleBasedBreakIterator *bi) {
+ int32_t pos; // Break Position in the test string
+ int32_t expectedI = 0; // Index of expected break position in the vector of expected results.
+ int32_t expectedPos; // Expected break position (index into test string)
+
+ bi->setText(testString);
+ pos = bi->first();
+ pos = bi->next();
+
+ while (pos != BreakIterator::DONE) {
+ if (expectedI >= breakPositions->size()) {
+ errln("Test file \"%s\", line %d, unexpected break found at position %d",
+ testFileName, lineNumber, pos);
+ break;
+ }
+ expectedPos = breakPositions->elementAti(expectedI);
+ if (pos < expectedPos) {
+ errln("Test file \"%s\", line %d, unexpected break found at position %d",
+ testFileName, lineNumber, pos);
+ break;
+ }
+ if (pos > expectedPos) {
+ errln("Test file \"%s\", line %d, failed to find break at position %d",
+ testFileName, lineNumber, expectedPos);
+ break;
+ }
+ pos = bi->next();
+ expectedI++;
+ }
+
+ if (pos==BreakIterator::DONE && expectedI<breakPositions->size()) {
+ errln("Test file \"%s\", line %d, failed to find break at position %d",
+ testFileName, lineNumber, breakPositions->elementAti(expectedI));
+ }
+}
+
+
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+//---------------------------------------------------------------------------------------
+//
+// classs RBBIMonkeyKind
+//
+// Monkey Test for Break Iteration
+// Abstract interface class. Concrete derived classes independently
+// implement the break rules for different iterator types.
+//
+// The Monkey Test itself uses doesn't know which type of break iterator it is
+// testing, but works purely in terms of the interface defined here.
+//
+//---------------------------------------------------------------------------------------
+class RBBIMonkeyKind {
+public:
+ // Return a UVector of UnicodeSets, representing the character classes used
+ // for this type of iterator.
+ virtual UVector *charClasses() = 0;
+
+ // Set the test text on which subsequent calls to next() will operate
+ virtual void setText(const UnicodeString &s) = 0;
+
+ // Find the next break postion, starting from the prev break position, or from zero.
+ // Return -1 after reaching end of string.
+ virtual int32_t next(int32_t i) = 0;
+
+ virtual ~RBBIMonkeyKind();
+ UErrorCode deferredStatus;
+
+
+protected:
+ RBBIMonkeyKind();
+
+private:
+};
+
+RBBIMonkeyKind::RBBIMonkeyKind() {
+ deferredStatus = U_ZERO_ERROR;
+}
+
+RBBIMonkeyKind::~RBBIMonkeyKind() {
+}
+
+
+//----------------------------------------------------------------------------------------
+//
+// Random Numbers. Similar to standard lib rand() and srand()
+// Not using library to
+// 1. Get same results on all platforms.
+// 2. Get access to current seed, to more easily reproduce failures.
+//
+//---------------------------------------------------------------------------------------
+static uint32_t m_seed = 1;
+
+static uint32_t m_rand()
+{
+ m_seed = m_seed * 1103515245 + 12345;
+ return (uint32_t)(m_seed/65536) % 32768;
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+// class RBBICharMonkey Character (Grapheme Cluster) specific implementation
+// of RBBIMonkeyKind.
+//
+//------------------------------------------------------------------------------------------
+class RBBICharMonkey: public RBBIMonkeyKind {
+public:
+ RBBICharMonkey();
+ virtual ~RBBICharMonkey();
+ virtual UVector *charClasses();
+ virtual void setText(const UnicodeString &s);
+ virtual int32_t next(int32_t i);
+private:
+ UVector *fSets;
+
+ UnicodeSet *fCRLFSet;
+ UnicodeSet *fControlSet;
+ UnicodeSet *fExtendSet;
+ UnicodeSet *fHangulSet;
+ UnicodeSet *fAnySet;
+
+ RegexMatcher *fMatcher;
+ const UnicodeString *fText;
+};
+
+
+RBBICharMonkey::RBBICharMonkey() {
+ UErrorCode status = U_ZERO_ERROR;
+
+ fText = NULL;
+ fMatcher = new RegexMatcher("\\X", 0, status); // Pattern to match a grampheme cluster
+
+ fCRLFSet = new UnicodeSet("[\\r\\n]", status);
+ fControlSet = new UnicodeSet("[[\\p{Zl}\\p{Zp}\\p{Cc}\\p{Cf}]-[\\n]-[\\r]-\\p{Grapheme_Extend}]", status);
+ fExtendSet = new UnicodeSet("[\\p{Grapheme_Extend}]", status);
+ fHangulSet = new UnicodeSet(
+ "[\\p{Hangul_Syllable_Type=L}\\p{Hangul_Syllable_Type=L}\\p{Hangul_Syllable_Type=T}"
+ "\\p{Hangul_Syllable_Type=LV}\\p{Hangul_Syllable_Type=LVT}]", status);
+ fAnySet = new UnicodeSet("[\\u0000-\\U0010ffff]", status);
+
+ fSets = new UVector(status);
+ fSets->addElement(fCRLFSet, status);
+ fSets->addElement(fControlSet, status);
+ fSets->addElement(fExtendSet, status);
+ fSets->addElement(fHangulSet, status);
+ fSets->addElement(fAnySet, status);
+ if (U_FAILURE(status)) {
+ deferredStatus = status;
+ }
+}
+
+
+void RBBICharMonkey::setText(const UnicodeString &s) {
+ fText = &s;
+ fMatcher->reset(s);
+}
+
+
+int32_t RBBICharMonkey::next(int32_t i) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t retVal = -1;
+
+ if (fMatcher->find(i, status)) {
+ retVal = fMatcher->end(status);
+ }
+ if (U_FAILURE(status)){
+ retVal = -1;
+ }
+ return retVal;
+}
+
+
+UVector *RBBICharMonkey::charClasses() {
+ return fSets;
+}
+
+
+RBBICharMonkey::~RBBICharMonkey() {
+ delete fSets;
+ delete fCRLFSet;
+ delete fControlSet;
+ delete fExtendSet;
+ delete fHangulSet;
+ delete fAnySet;
+
+ delete fMatcher;
+}
+
+//------------------------------------------------------------------------------------------
+//
+// class RBBIWordMonkey Word Break specific implementation
+// of RBBIMonkeyKind.
+//
+//------------------------------------------------------------------------------------------
+class RBBIWordMonkey: public RBBIMonkeyKind {
+public:
+ RBBIWordMonkey();
+ virtual ~RBBIWordMonkey();
+ virtual UVector *charClasses();
+ virtual void setText(const UnicodeString &s);
+ virtual int32_t next(int32_t i);
+private:
+ UVector *fSets;
+
+ UnicodeSet *fKatakanaSet;
+ UnicodeSet *fALetterSet;
+ UnicodeSet *fMidLetterSet;
+ UnicodeSet *fMidNumSet;
+ UnicodeSet *fNumericSet;
+ UnicodeSet *fFormatSet;
+ UnicodeSet *fOtherSet;
+ UnicodeSet *fExtendSet;
+ UnicodeSet *fExtendNumLetSet;
+
+ RegexMatcher *fMatcher;
+
+ const UnicodeString *fText;
+};
+
+
+RBBIWordMonkey::RBBIWordMonkey()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+
+ fSets = new UVector(status);
+
+ fALetterSet = new UnicodeSet("[\\p{Word_Break = ALetter}"
+ "[\\p{Line_Break = Complex_Context}"
+ "-\\p{Grapheme_Cluster_Break = Extend}"
+ "-\\p{Grapheme_Cluster_Break = Control}]]", status);
+ //fALetterSet = new UnicodeSet("[\\p{Word_Break = ALetter}]", status);
+ fKatakanaSet = new UnicodeSet("[\\p{Word_Break = Katakana}-[\\uff9e\\uff9f]]", status);
+ fMidLetterSet = new UnicodeSet("[\\p{Word_Break = MidLetter}]", status);
+ fMidNumSet = new UnicodeSet("[\\p{Word_Break = MidNum}]", status);
+ fNumericSet = new UnicodeSet("[\\p{Word_Break = Numeric}]", status);
+ fFormatSet = new UnicodeSet("[\\p{Word_Break = Format}]", status);
+ fExtendNumLetSet = new UnicodeSet("[\\p{Word_Break = ExtendNumLet}]", status);
+ //fExtendSet = new UnicodeSet("[\\p{Word_Break = Extend}]", status);
+ fExtendSet = new UnicodeSet("[\\p{Grapheme_Cluster_Break = Extend}\\uff9e\\uff9f]", status);
+
+ fOtherSet = new UnicodeSet();
+ if(U_FAILURE(status)) {
+ deferredStatus = status;
+ return;
+ }
+
+ fOtherSet->complement();
+ fOtherSet->removeAll(*fKatakanaSet);
+ fOtherSet->removeAll(*fALetterSet);
+ fOtherSet->removeAll(*fMidLetterSet);
+ fOtherSet->removeAll(*fMidNumSet);
+ fOtherSet->removeAll(*fNumericSet);
+ fOtherSet->removeAll(*fExtendNumLetSet);
+ fOtherSet->removeAll(*fFormatSet);
+ fOtherSet->removeAll(*fExtendSet);
+
+ fSets->addElement(fALetterSet, status);
+ fSets->addElement(fKatakanaSet, status);
+ fSets->addElement(fMidLetterSet, status);
+ fSets->addElement(fMidNumSet, status);
+ fSets->addElement(fNumericSet, status);
+ fSets->addElement(fFormatSet, status);
+ fSets->addElement(fExtendSet, status);
+ fSets->addElement(fOtherSet, status);
+ fSets->addElement(fExtendNumLetSet, status);
+
+
+ if (U_FAILURE(status)) {
+ deferredStatus = status;
+ }
+}
+
+void RBBIWordMonkey::setText(const UnicodeString &s) {
+ fText = &s;
+}
+
+
+int32_t RBBIWordMonkey::next(int32_t prevPos) {
+ int p0, p1, p2, p3; // Indices of the significant code points around the
+ // break position being tested. The candidate break
+ // location is before p2.
+
+ int breakPos = -1;
+
+ UChar32 c0, c1, c2, c3; // The code points at p0, p1, p2 & p3.
+
+ // Prev break at end of string. return DONE.
+ if (prevPos >= fText->length()) {
+ return -1;
+ }
+ p0 = p1 = p2 = p3 = prevPos;
+ c3 = fText->char32At(prevPos);
+ c0 = c1 = c2 = 0;
+
+ // Loop runs once per "significant" character position in the input text.
+ for (;;) {
+ // Move all of the positions forward in the input string.
+ p0 = p1; c0 = c1;
+ p1 = p2; c1 = c2;
+ p2 = p3; c2 = c3;
+
+ // Advancd p3 by X(Extend | Format)* Rule 4
+ do {
+ p3 = fText->moveIndex32(p3, 1);
+ c3 = fText->char32At(p3);
+ }
+ while (fFormatSet->contains(c3) || fExtendSet->contains(c3));
+
+
+ if (p1 == p2) {
+ // Still warming up the loop. (won't work with zero length strings, but we don't care)
+ continue;
+ }
+ if (p2 == fText->length()) {
+ // Reached end of string. Always a break position.
+ break;
+ }
+
+ // Rule (3) CR x LF
+ // No Extend or Format characters may appear between the CR and LF,
+ // which requires the additional check for p2 immediately following p1.
+ //
+ if (c1==0x0D && c2==0x0A && p1==(p2-1)) {
+ continue;
+ }
+
+ // Rule (5). ALetter x ALetter
+ if (fALetterSet->contains(c1) &&
+ fALetterSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule (6) ALetter x (MidLetter | MidNumLet) ALetter
+ //
+ // Also incorporates rule 7 by skipping pos ahead to position of the
+ // terminating ALetter.
+ if ( fALetterSet->contains(c1) &&
+ fMidLetterSet->contains(c2) &&
+ fALetterSet->contains(c3)) {
+ continue;
+ }
+
+
+ // Rule (7) ALetter (MidLetter | MidNumLet) x ALetter
+ if (fALetterSet->contains(c0) &&
+ (fMidLetterSet->contains(c1) ) &&
+ fALetterSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule (8) Numeric x Numeric
+ if (fNumericSet->contains(c1) &&
+ fNumericSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule (9) ALetter x Numeric
+ if (fALetterSet->contains(c1) &&
+ fNumericSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule (10) Numeric x ALetter
+ if (fNumericSet->contains(c1) &&
+ fALetterSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule (11) Numeric (MidNum | MidNumLet) x Numeric
+ if ( fNumericSet->contains(c0) &&
+ fMidNumSet->contains(c1) &&
+ fNumericSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule (12) Numeric x (MidNum | MidNumLet) Numeric
+ if (fNumericSet->contains(c1) &&
+ fMidNumSet->contains(c2) &&
+ fNumericSet->contains(c3)) {
+ continue;
+ }
+
+ // Rule (13) Katakana x Katakana
+ if (fKatakanaSet->contains(c1) &&
+ fKatakanaSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule 13a
+ if ((fALetterSet->contains(c1) || fNumericSet->contains(c1) ||
+ fKatakanaSet->contains(c1) || fExtendNumLetSet->contains(c1)) &&
+ fExtendNumLetSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule 13b
+ if (fExtendNumLetSet->contains(c1) &&
+ (fALetterSet->contains(c2) || fNumericSet->contains(c2) ||
+ fKatakanaSet->contains(c2))) {
+ continue;
+ }
+
+ // Rule 14. Break found here.
+ break;
+ }
+
+ breakPos = p2;
+ return breakPos;
+}
+
+
+UVector *RBBIWordMonkey::charClasses() {
+ return fSets;
+}
+
+
+RBBIWordMonkey::~RBBIWordMonkey() {
+ delete fSets;
+ delete fKatakanaSet;
+ delete fALetterSet;
+ delete fMidLetterSet;
+ delete fMidNumSet;
+ delete fNumericSet;
+ delete fFormatSet;
+ delete fExtendSet;
+ delete fExtendNumLetSet;
+ delete fOtherSet;
+}
+
+
+
+
+//------------------------------------------------------------------------------------------
+//
+// class RBBISentMonkey Sentence Break specific implementation
+// of RBBIMonkeyKind.
+//
+//------------------------------------------------------------------------------------------
+class RBBISentMonkey: public RBBIMonkeyKind {
+public:
+ RBBISentMonkey();
+ virtual ~RBBISentMonkey();
+ virtual UVector *charClasses();
+ virtual void setText(const UnicodeString &s);
+ virtual int32_t next(int32_t i);
+private:
+ int moveBack(int posFrom);
+ int moveForward(int posFrom);
+ UChar32 cAt(int pos);
+
+ UVector *fSets;
+
+ UnicodeSet *fSepSet;
+ UnicodeSet *fFormatSet;
+ UnicodeSet *fSpSet;
+ UnicodeSet *fLowerSet;
+ UnicodeSet *fUpperSet;
+ UnicodeSet *fOLetterSet;
+ UnicodeSet *fNumericSet;
+ UnicodeSet *fATermSet;
+ UnicodeSet *fSTermSet;
+ UnicodeSet *fCloseSet;
+ UnicodeSet *fOtherSet;
+ UnicodeSet *fExtendSet;
+
+ const UnicodeString *fText;
+
+};
+
+RBBISentMonkey::RBBISentMonkey()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ fSets = new UVector(status);
+
+ fSepSet = new UnicodeSet("[\\p{Sentence_Break = Sep}]", status);
+ fFormatSet = new UnicodeSet("[\\p{Sentence_Break = Format}]", status);
+ fSpSet = new UnicodeSet("[\\p{Sentence_Break = Sp}]", status);
+ fLowerSet = new UnicodeSet("[\\p{Sentence_Break = Lower}]", status);
+ fUpperSet = new UnicodeSet("[\\p{Sentence_Break = Upper}]", status);
+ fOLetterSet = new UnicodeSet("[\\p{Sentence_Break = OLetter}-[\\uff9e\\uff9f]]", status);
+ fNumericSet = new UnicodeSet("[\\p{Sentence_Break = Numeric}]", status);
+ fATermSet = new UnicodeSet("[\\p{Sentence_Break = ATerm}]", status);
+ fSTermSet = new UnicodeSet("[\\p{Sentence_Break = STerm}]", status);
+ fCloseSet = new UnicodeSet("[\\p{Sentence_Break = Close}]", status);
+ fExtendSet = new UnicodeSet("[\\p{Grapheme_Extend}\\uff9e\\uff9f]", status);
+ fOtherSet = new UnicodeSet();
+
+ if(U_FAILURE(status)) {
+ deferredStatus = status;
+ return;
+ }
+
+ fOtherSet->complement();
+ fOtherSet->removeAll(*fSepSet);
+ fOtherSet->removeAll(*fFormatSet);
+ fOtherSet->removeAll(*fSpSet);
+ fOtherSet->removeAll(*fLowerSet);
+ fOtherSet->removeAll(*fUpperSet);
+ fOtherSet->removeAll(*fOLetterSet);
+ fOtherSet->removeAll(*fNumericSet);
+ fOtherSet->removeAll(*fATermSet);
+ fOtherSet->removeAll(*fSTermSet);
+ fOtherSet->removeAll(*fCloseSet);
+ fOtherSet->removeAll(*fExtendSet);
+
+ fSets->addElement(fSepSet, status);
+ fSets->addElement(fFormatSet, status);
+
+ fSets->addElement(fSpSet, status);
+ fSets->addElement(fLowerSet, status);
+ fSets->addElement(fUpperSet, status);
+ fSets->addElement(fOLetterSet, status);
+ fSets->addElement(fNumericSet, status);
+ fSets->addElement(fATermSet, status);
+ fSets->addElement(fSTermSet, status);
+ fSets->addElement(fCloseSet, status);
+ fSets->addElement(fOtherSet, status);
+ fSets->addElement(fExtendSet, status);
+
+ if (U_FAILURE(status)) {
+ deferredStatus = status;
+ }
+}
+
+
+
+void RBBISentMonkey::setText(const UnicodeString &s) {
+ fText = &s;
+}
+
+UVector *RBBISentMonkey::charClasses() {
+ return fSets;
+}
+
+
+// moveBack() Find the "significant" code point preceding the index i.
+// Skips over ($Extend | $Format)* .
+//
+int RBBISentMonkey::moveBack(int i) {
+ if (i <= 0) {
+ return -1;
+ }
+ UChar32 c;
+ int32_t j = i;
+ do {
+ j = fText->moveIndex32(j, -1);
+ c = fText->char32At(j);
+ }
+ while (j>0 &&(fFormatSet->contains(c) || fExtendSet->contains(c)));
+ return j;
+
+ }
+
+
+int RBBISentMonkey::moveForward(int i) {
+ if (i>=fText->length()) {
+ return fText->length();
+ }
+ UChar32 c;
+ int32_t j = i;
+ do {
+ j = fText->moveIndex32(j, 1);
+ c = cAt(j);
+ }
+ while (fFormatSet->contains(c) || fExtendSet->contains(c));
+ return j;
+}
+
+UChar32 RBBISentMonkey::cAt(int pos) {
+ if (pos<0 || pos>=fText->length()) {
+ return -1;
+ } else {
+ return fText->char32At(pos);
+ }
+}
+
+int32_t RBBISentMonkey::next(int32_t prevPos) {
+ int p0, p1, p2, p3; // Indices of the significant code points around the
+ // break position being tested. The candidate break
+ // location is before p2.
+
+ int breakPos = -1;
+
+ UChar32 c0, c1, c2, c3; // The code points at p0, p1, p2 & p3.
+ UChar32 c;
+
+ // Prev break at end of string. return DONE.
+ if (prevPos >= fText->length()) {
+ return -1;
+ }
+ p0 = p1 = p2 = p3 = prevPos;
+ c3 = fText->char32At(prevPos);
+ c0 = c1 = c2 = 0;
+
+ // Loop runs once per "significant" character position in the input text.
+ for (;;) {
+ // Move all of the positions forward in the input string.
+ p0 = p1; c0 = c1;
+ p1 = p2; c1 = c2;
+ p2 = p3; c2 = c3;
+
+ // Advancd p3 by X(Extend | Format)* Rule 4
+ p3 = moveForward(p3);
+ c3 = cAt(p3);
+
+ // Rule (3) CR x LF
+ if (c1==0x0d && c2==0x0a && p2==(p1+1)) {
+ continue;
+ }
+
+ // Rule (4). Sep <break>
+ if (fSepSet->contains(c1)) {
+ p2 = p1+1; // Separators don't combine with Extend or Format.
+ break;
+ }
+
+ if (p2 >= fText->length()) {
+ // Reached end of string. Always a break position.
+ break;
+ }
+
+ if (p2 == prevPos) {
+ // Still warming up the loop. (won't work with zero length strings, but we don't care)
+ continue;
+ }
+
+ // Rule (6). ATerm x Numeric
+ if (fATermSet->contains(c1) && fNumericSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule (7). Upper ATerm x Uppper
+ if (fUpperSet->contains(c0) && fATermSet->contains(c1) && fUpperSet->contains(c2)) {
+ continue;
+ }
+
+ // Rule (8) ATerm Close* Sp* x (not (OLettter | Upper | Lower | Sep | STerm | ATerm))* Lower
+ // Note: STerm | ATerm are added to the negated part of the expression by a
+ // note to the Unicode 5.0 documents.
+ int p8 = p1;
+ while (fSpSet->contains(cAt(p8))) {
+ p8 = moveBack(p8);
+ }
+ while (fCloseSet->contains(cAt(p8))) {
+ p8 = moveBack(p8);
+ }
+ if (fATermSet->contains(cAt(p8))) {
+ p8=p2;
+ for (;;) {
+ c = cAt(p8);
+ if (c==-1 || fOLetterSet->contains(c) || fUpperSet->contains(c) ||
+ fLowerSet->contains(c) || fSepSet->contains(c) ||
+ fATermSet->contains(c) || fSTermSet->contains(c)) {
+ break;
+ }
+ p8 = moveForward(p8);
+ }
+ if (fLowerSet->contains(cAt(p8))) {
+ continue;
+ }
+ }
+
+ // Rule 8a (STerm | ATerm) Close* Sp* x (STerm | ATerm);
+ if (fSTermSet->contains(c2) || fATermSet->contains(c2)) {
+ p8 = p1;
+ while (fSpSet->contains(cAt(p8))) {
+ p8 = moveBack(p8);
+ }
+ while (fCloseSet->contains(cAt(p8))) {
+ p8 = moveBack(p8);
+ }
+ c = cAt(p8);
+ if (fSTermSet->contains(c) || fATermSet->contains(c)) {
+ continue;
+ }
+ }
+
+ // Rule (9) (STerm | ATerm) Close* x (Close | Sp | Sep)
+ int p9 = p1;
+ while (fCloseSet->contains(cAt(p9))) {
+ p9 = moveBack(p9);
+ }
+ c = cAt(p9);
+ if ((fSTermSet->contains(c) || fATermSet->contains(c))) {
+ if (fCloseSet->contains(c2) || fSpSet->contains(c2) || fSepSet->contains(c2)) {
+ continue;
+ }
+ }
+
+ // Rule (10) (Sterm | ATerm) Close* Sp* x (Sp | Sep)
+ int p10 = p1;
+ while (fSpSet->contains(cAt(p10))) {
+ p10 = moveBack(p10);
+ }
+ while (fCloseSet->contains(cAt(p10))) {
+ p10 = moveBack(p10);
+ }
+ if (fSTermSet->contains(cAt(p10)) || fATermSet->contains(cAt(p10))) {
+ if (fSpSet->contains(c2) || fSepSet->contains(c2)) {
+ continue;
+ }
+ }
+
+ // Rule (11) (STerm | ATerm) Close* Sp* <break>
+ int p11 = p1;
+ while (fSpSet->contains(cAt(p11))) {
+ p11 = moveBack(p11);
+ }
+ while (fCloseSet->contains(cAt(p11))) {
+ p11 = moveBack(p11);
+ }
+ if (fSTermSet->contains(cAt(p11)) || fATermSet->contains(cAt(p11))) {
+ break;
+ }
+
+ // Rule (12) Any x Any
+ continue;
+ }
+ breakPos = p2;
+ return breakPos;
+}
+
+RBBISentMonkey::~RBBISentMonkey() {
+ delete fSets;
+ delete fSepSet;
+ delete fFormatSet;
+ delete fSpSet;
+ delete fLowerSet;
+ delete fUpperSet;
+ delete fOLetterSet;
+ delete fNumericSet;
+ delete fATermSet;
+ delete fSTermSet;
+ delete fCloseSet;
+ delete fOtherSet;
+ delete fExtendSet;
+}
+
+
+
+//-------------------------------------------------------------------------------------------
+//
+// RBBILineMonkey
+//
+//-------------------------------------------------------------------------------------------
+
+class RBBILineMonkey: public RBBIMonkeyKind {
+public:
+ RBBILineMonkey();
+ virtual ~RBBILineMonkey();
+ virtual UVector *charClasses();
+ virtual void setText(const UnicodeString &s);
+ virtual int32_t next(int32_t i);
+ virtual void rule9Adjust(int32_t pos, UChar32 *posChar, int32_t *nextPos, UChar32 *nextChar);
+private:
+ UVector *fSets;
+
+ UnicodeSet *fBK;
+ UnicodeSet *fCR;
+ UnicodeSet *fLF;
+ UnicodeSet *fCM;
+ UnicodeSet *fNL;
+ UnicodeSet *fSG;
+ UnicodeSet *fWJ;
+ UnicodeSet *fZW;
+ UnicodeSet *fGL;
+ UnicodeSet *fCB;
+ UnicodeSet *fSP;
+ UnicodeSet *fB2;
+ UnicodeSet *fBA;
+ UnicodeSet *fBB;
+ UnicodeSet *fHY;
+ UnicodeSet *fH2;
+ UnicodeSet *fH3;
+ UnicodeSet *fCL;
+ UnicodeSet *fEX;
+ UnicodeSet *fIN;
+ UnicodeSet *fJL;
+ UnicodeSet *fJV;
+ UnicodeSet *fJT;
+ UnicodeSet *fNS;
+ UnicodeSet *fOP;
+ UnicodeSet *fQU;
+ UnicodeSet *fIS;
+ UnicodeSet *fNU;
+ UnicodeSet *fPO;
+ UnicodeSet *fPR;
+ UnicodeSet *fSY;
+ UnicodeSet *fAI;
+ UnicodeSet *fAL;
+ UnicodeSet *fID;
+ UnicodeSet *fSA;
+ UnicodeSet *fXX;
+
+ BreakIterator *fCharBI;
+
+ const UnicodeString *fText;
+ int32_t *fOrigPositions;
+
+ RegexMatcher *fNumberMatcher;
+ RegexMatcher *fLB11Matcher;
+};
+
+
+RBBILineMonkey::RBBILineMonkey()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ fSets = new UVector(status);
+
+ fBK = new UnicodeSet("[\\p{Line_Break=BK}]", status);
+ fCR = new UnicodeSet("[\\p{Line_break=CR}]", status);
+ fLF = new UnicodeSet("[\\p{Line_break=LF}]", status);
+ fCM = new UnicodeSet("[\\p{Line_break=CM}]", status);
+ fNL = new UnicodeSet("[\\p{Line_break=NL}]", status);
+ fWJ = new UnicodeSet("[\\p{Line_break=WJ}]", status);
+ fZW = new UnicodeSet("[\\p{Line_break=ZW}]", status);
+ fGL = new UnicodeSet("[\\p{Line_break=GL}]", status);
+ fCB = new UnicodeSet("[\\p{Line_break=CB}]", status);
+ fSP = new UnicodeSet("[\\p{Line_break=SP}]", status);
+ fB2 = new UnicodeSet("[\\p{Line_break=B2}]", status);
+ fBA = new UnicodeSet("[\\p{Line_break=BA}]", status);
+ fBB = new UnicodeSet("[\\p{Line_break=BB}]", status);
+ fHY = new UnicodeSet("[\\p{Line_break=HY}]", status);
+ fH2 = new UnicodeSet("[\\p{Line_break=H2}]", status);
+ fH3 = new UnicodeSet("[\\p{Line_break=H3}]", status);
+ fCL = new UnicodeSet("[\\p{Line_break=CL}]", status);
+ fEX = new UnicodeSet("[\\p{Line_break=EX}]", status);
+ fIN = new UnicodeSet("[\\p{Line_break=IN}]", status);
+ fJL = new UnicodeSet("[\\p{Line_break=JL}]", status);
+ fJV = new UnicodeSet("[\\p{Line_break=JV}]", status);
+ fJT = new UnicodeSet("[\\p{Line_break=JT}]", status);
+ fNS = new UnicodeSet("[\\p{Line_break=NS}]", status);
+ fOP = new UnicodeSet("[\\p{Line_break=OP}]", status);
+ fQU = new UnicodeSet("[\\p{Line_break=QU}]", status);
+ fIS = new UnicodeSet("[\\p{Line_break=IS}]", status);
+ fNU = new UnicodeSet("[\\p{Line_break=NU}]", status);
+ fPO = new UnicodeSet("[\\p{Line_break=PO}]", status);
+ fPR = new UnicodeSet("[\\p{Line_break=PR}]", status);
+ fSY = new UnicodeSet("[\\p{Line_break=SY}]", status);
+ fAI = new UnicodeSet("[\\p{Line_break=AI}]", status);
+ fAL = new UnicodeSet("[\\p{Line_break=AL}]", status);
+ fID = new UnicodeSet("[\\p{Line_break=ID}]", status);
+ fSA = new UnicodeSet("[\\p{Line_break=SA}]", status);
+ fSG = new UnicodeSet("[\\ud800-\\udfff]", status);
+ fXX = new UnicodeSet("[\\p{Line_break=XX}]", status);
+
+ if (U_FAILURE(status)) {
+ deferredStatus = status;
+ fCharBI = NULL;
+ fNumberMatcher = NULL;
+ return;
+ }
+
+ fAL->addAll(*fXX); // Default behavior for XX is identical to AL
+ fAL->addAll(*fAI); // Default behavior for AI is identical to AL
+ fAL->addAll(*fSA); // Default behavior for SA is XX, which defaults to AL
+ fAL->addAll(*fSG); // Default behavior for SG is identical to AL.
+
+ fSets->addElement(fBK, status);
+ fSets->addElement(fCR, status);
+ fSets->addElement(fLF, status);
+ fSets->addElement(fCM, status);
+ fSets->addElement(fNL, status);
+ fSets->addElement(fWJ, status);
+ fSets->addElement(fZW, status);
+ fSets->addElement(fGL, status);
+ fSets->addElement(fCB, status);
+ fSets->addElement(fSP, status);
+ fSets->addElement(fB2, status);
+ fSets->addElement(fBA, status);
+ fSets->addElement(fBB, status);
+ fSets->addElement(fHY, status);
+ fSets->addElement(fH2, status);
+ fSets->addElement(fH3, status);
+ fSets->addElement(fCL, status);
+ fSets->addElement(fEX, status);
+ fSets->addElement(fIN, status);
+ fSets->addElement(fJL, status);
+ fSets->addElement(fJT, status);
+ fSets->addElement(fJV, status);
+ fSets->addElement(fNS, status);
+ fSets->addElement(fOP, status);
+ fSets->addElement(fQU, status);
+ fSets->addElement(fIS, status);
+ fSets->addElement(fNU, status);
+ fSets->addElement(fPO, status);
+ fSets->addElement(fPR, status);
+ fSets->addElement(fSY, status);
+ fSets->addElement(fAI, status);
+ fSets->addElement(fAL, status);
+ fSets->addElement(fID, status);
+ fSets->addElement(fWJ, status);
+ fSets->addElement(fSA, status);
+ fSets->addElement(fSG, status);
+
+ fNumberMatcher = new RegexMatcher(
+ "((\\p{Line_Break=PR}|\\p{Line_Break=PO})\\p{Line_Break=CM}*)?"
+ "((\\p{Line_Break=OP}|\\p{Line_Break=HY})\\p{Line_Break=CM}*)?"
+ "\\p{Line_Break=NU}\\p{Line_Break=CM}*"
+ "((\\p{Line_Break=NU}|\\p{Line_Break=IS}|\\p{Line_Break=SY})\\p{Line_Break=CM}*)*"
+ "(\\p{Line_Break=CL}\\p{Line_Break=CM}*)?"
+ "((\\p{Line_Break=PR}|\\p{Line_Break=PO})\\p{Line_Break=CM}*)?",
+ 0, status);
+
+ fCharBI = BreakIterator::createCharacterInstance(Locale::getEnglish(), status);
+
+ if (U_FAILURE(status)) {
+ deferredStatus = status;
+ }
+}
+
+
+void RBBILineMonkey::setText(const UnicodeString &s) {
+ fText = &s;
+ fCharBI->setText(s);
+ fNumberMatcher->reset(s);
+}
+
+//
+// rule9Adjust
+// Line Break TR rules 9 and 10 implementation.
+// This deals with combining marks and other sequences that
+// that must be treated as if they were something other than what they actually are.
+//
+// This is factored out into a separate function because it must be applied twice for
+// each potential break, once to the chars before the position being checked, then
+// again to the text following the possible break.
+//
+void RBBILineMonkey::rule9Adjust(int32_t pos, UChar32 *posChar, int32_t *nextPos, UChar32 *nextChar) {
+ if (pos == -1) {
+ // Invalid initial position. Happens during the warmup iteration of the
+ // main loop in next().
+ return;
+ }
+
+ int32_t nPos = *nextPos;
+
+ // LB 9 Keep combining sequences together.
+ // advance over any CM class chars. Note that Line Break CM is different
+ // from the normal Grapheme Extend property.
+ if (!(fSP->contains(*posChar) || fBK->contains(*posChar) || *posChar==0x0d ||
+ *posChar==0x0a ||fNL->contains(*posChar) || fZW->contains(*posChar))) {
+ for (;;) {
+ *nextChar = fText->char32At(nPos);
+ if (!fCM->contains(*nextChar)) {
+ break;
+ }
+ nPos = fText->moveIndex32(nPos, 1);
+ }
+ }
+
+
+ // LB 9 Treat X CM* as if it were x.
+ // No explicit action required.
+
+ // LB 10 Treat any remaining combining mark as AL
+ if (fCM->contains(*posChar)) {
+ *posChar = 0x41; // thisChar = 'A';
+ }
+
+ // Push the updated nextPos and nextChar back to our caller.
+ // This only makes a difference if posChar got bigger by consuming a
+ // combining sequence.
+ *nextPos = nPos;
+ *nextChar = fText->char32At(nPos);
+}
+
+
+
+int32_t RBBILineMonkey::next(int32_t startPos) {
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t pos; // Index of the char following a potential break position
+ UChar32 thisChar; // Character at above position "pos"
+
+ int32_t prevPos; // Index of the char preceding a potential break position
+ UChar32 prevChar; // Character at above position. Note that prevChar
+ // and thisChar may not be adjacent because combining
+ // characters between them will be ignored.
+
+ int32_t nextPos; // Index of the next character following pos.
+ // Usually skips over combining marks.
+ int32_t nextCPPos; // Index of the code point following "pos."
+ // May point to a combining mark.
+ int32_t tPos; // temp value.
+ UChar32 c;
+
+ if (startPos >= fText->length()) {
+ return -1;
+ }
+
+
+ // Initial values for loop. Loop will run the first time without finding breaks,
+ // while the invalid values shift out and the "this" and
+ // "prev" positions are filled in with good values.
+ pos = prevPos = -1; // Invalid value, serves as flag for initial loop iteration.
+ thisChar = prevChar = 0;
+ nextPos = nextCPPos = startPos;
+
+
+ // Loop runs once per position in the test text, until a break position
+ // is found.
+ for (;;) {
+ prevPos = pos;
+ prevChar = thisChar;
+
+ pos = nextPos;
+ thisChar = fText->char32At(pos);
+
+ nextCPPos = fText->moveIndex32(pos, 1);
+ nextPos = nextCPPos;
+
+ // Rule LB2 - Break at end of text.
+ if (pos >= fText->length()) {
+ break;
+ }
+
+ // Rule LB 9 - adjust for combining sequences.
+ // We do this one out-of-order because the adjustment does not change anything
+ // that would match rules LB 3 - LB 6, but after the adjustment, LB 3-6 do need to
+ // be applied.
+ rule9Adjust(prevPos, &prevChar, &pos, &thisChar);
+ nextCPPos = nextPos = fText->moveIndex32(pos, 1);
+ c = fText->char32At(nextPos);
+ rule9Adjust(pos, &thisChar, &nextPos, &c);
+
+ // If the loop is still warming up - if we haven't shifted the initial
+ // -1 positions out of prevPos yet - loop back to advance the
+ // position in the input without any further looking for breaks.
+ if (prevPos == -1) {
+ continue;
+ }
+
+ // LB 4 Always break after hard line breaks,
+ if (fBK->contains(prevChar)) {
+ break;
+ }
+
+ // LB 5 Break after CR, LF, NL, but not inside CR LF
+ if (prevChar == 0x0d && thisChar == 0x0a) {
+ continue;
+ }
+ if (prevChar == 0x0d ||
+ prevChar == 0x0a ||
+ prevChar == 0x85) {
+ break;
+ }
+
+ // LB 6 Don't break before hard line breaks
+ if (thisChar == 0x0d || thisChar == 0x0a || thisChar == 0x85 ||
+ fBK->contains(thisChar)) {
+ continue;
+ }
+
+
+ // LB 7 Don't break before spaces or zero-width space.
+ if (fSP->contains(thisChar)) {
+ continue;
+ }
+
+ if (fZW->contains(thisChar)) {
+ continue;
+ }
+
+ // LB 8 Break after zero width space
+ if (fZW->contains(prevChar)) {
+ break;
+ }
+
+ // LB 9, 10 Already done, at top of loop.
+ //
+
+
+ // LB 11 Do not break before or after WORD JOINER and related characters.
+ // x WJ
+ // WJ x
+ //
+ if (fWJ->contains(thisChar) || fWJ->contains(prevChar)) {
+ continue;
+ }
+
+ // LB 12
+ // (!SP) x GL
+ // GL x
+ if ((!fSP->contains(prevChar)) && fGL->contains(thisChar) ||
+ fGL->contains(prevChar)) {
+ continue;
+ }
+
+
+
+ // LB 13 Don't break before closings.
+ // NU x CL and NU x IS are not matched here so that they will
+ // fall into LB 17 and the more general number regular expression.
+ //
+ if (!fNU->contains(prevChar) && fCL->contains(thisChar) ||
+ fEX->contains(thisChar) ||
+ !fNU->contains(prevChar) && fIS->contains(thisChar) ||
+ !fNU->contains(prevChar) && fSY->contains(thisChar)) {
+ continue;
+ }
+
+ // LB 14 Don't break after OP SP*
+ // Scan backwards, checking for this sequence.
+ // The OP char could include combining marks, so we actually check for
+ // OP CM* SP*
+ // Another Twist: The Rule 67 fixes may have changed a SP CM
+ // sequence into a ID char, so before scanning back through spaces,
+ // verify that prevChar is indeed a space. The prevChar variable
+ // may differ from fText[prevPos]
+ tPos = prevPos;
+ if (fSP->contains(prevChar)) {
+ while (tPos > 0 && fSP->contains(fText->char32At(tPos))) {
+ tPos=fText->moveIndex32(tPos, -1);
+ }
+ }
+ while (tPos > 0 && fCM->contains(fText->char32At(tPos))) {
+ tPos=fText->moveIndex32(tPos, -1);
+ }
+ if (fOP->contains(fText->char32At(tPos))) {
+ continue;
+ }
+
+
+ // LB 15 QU SP* x OP
+ if (fOP->contains(thisChar)) {
+ // Scan backwards from prevChar to see if it is preceded by QU CM* SP*
+ int tPos = prevPos;
+ while (tPos>0 && fSP->contains(fText->char32At(tPos))) {
+ tPos = fText->moveIndex32(tPos, -1);
+ }
+ while (tPos>0 && fCM->contains(fText->char32At(tPos))) {
+ tPos = fText->moveIndex32(tPos, -1);
+ }
+ if (fQU->contains(fText->char32At(tPos))) {
+ continue;
+ }
+ }
+
+
+
+ // LB 16 CL SP* x NS
+ // Scan backwards for SP* CM* CL
+ if (fNS->contains(thisChar)) {
+ int tPos = prevPos;
+ while (tPos>0 && fSP->contains(fText->char32At(tPos))) {
+ tPos = fText->moveIndex32(tPos, -1);
+ }
+ while (tPos>0 && fCM->contains(fText->char32At(tPos))) {
+ tPos = fText->moveIndex32(tPos, -1);
+ }
+ if (fCL->contains(fText->char32At(tPos))) {
+ continue;
+ }
+ }
+
+
+ // LB 17 B2 SP* x B2
+ if (fB2->contains(thisChar)) {
+ // Scan backwards, checking for the B2 CM* SP* sequence.
+ tPos = prevPos;
+ if (fSP->contains(prevChar)) {
+ while (tPos > 0 && fSP->contains(fText->char32At(tPos))) {
+ tPos=fText->moveIndex32(tPos, -1);
+ }
+ }
+ while (tPos > 0 && fCM->contains(fText->char32At(tPos))) {
+ tPos=fText->moveIndex32(tPos, -1);
+ }
+ if (fB2->contains(fText->char32At(tPos))) {
+ continue;
+ }
+ }
+
+
+ // LB 18 break after space
+ if (fSP->contains(prevChar)) {
+ break;
+ }
+
+ // LB 19
+ // x QU
+ // QU x
+ if (fQU->contains(thisChar) || fQU->contains(prevChar)) {
+ continue;
+ }
+
+ // LB 20 Break around a CB
+ if (fCB->contains(thisChar) || fCB->contains(prevChar)) {
+ break;
+ }
+
+ // LB 21
+ if (fBA->contains(thisChar) ||
+ fHY->contains(thisChar) ||
+ fNS->contains(thisChar) ||
+ fBB->contains(prevChar) ) {
+ continue;
+ }
+
+ // LB 22
+ if (fAL->contains(prevChar) && fIN->contains(thisChar) ||
+ fID->contains(prevChar) && fIN->contains(thisChar) ||
+ fIN->contains(prevChar) && fIN->contains(thisChar) ||
+ fNU->contains(prevChar) && fIN->contains(thisChar) ) {
+ continue;
+ }
+
+
+ // LB 23 ID x PO
+ // AL x NU
+ // NU x AL
+ if (fID->contains(prevChar) && fPO->contains(thisChar) ||
+ fAL->contains(prevChar) && fNU->contains(thisChar) ||
+ fNU->contains(prevChar) && fAL->contains(thisChar) ) {
+ continue;
+ }
+
+ // LB 24 Do not break between prefix and letters or ideographs.
+ // PR x ID
+ // PR x AL
+ // PO x AL
+ if (fPR->contains(prevChar) && fID->contains(thisChar) ||
+ fPR->contains(prevChar) && fAL->contains(thisChar) ||
+ fPO->contains(prevChar) && fAL->contains(thisChar) ) {
+ continue;
+ }
+
+
+
+ // LB 25 Numbers
+ if (fNumberMatcher->lookingAt(prevPos, status)) {
+ if (U_FAILURE(status)) {
+ break;
+ }
+ // Matched a number. But could have been just a single digit, which would
+ // not represent a "no break here" between prevChar and thisChar
+ int32_t numEndIdx = fNumberMatcher->end(status); // idx of first char following num
+ if (numEndIdx > pos) {
+ // Number match includes at least our two chars being checked
+ if (numEndIdx > nextPos) {
+ // Number match includes additional chars. Update pos and nextPos
+ // so that next loop iteration will continue at the end of the number,
+ // checking for breaks between last char in number & whatever follows.
+ pos = nextPos = numEndIdx;
+ do {
+ pos = fText->moveIndex32(pos, -1);
+ thisChar = fText->char32At(pos);
+ } while (fCM->contains(thisChar));
+ }
+ continue;
+ }
+ }
+
+
+ // LB 26 Do not break a Korean syllable.
+ if (fJL->contains(prevChar) && (fJL->contains(thisChar) ||
+ fJV->contains(thisChar) ||
+ fH2->contains(thisChar) ||
+ fH3->contains(thisChar))) {
+ continue;
+ }
+
+ if ((fJV->contains(prevChar) || fH2->contains(prevChar)) &&
+ (fJV->contains(thisChar) || fJT->contains(thisChar))) {
+ continue;
+ }
+
+ if ((fJT->contains(prevChar) || fH3->contains(prevChar)) &&
+ fJT->contains(thisChar)) {
+ continue;
+ }
+
+ // LB 27 Treat a Korean Syllable Block the same as ID.
+ if ((fJL->contains(prevChar) || fJV->contains(prevChar) ||
+ fJT->contains(prevChar) || fH2->contains(prevChar) || fH3->contains(prevChar)) &&
+ fIN->contains(thisChar)) {
+ continue;
+ }
+ if ((fJL->contains(prevChar) || fJV->contains(prevChar) ||
+ fJT->contains(prevChar) || fH2->contains(prevChar) || fH3->contains(prevChar)) &&
+ fPO->contains(thisChar)) {
+ continue;
+ }
+ if (fPR->contains(prevChar) && (fJL->contains(thisChar) || fJV->contains(thisChar) ||
+ fJT->contains(thisChar) || fH2->contains(thisChar) || fH3->contains(thisChar))) {
+ continue;
+ }
+
+
+
+ // LB 28 Do not break between alphabetics (“at”).
+ if (fAL->contains(prevChar) && fAL->contains(thisChar)) {
+ continue;
+ }
+
+ // LB 29 Do not break between numeric punctuation and alphabetics ("e.g.").
+ if (fIS->contains(prevChar) && fAL->contains(thisChar)) {
+ continue;
+ }
+
+ //LB 30 Do not break between letters, numbers or ordinary symbols and opening or closing punctuation
+ // (AL | NU) x OP
+ // CL x (AL | NU)
+ if ((fAL->contains(prevChar) || fNU->contains(prevChar)) &&
+ fOP->contains(thisChar)) {
+ continue;
+ }
+ if (fCL->contains(prevChar) &&
+ (fAL->contains(thisChar) || fNU->contains(thisChar))) {
+ continue;
+ }
+
+
+ // LB 31 Break everywhere else
+ break;
+
+ }
+
+ return pos;
+}
+
+
+UVector *RBBILineMonkey::charClasses() {
+ return fSets;
+}
+
+
+RBBILineMonkey::~RBBILineMonkey() {
+ delete fSets;
+
+ delete fBK;
+ delete fCR;
+ delete fLF;
+ delete fCM;
+ delete fNL;
+ delete fWJ;
+ delete fZW;
+ delete fGL;
+ delete fCB;
+ delete fSP;
+ delete fB2;
+ delete fBA;
+ delete fBB;
+ delete fHY;
+ delete fH2;
+ delete fH3;
+ delete fCL;
+ delete fEX;
+ delete fIN;
+ delete fJL;
+ delete fJV;
+ delete fJT;
+ delete fNS;
+ delete fOP;
+ delete fQU;
+ delete fIS;
+ delete fNU;
+ delete fPO;
+ delete fPR;
+ delete fSY;
+ delete fAI;
+ delete fAL;
+ delete fID;
+ delete fSA;
+ delete fSG;
+ delete fXX;
+
+ delete fCharBI;
+ delete fNumberMatcher;
+}
+
+
+//-------------------------------------------------------------------------------------------
+//
+// TestMonkey
+//
+// params
+// seed=nnnnn Random number starting seed.
+// Setting the seed allows errors to be reproduced.
+// loop=nnn Looping count. Controls running time.
+// -1: run forever.
+// 0 or greater: run length.
+//
+// type = char | word | line | sent | title
+//
+//-------------------------------------------------------------------------------------------
+
+static int32_t getIntParam(UnicodeString name, UnicodeString &params, int32_t defaultVal) {
+ int32_t val = defaultVal;
+ name.append(" *= *(-?\\d+)");
+ UErrorCode status = U_ZERO_ERROR;
+ RegexMatcher m(name, params, 0, status);
+ if (m.find()) {
+ // The param exists. Convert the string to an int.
+ char valString[100];
+ int32_t paramLength = m.end(1, status) - m.start(1, status);
+ if (paramLength >= (int32_t)(sizeof(valString)-1)) {
+ paramLength = (int32_t)(sizeof(valString)-2);
+ }
+ params.extract(m.start(1, status), paramLength, valString, sizeof(valString));
+ val = strtol(valString, NULL, 10);
+
+ // Delete this parameter from the params string.
+ m.reset();
+ params = m.replaceFirst("", status);
+ }
+ U_ASSERT(U_SUCCESS(status));
+ return val;
+}
+#endif
+
+static void testBreakBoundPreceding(RBBITest *test, UnicodeString ustr,
+ BreakIterator *bi,
+ int expected[],
+ int expectedcount)
+{
+ int count = 0;
+ int i = 0;
+ int forward[50];
+ bi->setText(ustr);
+ for (i = bi->first(); i != BreakIterator::DONE; i = bi->next()) {
+ forward[count] = i;
+ if (count < expectedcount && expected[count] != i) {
+ test->errln("break forward test failed: expected %d but got %d",
+ expected[count], i);
+ break;
+ }
+ count ++;
+ }
+ if (count != expectedcount) {
+ printStringBreaks(ustr, expected, expectedcount);
+ test->errln("break forward test failed: missed %d match",
+ expectedcount - count);
+ return;
+ }
+ // testing boundaries
+ for (i = 1; i < expectedcount; i ++) {
+ int j = expected[i - 1];
+ if (!bi->isBoundary(j)) {
+ printStringBreaks(ustr, expected, expectedcount);
+ test->errln("isBoundary() failed. Expected boundary at position %d", j);
+ return;
+ }
+ for (j = expected[i - 1] + 1; j < expected[i]; j ++) {
+ if (bi->isBoundary(j)) {
+ printStringBreaks(ustr, expected, expectedcount);
+ test->errln("isBoundary() failed. Not expecting boundary at position %d", j);
+ return;
+ }
+ }
+ }
+
+ for (i = bi->last(); i != BreakIterator::DONE; i = bi->previous()) {
+ count --;
+ if (forward[count] != i) {
+ test->errln("happy break test previous() failed: expected %d but got %d",
+ forward[count], i);
+ break;
+ }
+ }
+ if (count != 0) {
+ printStringBreaks(ustr, expected, expectedcount);
+ test->errln("break test previous() failed: missed a match");
+ return;
+ }
+
+ // testing preceding
+ for (i = 0; i < expectedcount - 1; i ++) {
+ // int j = expected[i] + 1;
+ int j = ustr.moveIndex32(expected[i], 1);
+ for (; j <= expected[i + 1]; j ++) {
+ if (bi->preceding(j) != expected[i]) {
+ printStringBreaks(ustr, expected, expectedcount);
+ test->errln("preceding(): Not expecting boundary at position %d", j);
+ return;
+ }
+ }
+ }
+}
+
+void RBBITest::TestWordBreaks(void)
+{
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+ // <data><>\u1d4a\u206e<?>\u0603\U0001d7ff<>\u2019<></data>
+ Locale locale("en");
+ UErrorCode status = U_ZERO_ERROR;
+ // BreakIterator *bi = BreakIterator::createCharacterInstance(locale, status);
+ BreakIterator *bi = BreakIterator::createWordInstance(locale, status);
+ UChar str[300];
+ static const char *strlist[] =
+ {
+ "\\U000e0032\\u0097\\u0f94\\uc2d8\\u05f4\\U000e0031\\u060d",
+ "\\U000e0037\\u4666\\u1202\\u003a\\U000e0031\\u064d\\u0bea\\u591c\\U000e0040\\u003b",
+ "\\u0589\\u3e99\\U0001d7f3\\U000e0074\\u1810\\u200e\\U000e004b\\u179c\\u0027\\U000e0061\\u003a",
+ "\\u398c\\U000104a5\\U0001d173\\u102d\\u002e\\uca3b\\u002e\\u002c\\u5622",
+ "\\u90ca\\u3588\\u009c\\u0953\\u194b",
+ "\\u200e\\U000e0072\\u0a4b\\U000e003f\\ufd2b\\u2027\\u002e\\u002e",
+ "\\u0602\\u2019\\ua191\\U000e0063\\u0a4c\\u003a\\ub4b5\\u003a\\u827f\\u002e",
+ "\\u7f1f\\uc634\\u65f8\\u0944\\u04f2\\uacdf\\u1f9c\\u05f4\\u002e",
+ "\\U000e0042\\u002e\\u0fb8\\u09ef\\u0ed1\\u2044",
+ "\\u003b\\u024a\\u102e\\U000e0071\\u0600",
+ "\\u2027\\U000e0067\\u0a47\\u00b7",
+ "\\u1fcd\\u002c\\u07aa\\u0027\\u11b0",
+ "\\u002c\\U000e003c\\U0001d7f4\\u003a\\u0c6f\\u0027",
+ "\\u0589\\U000e006e\\u0a42\\U000104a5",
+ "\\u4f66\\ub523\\u003a\\uacae\\U000e0047\\u003a",
+ "\\u003a\\u0f21\\u0668\\u0dab\\u003a\\u0655\\u00b7",
+ "\\u0027\\u11af\\U000e0057\\u0602",
+ "\\U0001d7f2\\U000e007\\u0004\\u0589",
+ "\\U000e0022\\u003a\\u10b3\\u003a\\ua21b\\u002e\\U000e0058\\u1732\\U000e002b",
+ "\\U0001d7f2\\U000e007d\\u0004\\u0589",
+ "\\u82ab\\u17e8\\u0736\\u2019\\U0001d64d",
+ "\\u0e01\\ub55c\\u0a68\\U000e0037\\u0cd6\\u002c\\ub959",
+ "\\U000e0065\\u302c\\uc986\\u09ee\\U000e0068",
+ "\\u0be8\\u002e\\u0c68\\u066e\\u136d\\ufc99\\u59e7",
+ "\\u0233\\U000e0020\\u0a69\\u0d6a",
+ "\\u206f\\u0741\\ub3ab\\u2019\\ubcac\\u2019",
+ "\\u58f4\\U000e0049\\u20e7\\u2027",
+ "\\ub315\\U0001d7e5\\U000e0073\\u0c47\\u06f2\\u0c6a\\u0037\\u10fe",
+ "\\ua183\\u102d\\u0bec\\u003a",
+ "\\u17e8\\u06e7\\u002e\\u096d\\u003b",
+ "\\u003a\\u0e57\\u0fad\\u002e",
+ "\\u002e\\U000e004c\\U0001d7ea\\u05bb\\ud0fd\\u02de",
+ "\\u32e6\\U0001d7f6\\u0fa1\\u206a\\U000e003c\\u0cec\\u003a",
+ "\\U000e005d\\u2044\\u0731\\u0650\\u0061",
+ "\\u003a\\u0664\\u00b7\\u1fba",
+ "\\u003b\\u0027\\u00b7\\u47a3",
+ "\\u2027\\U000e0067\\u0a42\\u00b7\\ubddf\\uc26c\\u003a\\u4186\\u041b",
+ "\\u0027\\u003a\\U0001d70f\\U0001d7df\\ubf4a\\U0001d7f5\\U0001d177\\u003a\\u0e51\\u1058\\U000e0058\\u00b7\\u0673",
+ "\\uc30d\\u002e\\U000e002c\\u0c48\\u003a\\ub5a1\\u0661\\u002c",
+ };
+ int loop;
+ if (U_FAILURE(status)) {
+ errln("Creation of break iterator failed %s", u_errorName(status));
+ return;
+ }
+ for (loop = 0; loop < (int)(sizeof(strlist) / sizeof(char *)); loop ++) {
+ // printf("looping %d\n", loop);
+ u_unescape(strlist[loop], str, 25);
+ UnicodeString ustr(str);
+ // RBBICharMonkey monkey;
+ RBBIWordMonkey monkey;
+
+ int expected[50];
+ int expectedcount = 0;
+
+ monkey.setText(ustr);
+ int i;
+ for (i = 0; i != BreakIterator::DONE; i = monkey.next(i)) {
+ expected[expectedcount ++] = i;
+ }
+
+ testBreakBoundPreceding(this, ustr, bi, expected, expectedcount);
+ }
+ delete bi;
+#endif
+}
+
+void RBBITest::TestWordBoundary(void)
+{
+ // <data><>\u1d4a\u206e<?>\u0603\U0001d7ff<>\u2019<></data>
+ Locale locale("en");
+ UErrorCode status = U_ZERO_ERROR;
+ // BreakIterator *bi = BreakIterator::createCharacterInstance(locale, status);
+ BreakIterator *bi = BreakIterator::createWordInstance(locale, status);
+ UChar str[50];
+ static const char *strlist[] =
+ {
+ "\\u200e\\U000e0072\\u0a4b\\U000e003f\\ufd2b\\u2027\\u002e\\u002e",
+ "\\U000e0042\\u002e\\u0fb8\\u09ef\\u0ed1\\u2044",
+ "\\u003b\\u024a\\u102e\\U000e0071\\u0600",
+ "\\u2027\\U000e0067\\u0a47\\u00b7",
+ "\\u1fcd\\u002c\\u07aa\\u0027\\u11b0",
+ "\\u002c\\U000e003c\\U0001d7f4\\u003a\\u0c6f\\u0027",
+ "\\u0589\\U000e006e\\u0a42\\U000104a5",
+ "\\u4f66\\ub523\\u003a\\uacae\\U000e0047\\u003a",
+ "\\u003a\\u0f21\\u0668\\u0dab\\u003a\\u0655\\u00b7",
+ "\\u0027\\u11af\\U000e0057\\u0602",
+ "\\U0001d7f2\\U000e007\\u0004\\u0589",
+ "\\U000e0022\\u003a\\u10b3\\u003a\\ua21b\\u002e\\U000e0058\\u1732\\U000e002b",
+ "\\U0001d7f2\\U000e007d\\u0004\\u0589",
+ "\\u82ab\\u17e8\\u0736\\u2019\\U0001d64d",
+ "\\u0e01\\ub55c\\u0a68\\U000e0037\\u0cd6\\u002c\\ub959",
+ "\\U000e0065\\u302c\\uc986\\u09ee\\U000e0068",
+ "\\u0be8\\u002e\\u0c68\\u066e\\u136d\\ufc99\\u59e7",
+ "\\u0233\\U000e0020\\u0a69\\u0d6a",
+ "\\u206f\\u0741\\ub3ab\\u2019\\ubcac\\u2019",
+ "\\u58f4\\U000e0049\\u20e7\\u2027",
+ "\\ub315\\U0001d7e5\\U000e0073\\u0c47\\u06f2\\u0c6a\\u0037\\u10fe",
+ "\\ua183\\u102d\\u0bec\\u003a",
+ "\\u17e8\\u06e7\\u002e\\u096d\\u003b",
+ "\\u003a\\u0e57\\u0fad\\u002e",
+ "\\u002e\\U000e004c\\U0001d7ea\\u05bb\\ud0fd\\u02de",
+ "\\u32e6\\U0001d7f6\\u0fa1\\u206a\\U000e003c\\u0cec\\u003a",
+ "\\ua2a5\\u0038\\u2044\\u002e\\u0c67\\U000e003c\\u05f4\\u2027\\u05f4\\u2019",
+ "\\u003a\\u0664\\u00b7\\u1fba",
+ "\\u003b\\u0027\\u00b7\\u47a3",
+ };
+ int loop;
+ if (U_FAILURE(status)) {
+ errln("Creation of break iterator failed %s", u_errorName(status));
+ return;
+ }
+ for (loop = 0; loop < (int)(sizeof(strlist) / sizeof(char *)); loop ++) {
+ // printf("looping %d\n", loop);
+ u_unescape(strlist[loop], str, 20);
+ UnicodeString ustr(str);
+ int forward[50];
+ int count = 0;
+
+ bi->setText(ustr);
+ int prev = 0;
+ int i;
+ for (i = bi->first(); i != BreakIterator::DONE; i = bi->next()) {
+ forward[count ++] = i;
+ if (i > prev) {
+ int j;
+ for (j = prev + 1; j < i; j ++) {
+ if (bi->isBoundary(j)) {
+ printStringBreaks(ustr, forward, count);
+ errln("happy boundary test failed: expected %d not a boundary",
+ j);
+ return;
+ }
+ }
+ }
+ if (!bi->isBoundary(i)) {
+ printStringBreaks(ustr, forward, count);
+ errln("happy boundary test failed: expected %d a boundary",
+ i);
+ return;
+ }
+ prev = i;
+ }
+ }
+ delete bi;
+}
+
+void RBBITest::TestLineBreaks(void)
+{
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+ Locale locale("en");
+ UErrorCode status = U_ZERO_ERROR;
+ BreakIterator *bi = BreakIterator::createLineInstance(locale, status);
+ const int32_t STRSIZE = 50;
+ UChar str[STRSIZE];
+ static const char *strlist[] =
+ {
+ "\\u300f\\ufdfc\\ub798\\u2011\\u2011\\u0020\\u0b43\\u002d\\ubeec\\ufffc",
+ "\\u24ba\\u2060\\u3405\\ub290\\u000d\\U000e0032\\ufe35\\u00a0\\u0361\\"
+ "U000112ed\\u0f0c\\u000a\\u308e\\ua875\\u0085\\u114d",
+ "\\ufffc\\u3063\\u2e08\\u30e3\\u000d\\u002d\\u0ed8\\u002f\\U00011a57\\"
+ "u2014\\U000e0105\\u118c\\u000a\\u07f8",
+ "\\u0668\\u192b\\u002f\\u2034\\ufe39\\u00b4\\u0cc8\\u2571\\u200b\\u003f",
+ "\\ufeff\\ufffc\\u3289\\u0085\\u2772\\u0020\\U000e010a\\u0020\\u2025\\u000a\\U000e0123",
+ "\\ufe3c\\u201c\\u000d\\u2025\\u2007\\u201c\\u002d\\u20a0\\u002d\\u30a7\\u17a4",
+ "\\u2772\\u0020\\U000e010a\\u0020\\u2025\\u000a\\U000e0123",
+ "\\u002d\\uff1b\\u02c8\\u2029\\ufeff\\u0f22\\u2044\\ufe09\\u003a\\u096d\\u2009\\u000a\\u06f7\\u02cc\\u1019\\u2060",
+ "\\u1781\\u0b68\\u0f0c\\u3010\\u0085\\U00011f7a\\u0020\\u0dd6\\u200b\\U000e007a\\u000a\\u2060\\u2026\\u002f\\u2026\\u24dc\\u101e\\u2014\\u2007\\u30a5",
+ "\\u2770\\u0020\\U000e010f\\u0020\\u2060\\u000a\\u02cc\\u0bcc\\u060d\\u30e7\\u0f3b\\u002f",
+ "\\ufeff\\u0028\\u003b\\U00012fec\\u2010\\u0020\\u0004\\u200b\\u0020\\u275c\\u002f\\u17b1",
+ "\\u20a9\\u2014\\u00a2\\u31f1\\u002f\\u0020\\u05b8\\u200b\\u0cc2\\u003b\\u060d\\u02c8\\ua4e8\\u002f\\u17d5",
+ "\\u002d\\u136f\\uff63\\u0084\\ua933\\u2028\\u002d\\u431b\\u200b\\u20b0",
+ "\\uade3\\u11d6\\u000a\\U0001107d\\u203a\\u201d\\ub070\\u000d\\u2024\\ufffc",
+ "\\uff5b\\u101c\\u1806\\u002f\\u2213\\uff5f",
+ "\\u2014\\u0a83\\ufdfc\\u003f\\u00a0\\u0020\\u000a\\u2991\\U0001d179\\u0020\\u201d\\U000125f6\\u0a67\\u20a7\\ufeff\\u043f",
+ "\\u169b\\U000e0130\\u002d\\u1041\\u0f3d\\u0abf\\u00b0\\u31fb\\u00a0\\u002d\\u02c8\\u003b",
+ "\\u2762\\u1680\\u002d\\u2028\\u0027\\u01dc\\ufe56\\u003a\\u000a\\uffe6\\u29fd\\u0020\\u30ee\\u007c\\U0001d178\\u0af1\\u0085",
+ "\\u3010\\u200b\\u2029\\ufeff\\ufe6a\\u275b\\U000e013b\\ufe37\\u24d4\\u002d\\u1806\\u256a\\u1806\\u247c\\u0085\\u17ac",
+ "\\u99ab\\u0027\\u003b\\u2026\\ueaf0\\u0020\\u0020\\u0313\\u0020\\u3099\\uff09\\u208e\\u2011\\u2007\\u2060\\u000a\\u0020\\u0020\\u300b\\u0bf9",
+ "\\u1806\\u060d\\u30f5\\u00b4\\u17e9\\u2544\\u2028\\u2024\\u2011\\u20a3\\u002d\\u09cc\\u1782\\u000d\\uff6f\\u0025",
+ "\\u002f\\uf22e\\u1944\\ufe3d\\u0020\\u206f\\u31b3\\u2014\\u002d\\u2025\\u0f0c\\u0085\\u2763",
+ "\\u002f\\u2563\\u202f\\u0085\\u17d5\\u200b\\u0020\\U000e0043\\u2014\\u058a\\u3d0a\\ufe57\\u2035\\u2028\\u2029",
+ "\\u20ae\\U0001d169\\u9293\\uff1f\\uff1f\\u0021\\u2012\\u2039\\u0085\\u02cc\\u00a2\\u0020\\U000e01ab\\u3085\\u0f3a\\u1806\\u0f0c\\u1945\\u000a\\U0001d7e7",
+ "\\uffe6\\u00a0\\u200b\\u0085\\u2116\\u255b\\U0001d7f7\\u178c\\ufffc",
+ "\\u02cc\\ufe6a\\u00a0\\u0021\\u002d\\u7490\\uec2e\\u200b\\u000a",
+ "\\uec2e\\u200b\\u000a\\u0020\\u2028\\u2014\\u8945",
+ "\\u7490\\uec2e\\u200b\\u000a\\u0020\\u2028\\u2014",
+ "\\u0020\\u2028\\u2014\\u8945\\u002c\\u005b",
+ "\\u000a\\ufe3c\\u201c\\u000d\\u2025\\u2007\\u201c\\u002d\\u20a0",
+ "\\u2473\\u0e9d\\u0020\\u0085\\u000a\\ufe3c\\u201c\\u000d\\u2025",
+ "\\U0001d16e\\ufffc\\u2025\\u0021\\u002d",
+ "\\ufffc\\u301b\\u0fa5\\U000e0103\\u2060\\u208e\\u17d5\\u034f\\u1009\\u003a\\u180e\\u2009\\u3111",
+ "\\u2014\\u0020\\u000a\\u17c5\\u24fc",
+ "\\ufffc\\u0020\\u2116\\uff6c\\u200b\\u0ac3\\U0001028f",
+ "\\uaeb0\\u0344\\u0085\\ufffc\\u073b\\u2010",
+ "\\ufeff\\u0589\\u0085\\u0eb8\\u30fd\\u002f\\u003a\\u2014\\ufe43",
+ "\\u09cc\\u256a\\u276d\\u002d\\u3085\\u000d\\u0e05\\u2028\\u0fbb",
+ "\\u2034\\u00bb\\u0ae6\\u300c\\u0020\\u31f8\\ufffc",
+ "\\u2116\\u0ed2\\uff64\\u02cd\\u2001\\u2060",
+ "\\u809d\\u2e02\\u0f0a\\uc48f\\u2540\\u000d\\u0cef\\u003a\\u0e4d"
+ "\\U000e0172\\U000e005c\\u17cf\\U00010ca6\\ufeff\\uf621\\u06f3\\uffe5"
+ "\\u0ea2\\ufeff\\udcea\\u3085\\ua874\\u000a\\u0020\\u000b\\u200b",
+ "\\ufe10\\u2060\\u1a5a\\u2060\\u17e4\\ufffc\\ubbe1\\ufe15\\u0020\\u00a0",
+ "\\u2060\\u2213\\u200b\\u2019\\uc2dc\\uff6a\\u1736\\u0085\\udb07",
+ };
+ int loop;
+ TEST_ASSERT_SUCCESS(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ for (loop = 0; loop < (int)(sizeof(strlist) / sizeof(char *)); loop ++) {
+ // printf("looping %d\n", loop);
+ int32_t t = u_unescape(strlist[loop], str, STRSIZE);
+ if (t >= STRSIZE) {
+ TEST_ASSERT(FALSE);
+ continue;
+ }
+
+
+ UnicodeString ustr(str);
+ RBBILineMonkey monkey;
+ if (U_FAILURE(monkey.deferredStatus)) {
+ continue;
+ }
+
+ const int EXPECTEDSIZE = 50;
+ int expected[EXPECTEDSIZE];
+ int expectedcount = 0;
+
+ monkey.setText(ustr);
+ int i;
+ for (i = 0; i != BreakIterator::DONE; i = monkey.next(i)) {
+ if (expectedcount >= EXPECTEDSIZE) {
+ TEST_ASSERT(expectedcount < EXPECTEDSIZE);
+ return;
+ }
+ expected[expectedcount ++] = i;
+ }
+
+ testBreakBoundPreceding(this, ustr, bi, expected, expectedcount);
+ }
+ delete bi;
+#endif
+}
+
+void RBBITest::TestSentBreaks(void)
+{
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+ Locale locale("en");
+ UErrorCode status = U_ZERO_ERROR;
+ BreakIterator *bi = BreakIterator::createSentenceInstance(locale, status);
+ UChar str[200];
+ static const char *strlist[] =
+ {
+ "Now\ris\nthe\r\ntime\n\rfor\r\r",
+ "This\n",
+ "Hello! how are you? I'am fine. Thankyou. How are you doing? This\n costs $20,00,000.",
+ "\"Sentence ending with a quote.\" Bye.",
+ " (This is it). Testing the sentence iterator. \"This isn't it.\"",
+ "Hi! This is a simple sample sentence. (This is it.) This is a simple sample sentence. \"This isn't it.\"",
+ "Hi! This is a simple sample sentence. It does not have to make any sense as you can see. ",
+ "Nel mezzo del cammin di nostra vita, mi ritrovai in una selva oscura. ",
+ "Che la dritta via aveo smarrita. He said, that I said, that you said!! ",
+ "Don't rock the boat.\\u2029Because I am the daddy, that is why. Not on my time (el timo.)!",
+ "\\U0001040a\\u203a\\u1217\\u2b23\\u000d\\uff3b\\u03dd\\uff57\\u0a69\\u104a\\ufe56\\ufe52"
+ "\\u3016\\U000e002f\\U000e0077\\u0662\\u1680\\u2984\\U000e006a\\u002e\\ua6ab\\u104a"
+ "\\u002e\\u019b\\u2005\\u002e\\u0477\\u0438\\u0085\\u0441\\u002e\\u5f61\\u202f"
+ "\\U0001019f\\uff08\\u27e8\\u055c\\u0352",
+ "\\u1f3e\\u004d\\u000a\\ua3e4\\U000e0023\\uff63\\u0c52\\u276d\\U0001d5de\\U0001d171"
+ "\\u0e38\\u17e5\\U00012fe6\\u0fa9\\u267f\\u1da3\\u0046\\u03ed\\udc72\\u0030"
+ "\\U0001d688\\u0b6d\\u0085\\u0c67\\u1f94\\u0c6c\\u9cb2\\u202a\\u180e\\u000b"
+ "\\u002e\\U000e005e\\u035b\\u061f\\u02c1\\U000e0025\\u0357\\u0969\\u202b"
+ "\\U000130c5\\u0486\\U000e0123\\u2019\\u01bc\\u2006\\u11ad\\u180e\\u2e05"
+ "\\u10b7\\u013e\\u000a\\u002e\\U00013ea4"
+ };
+ int loop;
+ if (U_FAILURE(status)) {
+ errln("Creation of break iterator failed %s", u_errorName(status));
+ return;
+ }
+ for (loop = 0; loop < (int)(sizeof(strlist) / sizeof(char *)); loop ++) {
+ u_unescape(strlist[loop], str, (int32_t)(sizeof(str) / sizeof(str[0])));
+ UnicodeString ustr(str);
+
+ RBBISentMonkey monkey;
+ if (U_FAILURE(monkey.deferredStatus)) {
+ continue;
+ }
+
+ const int EXPECTEDSIZE = 50;
+ int expected[EXPECTEDSIZE];
+ int expectedcount = 0;
+
+ monkey.setText(ustr);
+ int i;
+ for (i = 0; i != BreakIterator::DONE; i = monkey.next(i)) {
+ if (expectedcount >= EXPECTEDSIZE) {
+ TEST_ASSERT(expectedcount < EXPECTEDSIZE);
+ return;
+ }
+ expected[expectedcount ++] = i;
+ }
+
+ testBreakBoundPreceding(this, ustr, bi, expected, expectedcount);
+ }
+ delete bi;
+#endif
+}
+
+void RBBITest::TestMonkey(char *params) {
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t loopCount = 500;
+ int32_t seed = 1;
+ UnicodeString breakType = "all";
+ Locale locale("en");
+ UBool useUText = FALSE;
+
+ if (quick == FALSE) {
+ loopCount = 10000;
+ }
+
+ if (params) {
+ UnicodeString p(params);
+ loopCount = getIntParam("loop", p, loopCount);
+ seed = getIntParam("seed", p, seed);
+
+ RegexMatcher m(" *type *= *(char|word|line|sent|title) *", p, 0, status);
+ if (m.find()) {
+ breakType = m.group(1, status);
+ m.reset();
+ p = m.replaceFirst("", status);
+ }
+
+ RegexMatcher u(" *utext", p, 0, status);
+ if (u.find()) {
+ useUText = TRUE;
+ u.reset();
+ p = u.replaceFirst("", status);
+ }
+
+
+ // m.reset(p);
+ if (RegexMatcher("\\S", p, 0, status).find()) {
+ // Each option is stripped out of the option string as it is processed.
+ // All options have been checked. The option string should have been completely emptied..
+ char buf[100];
+ p.extract(buf, sizeof(buf), NULL, status);
+ buf[sizeof(buf)-1] = 0;
+ errln("Unrecognized or extra parameter: %s\n", buf);
+ return;
+ }
+
+ }
+
+ if (breakType == "char" || breakType == "all") {
+ RBBICharMonkey m;
+ BreakIterator *bi = BreakIterator::createCharacterInstance(locale, status);
+ if (U_SUCCESS(status)) {
+ RunMonkey(bi, m, "char", seed, loopCount, useUText);
+ if (breakType == "all" && useUText==FALSE) {
+ // Also run a quick test with UText when "all" is specified
+ RunMonkey(bi, m, "char", seed, loopCount, TRUE);
+ }
+ }
+ else {
+ errln("Creation of character break iterator failed %s", u_errorName(status));
+ }
+ delete bi;
+ }
+
+ if (breakType == "word" || breakType == "all") {
+ logln("Word Break Monkey Test");
+ RBBIWordMonkey m;
+ BreakIterator *bi = BreakIterator::createWordInstance(locale, status);
+ if (U_SUCCESS(status)) {
+ RunMonkey(bi, m, "word", seed, loopCount, useUText);
+ }
+ else {
+ errln("Creation of word break iterator failed %s", u_errorName(status));
+ }
+ delete bi;
+ }
+
+ if (breakType == "line" || breakType == "all") {
+ logln("Line Break Monkey Test");
+ RBBILineMonkey m;
+ BreakIterator *bi = BreakIterator::createLineInstance(locale, status);
+ if (loopCount >= 10) {
+ loopCount = loopCount / 5; // Line break runs slower than the others.
+ }
+ if (U_SUCCESS(status)) {
+ RunMonkey(bi, m, "line", seed, loopCount, useUText);
+ }
+ else {
+ errln("Creation of line break iterator failed %s", u_errorName(status));
+ }
+ delete bi;
+ }
+
+ if (breakType == "sent" || breakType == "all" ) {
+ logln("Sentence Break Monkey Test");
+ RBBISentMonkey m;
+ BreakIterator *bi = BreakIterator::createSentenceInstance(locale, status);
+ if (loopCount >= 10) {
+ loopCount = loopCount / 10; // Sentence runs slower than the other break types
+ }
+ if (U_SUCCESS(status)) {
+ RunMonkey(bi, m, "sentence", seed, loopCount, useUText);
+ }
+ else {
+ errln("Creation of line break iterator failed %s", u_errorName(status));
+ }
+ delete bi;
+ }
+
+#endif
+}
+
+//
+// Run a RBBI monkey test. Common routine, for all break iterator types.
+// Parameters:
+// bi - the break iterator to use
+// mk - MonkeyKind, abstraction for obtaining expected results
+// name - Name of test (char, word, etc.) for use in error messages
+// seed - Seed for starting random number generator (parameter from user)
+// numIterations
+//
+void RBBITest::RunMonkey(BreakIterator *bi, RBBIMonkeyKind &mk, const char *name, uint32_t seed,
+ int32_t numIterations, UBool useUText) {
+
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+ const int32_t TESTSTRINGLEN = 500;
+ UnicodeString testText;
+ int32_t numCharClasses;
+ UVector *chClasses;
+ int expected[TESTSTRINGLEN*2 + 1];
+ int expectedCount = 0;
+ char expectedBreaks[TESTSTRINGLEN*2 + 1];
+ char forwardBreaks[TESTSTRINGLEN*2 + 1];
+ char reverseBreaks[TESTSTRINGLEN*2+1];
+ char isBoundaryBreaks[TESTSTRINGLEN*2+1];
+ char followingBreaks[TESTSTRINGLEN*2+1];
+ char precedingBreaks[TESTSTRINGLEN*2+1];
+ int i;
+ int loopCount = 0;
+
+ m_seed = seed;
+
+ numCharClasses = mk.charClasses()->size();
+ chClasses = mk.charClasses();
+
+ // Check for errors that occured during the construction of the MonkeyKind object.
+ // Can't report them where they occured because errln() is a method coming from intlTest,
+ // and is not visible outside of RBBITest :-(
+ if (U_FAILURE(mk.deferredStatus)) {
+ errln("status of \"%s\" in creation of RBBIMonkeyKind.", u_errorName(mk.deferredStatus));
+ return;
+ }
+
+ // Verify that the character classes all have at least one member.
+ for (i=0; i<numCharClasses; i++) {
+ UnicodeSet *s = (UnicodeSet *)chClasses->elementAt(i);
+ if (s == NULL || s->size() == 0) {
+ errln("Character Class #%d is null or of zero size.", i);
+ return;
+ }
+ }
+
+ while (loopCount < numIterations || numIterations == -1) {
+ if (numIterations == -1 && loopCount % 10 == 0) {
+ // If test is running in an infinite loop, display a periodic tic so
+ // we can tell that it is making progress.
+ fprintf(stderr, ".");
+ }
+ // Save current random number seed, so that we can recreate the random numbers
+ // for this loop iteration in event of an error.
+ seed = m_seed;
+
+ // Populate a test string with data.
+ testText.truncate(0);
+ for (i=0; i<TESTSTRINGLEN; i++) {
+ int32_t aClassNum = m_rand() % numCharClasses;
+ UnicodeSet *classSet = (UnicodeSet *)chClasses->elementAt(aClassNum);
+ int32_t charIdx = m_rand() % classSet->size();
+ UChar32 c = classSet->charAt(charIdx);
+ if (c < 0) { // TODO: deal with sets containing strings.
+ errln("c < 0");
+ break;
+ }
+ testText.append(c);
+ }
+
+ // Calculate the expected results for this test string.
+ mk.setText(testText);
+ memset(expectedBreaks, 0, sizeof(expectedBreaks));
+ expectedBreaks[0] = 1;
+ int32_t breakPos = 0;
+ expectedCount = 0;
+ for (;;) {
+ breakPos = mk.next(breakPos);
+ if (breakPos == -1) {
+ break;
+ }
+ if (breakPos > testText.length()) {
+ errln("breakPos > testText.length()");
+ }
+ expectedBreaks[breakPos] = 1;
+ U_ASSERT(expectedCount<testText.length());
+ expected[expectedCount ++] = breakPos;
+ }
+
+ // Find the break positions using forward iteration
+ memset(forwardBreaks, 0, sizeof(forwardBreaks));
+ if (useUText) {
+ UErrorCode status = U_ZERO_ERROR;
+ UText *testUText = utext_openReplaceable(NULL, &testText, &status);
+ // testUText = utext_openUnicodeString(testUText, &testText, &status);
+ bi->setText(testUText, status);
+ TEST_ASSERT_SUCCESS(status);
+ utext_close(testUText); // The break iterator does a shallow clone of the UText
+ // This UText can be closed immediately, so long as the
+ // testText string continues to exist.
+ } else {
+ bi->setText(testText);
+ }
+
+ for (i=bi->first(); i != BreakIterator::DONE; i=bi->next()) {
+ if (i < 0 || i > testText.length()) {
+ errln("%s break monkey test: Out of range value returned by breakIterator::next()", name);
+ break;
+ }
+ forwardBreaks[i] = 1;
+ }
+
+ // Find the break positions using reverse iteration
+ memset(reverseBreaks, 0, sizeof(reverseBreaks));
+ for (i=bi->last(); i != BreakIterator::DONE; i=bi->previous()) {
+ if (i < 0 || i > testText.length()) {
+ errln("%s break monkey test: Out of range value returned by breakIterator::next()", name);
+ break;
+ }
+ reverseBreaks[i] = 1;
+ }
+
+ // Find the break positions using isBoundary() tests.
+ memset(isBoundaryBreaks, 0, sizeof(isBoundaryBreaks));
+ U_ASSERT((int32_t)sizeof(isBoundaryBreaks) > testText.length());
+ for (i=0; i<=testText.length(); i++) {
+ isBoundaryBreaks[i] = bi->isBoundary(i);
+ }
+
+
+ // Find the break positions using the following() function.
+ // printf(".");
+ memset(followingBreaks, 0, sizeof(followingBreaks));
+ int32_t lastBreakPos = 0;
+ followingBreaks[0] = 1;
+ for (i=0; i<testText.length(); i++) {
+ breakPos = bi->following(i);
+ if (breakPos <= i ||
+ breakPos < lastBreakPos ||
+ breakPos > testText.length() ||
+ breakPos > lastBreakPos && lastBreakPos > i ) {
+ errln("%s break monkey test: "
+ "Out of range value returned by BreakIterator::following().\n"
+ "Random seed=%d index=%d; following returned %d; lastbreak=%d",
+ name, seed, i, breakPos, lastBreakPos);
+ break;
+ }
+ followingBreaks[breakPos] = 1;
+ lastBreakPos = breakPos;
+ }
+
+ // Find the break positions using the preceding() function.
+ memset(precedingBreaks, 0, sizeof(followingBreaks));
+ lastBreakPos = testText.length();
+ precedingBreaks[testText.length()] = 1;
+ for (i=testText.length(); i>0; i--) {
+ breakPos = bi->preceding(i);
+ if (breakPos >= i ||
+ breakPos > lastBreakPos ||
+ breakPos < 0 && testText.getChar32Start(i)>0 ||
+ breakPos < lastBreakPos && lastBreakPos < testText.getChar32Start(i) ) {
+ errln("%s break monkey test: "
+ "Out of range value returned by BreakIterator::preceding().\n"
+ "index=%d; prev returned %d; lastBreak=%d" ,
+ name, i, breakPos, lastBreakPos);
+ precedingBreaks[i] = 2; // Forces an error.
+ } else {
+ precedingBreaks[breakPos] = 1;
+ lastBreakPos = breakPos;
+ }
+ }
+
+ // Compare the expected and actual results.
+ for (i=0; i<=testText.length(); i++) {
+ const char *errorType = NULL;
+ if (forwardBreaks[i] != expectedBreaks[i]) {
+ errorType = "next()";
+ } else if (reverseBreaks[i] != forwardBreaks[i]) {
+ errorType = "previous()";
+ } else if (isBoundaryBreaks[i] != expectedBreaks[i]) {
+ errorType = "isBoundary()";
+ } else if (followingBreaks[i] != expectedBreaks[i]) {
+ errorType = "following()";
+ } else if (precedingBreaks[i] != expectedBreaks[i]) {
+ errorType = "preceding()";
+ }
+
+
+ if (errorType != NULL) {
+ // Format a range of the test text that includes the failure as
+ // a data item that can be included in the rbbi test data file.
+
+ // Start of the range is the last point where expected and actual results
+ // both agreed that there was a break position.
+ int startContext = i;
+ int32_t count = 0;
+ for (;;) {
+ if (startContext==0) { break; }
+ startContext --;
+ if (expectedBreaks[startContext] != 0) {
+ if (count == 2) break;
+ count ++;
+ }
+ }
+
+ // End of range is two expected breaks past the start position.
+ int endContext = i + 1;
+ int ci;
+ for (ci=0; ci<2; ci++) { // Number of items to include in error text.
+ for (;;) {
+ if (endContext >= testText.length()) {break;}
+ if (expectedBreaks[endContext-1] != 0) {
+ if (count == 0) break;
+ count --;
+ }
+ endContext ++;
+ }
+ }
+
+ // Format looks like "<data>\\\uabcd\uabcd\\\U0001abcd...</data>"
+ UnicodeString errorText = "<data>";
+ /***if (strcmp(errorType, "next()") == 0) {
+ startContext = 0;
+ endContext = testText.length();
+
+ printStringBreaks(testText, expected, expectedCount);
+ }***/
+
+ for (ci=startContext; ci<endContext;) {
+ UnicodeString hexChars("0123456789abcdef");
+ UChar32 c;
+ int bn;
+ c = testText.char32At(ci);
+ if (ci == i) {
+ // This is the location of the error.
+ errorText.append("<?>");
+ } else if (expectedBreaks[ci] != 0) {
+ // This a non-error expected break position.
+ errorText.append("\\");
+ }
+ if (c < 0x10000) {
+ errorText.append("\\u");
+ for (bn=12; bn>=0; bn-=4) {
+ errorText.append(hexChars.charAt((c>>bn)&0xf));
+ }
+ } else {
+ errorText.append("\\U");
+ for (bn=28; bn>=0; bn-=4) {
+ errorText.append(hexChars.charAt((c>>bn)&0xf));
+ }
+ }
+ ci = testText.moveIndex32(ci, 1);
+ }
+ errorText.append("\\");
+ errorText.append("</data>\n");
+
+ // Output the error
+ char charErrorTxt[500];
+ UErrorCode status = U_ZERO_ERROR;
+ errorText.extract(charErrorTxt, sizeof(charErrorTxt), NULL, status);
+ charErrorTxt[sizeof(charErrorTxt)-1] = 0;
+ errln("%s break monkey test error. %s. Operation = %s; Random seed = %d; buf Idx = %d\n%s",
+ name, (expectedBreaks[i]? "break expected but not found" : "break found but not expected"),
+ errorType, seed, i, charErrorTxt);
+ break;
+ }
+ }
+
+ loopCount++;
+ }
+#endif
+}
+
+//
+// TestDebug - A place-holder test for debugging purposes.
+// For putting in fragments of other tests that can be invoked
+// for tracing without a lot of unwanted extra stuff happening.
+//
+void RBBITest::TestDebug(void) {
+#if 0
+ UErrorCode status = U_ZERO_ERROR;
+ int pos = 0;
+ int ruleStatus = 0;
+
+ RuleBasedBreakIterator* bi =
+ // (RuleBasedBreakIterator *)BreakIterator::createLineInstance(Locale::getDefault(), status);
+ // (RuleBasedBreakIterator *)BreakIterator::createWordInstance(Locale::Locale("th"), status);
+ (RuleBasedBreakIterator *)BreakIterator::createSentenceInstance(Locale::getDefault(), status);
+ UnicodeString s("\\u2008\\u002e\\udc6a\\u37cd\\u71d0\\u2048\\U000e006a\\u002e\\u0046\\ufd3f\\u000a\\u002e");
+ // UnicodeString s("Aaa. Bcd");
+ s = s.unescape();
+ bi->setText(s);
+ UBool r = bi->isBoundary(8);
+ printf("%s", r?"true":"false");
+ return;
+ pos = bi->last();
+ do {
+ // ruleStatus = bi->getRuleStatus();
+ printf("%d\t%d\n", pos, ruleStatus);
+ pos = bi->previous();
+ } while (pos != BreakIterator::DONE);
+#endif
+}
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/rbbitst.h b/Build/source/libs/icu/icu-xetex/test/intltest/rbbitst.h
new file mode 100644
index 00000000000..d625c4a42be
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/rbbitst.h
@@ -0,0 +1,130 @@
+/*************************************************************************
+ * Copyright (c) 1999-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *************************************************************************
+ * Date Name Description
+ * 12/15/99 Madhu Creation.
+ * 01/12/2000 Madhu Updated for changed API and added new tests
+ ************************************************************************/
+
+
+#ifndef RBBITEST_H
+#define RBBITEST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+#include "intltest.h"
+#include "unicode/brkiter.h"
+
+
+class Enumeration;
+class BITestData;
+struct TestParams;
+class RBBIMonkeyKind;
+
+U_NAMESPACE_BEGIN
+class UVector32;
+U_NAMESPACE_END
+
+/**
+ * Test the RuleBasedBreakIterator class giving different rules
+ */
+class RBBITest: public IntlTest {
+public:
+
+ RBBITest();
+ virtual ~RBBITest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ /**
+ * Tests rule status return values
+ **/
+ void TestStatusReturn();
+
+ void TestEmptyString();
+ void TestGetAvailableLocales();
+ void TestGetDisplayName();
+ void TestEndBehaviour();
+ void TestBug4153072();
+ void TestJapaneseLineBreak();
+ void TestThaiLineBreak();
+ void TestMixedThaiLineBreak();
+ void TestMaiyamok();
+ void TestMonkey(char *params);
+
+ void TestExtended();
+ UChar *ReadAndConvertFile(const char *fileName, int &ulen, const char *encoding, UErrorCode &status);
+ void executeTest(TestParams *);
+
+ void TestWordBreaks();
+ void TestWordBoundary();
+ void TestLineBreaks();
+ void TestSentBreaks();
+ void TestBug3818();
+ void TestJapaneseWordBreak();
+ void TestTrieDict();
+ void TestUnicodeFiles();
+ void TestBug5775();
+
+ void TestDebug();
+
+
+/***********************/
+private:
+ /**
+ * internal methods to prepare test data
+ **/
+
+ /**
+ * Perform tests of BreakIterator forward and backward functionality
+ * on different kinds of iterators (word, sentence, line and character).
+ * It tests the methods first(), next(), current(), preceding(), following()
+ * previous() and isBoundary().
+ * It makes use of internal functions to achieve this.
+ **/
+ void generalIteratorTest(RuleBasedBreakIterator& bi, BITestData &td);
+ /**
+ * Internal method to perform iteration and test the first() and next() functions
+ **/
+ void testFirstAndNext(RuleBasedBreakIterator& bi, BITestData &td);
+ /**
+ * Internal method to perform iteration and test the last() and previous() functions
+ **/
+ void testLastAndPrevious(RuleBasedBreakIterator& bi, BITestData &td);
+ /**
+ * Internal method to perform iteration and test the following() function
+ **/
+ void testFollowing(RuleBasedBreakIterator& bi, BITestData &td);
+ /**
+ * Internal method to perform iteration and test the preceding() function
+ **/
+ void testPreceding(RuleBasedBreakIterator& bi, BITestData &td);
+ /**
+ * Internal method to perform iteration and test the isBoundary() function
+ **/
+ void testIsBoundary(RuleBasedBreakIterator& bi, BITestData &td);
+ /**
+ * Internal method to perform tests of BreakIterator multiple selection functionality
+ * on different kinds of iterators (word, sentence, line and character)
+ **/
+ void doMultipleSelectionTest(RuleBasedBreakIterator& iterator, BITestData &td);
+
+ void RunMonkey(BreakIterator *bi, RBBIMonkeyKind &mk, const char *name, uint32_t seed,
+ int32_t loopCount, UBool useUText);
+
+ // Run one of the Unicode Consortium boundary test data files.
+ void runUnicodeTestData(const char *fileName, RuleBasedBreakIterator *bi);
+
+ // Run a single test case from one of the Unicode Consortium test files.
+ void checkUnicodeTestCase(const char *testFileName, int lineNumber,
+ const UnicodeString &testString,
+ UVector32 *breakPositions,
+ RuleBasedBreakIterator *bi);
+};
+
+#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/regcoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/regcoll.cpp
new file mode 100644
index 00000000000..074f678be24
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/regcoll.cpp
@@ -0,0 +1,1215 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/unistr.h"
+#include "unicode/sortkey.h"
+#include "regcoll.h"
+#include "sfwdchit.h"
+
+#define ARRAY_LENGTH(array) ((int32_t)(sizeof array / sizeof array[0]))
+
+CollationRegressionTest::CollationRegressionTest()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ en_us = (RuleBasedCollator *)Collator::createInstance(Locale::getUS(), status);
+ if(U_FAILURE(status)) {
+ delete en_us;
+ en_us = 0;
+ errln("Collator creation failed with %s", u_errorName(status));
+ return;
+ }
+}
+
+CollationRegressionTest::~CollationRegressionTest()
+{
+ delete en_us;
+}
+
+
+ // @bug 4048446
+//
+// CollationElementIterator.reset() doesn't work
+//
+void CollationRegressionTest::Test4048446(/* char* par */)
+{
+ const UnicodeString test1 = "XFILE What subset of all possible test cases has the highest probability of detecting the most errors?";
+ const UnicodeString test2 = "Xf_ile What subset of all possible test cases has the lowest probability of detecting the least errors?";
+ CollationElementIterator *i1 = en_us->createCollationElementIterator(test1);
+ CollationElementIterator *i2 = en_us->createCollationElementIterator(test1);
+ UErrorCode status = U_ZERO_ERROR;
+
+ if (i1 == NULL|| i2 == NULL)
+ {
+ errln("Could not create CollationElementIterator's");
+ delete i1;
+ delete i2;
+ return;
+ }
+
+ while (i1->next(status) != CollationElementIterator::NULLORDER)
+ {
+ if (U_FAILURE(status))
+ {
+ errln("error calling next()");
+
+ delete i1;
+ delete i2;
+ return;
+ }
+ }
+
+ i1->reset();
+
+ assertEqual(*i1, *i2);
+
+ delete i1;
+ delete i2;
+}
+
+// @bug 4051866
+//
+// Collator -> rules -> Collator round-trip broken for expanding characters
+//
+void CollationRegressionTest::Test4051866(/* char* par */)
+{
+/*
+ RuleBasedCollator c1 = new RuleBasedCollator("< o "
+ +"& oe ,o\u3080"
+ +"& oe ,\u1530 ,O"
+ +"& OE ,O\u3080"
+ +"& OE ,\u1520"
+ +"< p ,P");
+*/
+
+ UnicodeString rules;
+ UErrorCode status = U_ZERO_ERROR;
+
+ rules += "< o ";
+ rules += "& oe ,o";
+ rules += (UChar)0x3080;
+ rules += "& oe ,";
+ rules += (UChar)0x1530;
+ rules += " ,O";
+ rules += "& OE ,O";
+ rules += (UChar)0x3080;
+ rules += "& OE ,";
+ rules += (UChar)0x1520;
+ rules += "< p ,P";
+
+ // Build a collator containing expanding characters
+ RuleBasedCollator *c1 = new RuleBasedCollator(rules, status);
+
+ // Build another using the rules from the first
+ RuleBasedCollator *c2 = new RuleBasedCollator(c1->getRules(), status);
+
+ // Make sure they're the same
+ if (!(c1->getRules() == c2->getRules()))
+ {
+ errln("Rules are not equal");
+ }
+
+ delete c2;
+ delete c1;
+}
+
+// @bug 4053636
+//
+// Collator thinks "black-bird" == "black"
+//
+void CollationRegressionTest::Test4053636(/* char* par */)
+{
+ if (en_us->equals("black_bird", "black"))
+ {
+ errln("black-bird == black");
+ }
+}
+
+// @bug 4054238
+//
+// CollationElementIterator will not work correctly if the associated
+// Collator object's mode is changed
+//
+void CollationRegressionTest::Test4054238(/* char* par */)
+{
+ const UChar chars3[] = {0x61, 0x00FC, 0x62, 0x65, 0x63, 0x6b, 0x20, 0x47, 0x72, 0x00F6, 0x00DF, 0x65, 0x20, 0x4c, 0x00FC, 0x62, 0x63, 0x6b, 0};
+ const UnicodeString test3(chars3);
+ RuleBasedCollator *c = (RuleBasedCollator *) en_us->clone();
+
+ // NOTE: The Java code uses en_us to create the CollationElementIterators
+ // but I'm pretty sure that's wrong, so I've changed this to use c.
+ UErrorCode status = U_ZERO_ERROR;
+ c->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ CollationElementIterator *i1 = c->createCollationElementIterator(test3);
+ delete i1;
+ delete c;
+}
+
+// @bug 4054734
+//
+// Collator::IDENTICAL documented but not implemented
+//
+void CollationRegressionTest::Test4054734(/* char* par */)
+{
+ /*
+ Here's the original Java:
+
+ String[] decomp = {
+ "\u0001", "<", "\u0002",
+ "\u0001", "=", "\u0001",
+ "A\u0001", ">", "~\u0002", // Ensure A and ~ are not compared bitwise
+ "\u00C0", "=", "A\u0300" // Decomp should make these equal
+ };
+
+ String[] nodecomp = {
+ "\u00C0", ">", "A\u0300" // A-grave vs. A combining-grave
+ };
+ */
+
+ static const UChar decomp[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x0001, 0}, {0x3c, 0}, {0x0002, 0},
+ {0x0001, 0}, {0x3d, 0}, {0x0001, 0},
+ {0x41, 0x0001, 0}, {0x3e, 0}, {0x7e, 0x0002, 0},
+ {0x00c0, 0}, {0x3d, 0}, {0x41, 0x0300, 0}
+ };
+
+
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *c = (RuleBasedCollator *) en_us->clone();
+
+ c->setStrength(Collator::IDENTICAL);
+
+ c->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ compareArray(*c, decomp, ARRAY_LENGTH(decomp));
+
+ delete c;
+}
+
+// @bug 4054736
+//
+// Full Decomposition mode not implemented
+//
+void CollationRegressionTest::Test4054736(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *c = (RuleBasedCollator *) en_us->clone();
+
+ c->setStrength(Collator::SECONDARY);
+ c->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+
+ static const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0xFB4F, 0}, {0x3d, 0}, {0x05D0, 0x05DC} // Alef-Lamed vs. Alef, Lamed
+ };
+
+ compareArray(*c, tests, ARRAY_LENGTH(tests));
+
+ delete c;
+}
+
+// @bug 4058613
+//
+// Collator::createInstance() causes an ArrayIndexOutofBoundsException for Korean
+//
+void CollationRegressionTest::Test4058613(/* char* par */)
+{
+ // Creating a default collator doesn't work when Korean is the default
+ // locale
+
+ Locale oldDefault = Locale::getDefault();
+ UErrorCode status = U_ZERO_ERROR;
+
+ Locale::setDefault(Locale::getKorean(), status);
+
+ if (U_FAILURE(status))
+ {
+ errln("Could not set default locale to Locale::KOREAN");
+ return;
+ }
+
+ Collator *c = NULL;
+
+ c = Collator::createInstance("en_US", status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Could not create a Korean collator");
+ Locale::setDefault(oldDefault, status);
+ delete c;
+ return;
+ }
+
+ // Since the fix to this bug was to turn off decomposition for Korean collators,
+ // ensure that's what we got
+ if (c->getAttribute(UCOL_NORMALIZATION_MODE, status) != UCOL_OFF)
+ {
+ errln("Decomposition is not set to NO_DECOMPOSITION for Korean collator");
+ }
+
+ delete c;
+
+ Locale::setDefault(oldDefault, status);
+}
+
+// @bug 4059820
+//
+// RuleBasedCollator.getRules does not return the exact pattern as input
+// for expanding character sequences
+//
+void CollationRegressionTest::Test4059820(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ RuleBasedCollator *c = NULL;
+ UnicodeString rules = "< a < b , c/a < d < z";
+
+ c = new RuleBasedCollator(rules, status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Failure building a collator.");
+ delete c;
+ return;
+ }
+
+ if ( c->getRules().indexOf("c/a") == -1)
+ {
+ errln("returned rules do not contain 'c/a'");
+ }
+
+ delete c;
+}
+
+// @bug 4060154
+//
+// MergeCollation::fixEntry broken for "& H < \u0131, \u0130, i, I"
+//
+void CollationRegressionTest::Test4060154(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString rules;
+
+ rules += "< g, G < h, H < i, I < j, J";
+ rules += " & H < ";
+ rules += (UChar)0x0131;
+ rules += ", ";
+ rules += (UChar)0x0130;
+ rules += ", i, I";
+
+ RuleBasedCollator *c = NULL;
+
+ c = new RuleBasedCollator(rules, status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("failure building collator.");
+ delete c;
+ return;
+ }
+
+ c->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+
+ /*
+ String[] tertiary = {
+ "A", "<", "B",
+ "H", "<", "\u0131",
+ "H", "<", "I",
+ "\u0131", "<", "\u0130",
+ "\u0130", "<", "i",
+ "\u0130", ">", "H",
+ };
+*/
+
+ static const UChar tertiary[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x41, 0}, {0x3c, 0}, {0x42, 0},
+ {0x48, 0}, {0x3c, 0}, {0x0131, 0},
+ {0x48, 0}, {0x3c, 0}, {0x49, 0},
+ {0x0131, 0}, {0x3c, 0}, {0x0130, 0},
+ {0x0130, 0}, {0x3c, 0}, {0x69, 0},
+ {0x0130, 0}, {0x3e, 0}, {0x48, 0}
+ };
+
+ c->setStrength(Collator::TERTIARY);
+ compareArray(*c, tertiary, ARRAY_LENGTH(tertiary));
+
+ /*
+ String[] secondary = {
+ "H", "<", "I",
+ "\u0131", "=", "\u0130",
+ };
+*/
+ static const UChar secondary[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x48, 0}, {0x3c, 0}, {0x49, 0},
+ {0x0131, 0}, {0x3d, 0}, {0x0130, 0}
+ };
+
+ c->setStrength(Collator::PRIMARY);
+ compareArray(*c, secondary, ARRAY_LENGTH(secondary));
+
+ delete c;
+}
+
+// @bug 4062418
+//
+// Secondary/Tertiary comparison incorrect in French Secondary
+//
+void CollationRegressionTest::Test4062418(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ RuleBasedCollator *c = NULL;
+
+ c = (RuleBasedCollator *) Collator::createInstance(Locale::getFrance(), status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create collator for Locale::getFrance()");
+ delete c;
+ return;
+ }
+
+ c->setStrength(Collator::SECONDARY);
+
+/*
+ String[] tests = {
+ "p\u00eache", "<", "p\u00e9ch\u00e9", // Comparing accents from end, p\u00e9ch\u00e9 is greater
+ };
+*/
+ static const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x70, 0x00EA, 0x63, 0x68, 0x65, 0}, {0x3c, 0}, {0x70, 0x00E9, 0x63, 0x68, 0x00E9, 0}
+ };
+
+ compareArray(*c, tests, ARRAY_LENGTH(tests));
+
+ delete c;
+}
+
+// @bug 4065540
+//
+// Collator::compare() method broken if either string contains spaces
+//
+void CollationRegressionTest::Test4065540(/* char* par */)
+{
+ if (en_us->compare("abcd e", "abcd f") == 0)
+ {
+ errln("'abcd e' == 'abcd f'");
+ }
+}
+
+// @bug 4066189
+//
+// Unicode characters need to be recursively decomposed to get the
+// correct result. For example,
+// u1EB1 -> \u0103 + \u0300 -> a + \u0306 + \u0300.
+//
+void CollationRegressionTest::Test4066189(/* char* par */)
+{
+ static const UChar chars1[] = {0x1EB1, 0};
+ static const UChar chars2[] = {0x61, 0x0306, 0x0300, 0};
+ const UnicodeString test1(chars1);
+ const UnicodeString test2(chars2);
+ UErrorCode status = U_ZERO_ERROR;
+
+ // NOTE: The java code used en_us to create the
+ // CollationElementIterator's. I'm pretty sure that
+ // was wrong, so I've change the code to use c1 and c2
+ RuleBasedCollator *c1 = (RuleBasedCollator *) en_us->clone();
+ c1->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ CollationElementIterator *i1 = c1->createCollationElementIterator(test1);
+
+ RuleBasedCollator *c2 = (RuleBasedCollator *) en_us->clone();
+ c2->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_OFF, status);
+ CollationElementIterator *i2 = c2->createCollationElementIterator(test2);
+
+ assertEqual(*i1, *i2);
+
+ delete i2;
+ delete c2;
+ delete i1;
+ delete c1;
+}
+
+// @bug 4066696
+//
+// French secondary collation checking at the end of compare iteration fails
+//
+void CollationRegressionTest::Test4066696(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *c = NULL;
+
+ c = (RuleBasedCollator *)Collator::createInstance(Locale::getFrance(), status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Failure creating collator for Locale::getFrance()");
+ delete c;
+ return;
+ }
+
+ c->setStrength(Collator::SECONDARY);
+
+/*
+ String[] tests = {
+ "\u00e0", "<", "\u01fa", // a-grave < A-ring-acute
+ };
+
+ should be:
+
+ String[] tests = {
+ "\u00e0", ">", "\u01fa", // a-grave < A-ring-acute
+ };
+
+*/
+
+ static const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x00E0, 0}, {0x3e, 0}, {0x01FA, 0}
+ };
+
+ compareArray(*c, tests, ARRAY_LENGTH(tests));
+
+ delete c;
+}
+
+// @bug 4076676
+//
+// Bad canonicalization of same-class combining characters
+//
+void CollationRegressionTest::Test4076676(/* char* par */)
+{
+ // These combining characters are all in the same class, so they should not
+ // be reordered, and they should compare as unequal.
+ static const UChar s1[] = {0x41, 0x0301, 0x0302, 0x0300, 0};
+ static const UChar s2[] = {0x41, 0x0302, 0x0300, 0x0301, 0};
+
+ RuleBasedCollator *c = (RuleBasedCollator *) en_us->clone();
+ c->setStrength(Collator::TERTIARY);
+
+ if (c->compare(s1,s2) == 0)
+ {
+ errln("Same-class combining chars were reordered");
+ }
+
+ delete c;
+}
+
+// @bug 4079231
+//
+// RuleBasedCollator::operator==(NULL) throws NullPointerException
+//
+void CollationRegressionTest::Test4079231(/* char* par */)
+{
+ // I don't think there's any way to write this test
+ // in C++. The following is equivalent to the Java,
+ // but doesn't compile 'cause NULL can't be converted
+ // to Collator&
+ //
+ // if (en_us->operator==(NULL))
+ // {
+ // errln("en_us->operator==(NULL) returned TRUE");
+ // }
+
+ /*
+ try {
+ if (en_us->equals(null)) {
+ errln("en_us->equals(null) returned true");
+ }
+ }
+ catch (Exception e) {
+ errln("en_us->equals(null) threw " + e.toString());
+ }
+*/
+}
+
+// @bug 4078588
+//
+// RuleBasedCollator breaks on "< a < bb" rule
+//
+void CollationRegressionTest::Test4078588(/* char *par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *rbc = new RuleBasedCollator((UnicodeString)"< a < bb", status);
+
+ if (rbc == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create RuleBasedCollator.");
+ delete rbc;
+ return;
+ }
+
+ Collator::EComparisonResult result = rbc->compare("a","bb");
+
+ if (result != Collator::LESS)
+ {
+ errln((UnicodeString)"Compare(a,bb) returned " + (int)result
+ + (UnicodeString)"; expected -1");
+ }
+
+ delete rbc;
+}
+
+// @bug 4081866
+//
+// Combining characters in different classes not reordered properly.
+//
+void CollationRegressionTest::Test4081866(/* char* par */)
+{
+ // These combining characters are all in different classes,
+ // so they should be reordered and the strings should compare as equal.
+ static const UChar s1[] = {0x41, 0x0300, 0x0316, 0x0327, 0x0315, 0};
+ static const UChar s2[] = {0x41, 0x0327, 0x0316, 0x0315, 0x0300, 0};
+
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *c = (RuleBasedCollator *) en_us->clone();
+ c->setStrength(Collator::TERTIARY);
+
+ // Now that the default collators are set to NO_DECOMPOSITION
+ // (as a result of fixing bug 4114077), we must set it explicitly
+ // when we're testing reordering behavior. -- lwerner, 5/5/98
+ c->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+
+ if (c->compare(s1,s2) != 0)
+ {
+ errln("Combining chars were not reordered");
+ }
+
+ delete c;
+}
+
+// @bug 4087241
+//
+// string comparison errors in Scandinavian collators
+//
+void CollationRegressionTest::Test4087241(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Locale da_DK("da", "DK");
+ RuleBasedCollator *c = NULL;
+
+ c = (RuleBasedCollator *) Collator::createInstance(da_DK, status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create collator for da_DK locale");
+ delete c;
+ return;
+ }
+
+ c->setStrength(Collator::SECONDARY);
+
+ static const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x7a, 0}, {0x3c, 0}, {0x00E6, 0}, // z < ae
+ {0x61, 0x0308, 0}, {0x3c, 0}, {0x61, 0x030A, 0}, // a-unlaut < a-ring
+ {0x59, 0}, {0x3c, 0}, {0x75, 0x0308, 0}, // Y < u-umlaut
+ };
+
+ compareArray(*c, tests, ARRAY_LENGTH(tests));
+
+ delete c;
+}
+
+// @bug 4087243
+//
+// CollationKey takes ignorable strings into account when it shouldn't
+//
+void CollationRegressionTest::Test4087243(/* char* par */)
+{
+ RuleBasedCollator *c = (RuleBasedCollator *) en_us->clone();
+ c->setStrength(Collator::TERTIARY);
+
+ static const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x31, 0x32, 0x33, 0}, {0x3d, 0}, {0x31, 0x32, 0x33, 0x0001, 0} // 1 2 3 = 1 2 3 ctrl-A
+ };
+
+ compareArray(*c, tests, ARRAY_LENGTH(tests));
+
+ delete c;
+}
+
+// @bug 4092260
+//
+// Mu/micro conflict
+// Micro symbol and greek lowercase letter Mu should sort identically
+//
+void CollationRegressionTest::Test4092260(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Locale el("el", "");
+ Collator *c = NULL;
+
+ c = Collator::createInstance(el, status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create collator for el locale.");
+ delete c;
+ return;
+ }
+
+ // These now have tertiary differences in UCA
+ c->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, status);
+
+ static const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x00B5, 0}, {0x3d, 0}, {0x03BC, 0}
+ };
+
+ compareArray(*c, tests, ARRAY_LENGTH(tests));
+
+ delete c;
+}
+
+// @bug 4095316
+//
+void CollationRegressionTest::Test4095316(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Locale el_GR("el", "GR");
+ Collator *c = Collator::createInstance(el_GR, status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create collator for el_GR locale");
+ delete c;
+ return;
+ }
+ // These now have tertiary differences in UCA
+ //c->setStrength(Collator::TERTIARY);
+ c->setAttribute(UCOL_STRENGTH, UCOL_SECONDARY, status);
+
+ static const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x03D4, 0}, {0x3d, 0}, {0x03AB, 0}
+ };
+
+ compareArray(*c, tests, ARRAY_LENGTH(tests));
+
+ delete c;
+}
+
+// @bug 4101940
+//
+void CollationRegressionTest::Test4101940(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *c = NULL;
+ UnicodeString rules = "< a < b";
+ UnicodeString nothing = "";
+
+ c = new RuleBasedCollator(rules, status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create RuleBasedCollator");
+ delete c;
+ return;
+ }
+
+ CollationElementIterator *i = c->createCollationElementIterator(nothing);
+ i->reset();
+
+ if (i->next(status) != CollationElementIterator::NULLORDER)
+ {
+ errln("next did not return NULLORDER");
+ }
+
+ delete i;
+ delete c;
+}
+
+// @bug 4103436
+//
+// Collator::compare not handling spaces properly
+//
+void CollationRegressionTest::Test4103436(/* char* par */)
+{
+ RuleBasedCollator *c = (RuleBasedCollator *) en_us->clone();
+ c->setStrength(Collator::TERTIARY);
+
+ static const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x66, 0x69, 0x6c, 0x65, 0}, {0x3c, 0}, {0x66, 0x69, 0x6c, 0x65, 0x20, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0},
+ {0x66, 0x69, 0x6c, 0x65, 0}, {0x3c, 0}, {0x66, 0x69, 0x6c, 0x65, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0}
+ };
+
+ compareArray(*c, tests, ARRAY_LENGTH(tests));
+
+ delete c;
+}
+
+// @bug 4114076
+//
+// Collation not Unicode conformant with Hangul syllables
+//
+void CollationRegressionTest::Test4114076(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *c = (RuleBasedCollator *) en_us->clone();
+ c->setStrength(Collator::TERTIARY);
+
+ //
+ // With Canonical decomposition, Hangul syllables should get decomposed
+ // into Jamo, but Jamo characters should not be decomposed into
+ // conjoining Jamo
+ //
+ static const UChar test1[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0xd4db, 0}, {0x3d, 0}, {0x1111, 0x1171, 0x11b6, 0}
+ };
+
+ c->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ compareArray(*c, test1, ARRAY_LENGTH(test1));
+
+ // From UTR #15:
+ // *In earlier versions of Unicode, jamo characters like ksf
+ // had compatibility mappings to kf + sf. These mappings were
+ // removed in Unicode 2.1.9 to ensure that Hangul syllables are maintained.)
+ // That is, the following test is obsolete as of 2.1.9
+
+//obsolete- // With Full decomposition, it should go all the way down to
+//obsolete- // conjoining Jamo characters.
+//obsolete- //
+//obsolete- static const UChar test2[][CollationRegressionTest::MAX_TOKEN_LEN] =
+//obsolete- {
+//obsolete- {0xd4db, 0}, {0x3d, 0}, {0x1111, 0x116e, 0x1175, 0x11af, 0x11c2, 0}
+//obsolete- };
+//obsolete-
+//obsolete- c->setDecomposition(Normalizer::DECOMP_COMPAT);
+//obsolete- compareArray(*c, test2, ARRAY_LENGTH(test2));
+
+ delete c;
+}
+
+
+// @bug 4124632
+//
+// Collator::getCollationKey was hanging on certain character sequences
+//
+void CollationRegressionTest::Test4124632(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *coll = NULL;
+
+ coll = Collator::createInstance(Locale::getJapan(), status);
+
+ if (coll == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create collator for Locale::JAPAN");
+ delete coll;
+ }
+
+ static const UChar test[] = {0x41, 0x0308, 0x62, 0x63, 0};
+ CollationKey key;
+
+ coll->getCollationKey(test, key, status);
+
+ if (key.isBogus() || U_FAILURE(status))
+ {
+ errln("CollationKey creation failed.");
+ }
+
+ delete coll;
+}
+
+// @bug 4132736
+//
+// sort order of french words with multiple accents has errors
+//
+void CollationRegressionTest::Test4132736(/* char* par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ Collator *c = NULL;
+
+ c = Collator::createInstance(Locale::getFrance(), status);
+ c->setStrength(Collator::TERTIARY);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create a collator for Locale::getFrance()");
+ delete c;
+ }
+
+ static const UChar test1[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x65, 0x0300, 0x65, 0x0301, 0}, {0x3c, 0}, {0x65, 0x0301, 0x65, 0x0300, 0},
+ {0x65, 0x0300, 0x0301, 0}, {0x3c, 0}, {0x65, 0x0301, 0x0300, 0}
+ };
+
+ compareArray(*c, test1, ARRAY_LENGTH(test1));
+
+ delete c;
+}
+
+// @bug 4133509
+//
+// The sorting using java.text.CollationKey is not in the exact order
+//
+void CollationRegressionTest::Test4133509(/* char* par */)
+{
+ static const UChar test1[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0}, {0x3c, 0}, {0x45, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x72, 0x45, 0x72, 0x72, 0x6f, 0x72, 0},
+ {0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0}, {0x3c, 0}, {0x47, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0},
+ {0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0}, {0x3c, 0}, {0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0}
+ };
+
+ compareArray(*en_us, test1, ARRAY_LENGTH(test1));
+}
+
+// @bug 4114077
+//
+// Collation with decomposition off doesn't work for Europe
+//
+void CollationRegressionTest::Test4114077(/* char* par */)
+{
+ // Ensure that we get the same results with decomposition off
+ // as we do with it on....
+
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *c = (RuleBasedCollator *) en_us->clone();
+ c->setStrength(Collator::TERTIARY);
+
+ static const UChar test1[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x00C0, 0}, {0x3d, 0}, {0x41, 0x0300, 0}, // Should be equivalent
+ {0x70, 0x00ea, 0x63, 0x68, 0x65, 0}, {0x3e, 0}, {0x70, 0x00e9, 0x63, 0x68, 0x00e9, 0},
+ {0x0204, 0}, {0x3d, 0}, {0x45, 0x030F, 0},
+ {0x01fa, 0}, {0x3d, 0}, {0x41, 0x030a, 0x0301, 0}, // a-ring-acute -> a-ring, acute
+ // -> a, ring, acute
+ {0x41, 0x0300, 0x0316, 0}, {0x3c, 0}, {0x41, 0x0316, 0x0300, 0} // No reordering --> unequal
+ };
+
+ c->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_OFF, status);
+ compareArray(*c, test1, ARRAY_LENGTH(test1));
+
+ static const UChar test2[][CollationRegressionTest::MAX_TOKEN_LEN] =
+ {
+ {0x41, 0x0300, 0x0316, 0}, {0x3d, 0}, {0x41, 0x0316, 0x0300, 0} // Reordering --> equal
+ };
+
+ c->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ compareArray(*c, test2, ARRAY_LENGTH(test2));
+
+ delete c;
+}
+
+// @bug 4141640
+//
+// Support for Swedish gone in 1.1.6 (Can't create Swedish collator)
+//
+void CollationRegressionTest::Test4141640(/* char* par */)
+{
+ //
+ // Rather than just creating a Swedish collator, we might as well
+ // try to instantiate one for every locale available on the system
+ // in order to prevent this sort of bug from cropping up in the future
+ //
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t i, localeCount;
+ const Locale *locales = Locale::getAvailableLocales(localeCount);
+
+ for (i = 0; i < localeCount; i += 1)
+ {
+ Collator *c = NULL;
+
+ status = U_ZERO_ERROR;
+ c = Collator::createInstance(locales[i], status);
+
+ if (c == NULL || U_FAILURE(status))
+ {
+ UnicodeString msg, localeName;
+
+ msg += "Could not create collator for locale ";
+ msg += locales[i].getName();
+
+ errln(msg);
+ }
+
+ delete c;
+ }
+}
+
+// @bug 4139572
+//
+// getCollationKey throws exception for spanish text
+// Cannot reproduce this bug on 1.2, however it DOES fail on 1.1.6
+//
+void CollationRegressionTest::Test4139572(/* char* par */)
+{
+ //
+ // Code pasted straight from the bug report
+ // (and then translated to C++ ;-)
+ //
+ // create spanish locale and collator
+ UErrorCode status = U_ZERO_ERROR;
+ Locale l("es", "es");
+ Collator *col = NULL;
+
+ col = Collator::createInstance(l, status);
+
+ if (col == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create a collator for es_es locale.");
+ delete col;
+ return;
+ }
+
+ CollationKey key;
+
+ // this spanish phrase kills it!
+ col->getCollationKey("Nombre De Objeto", key, status);
+
+ if (key.isBogus() || U_FAILURE(status))
+ {
+ errln("Error creating CollationKey for \"Nombre De Ojbeto\"");
+ }
+
+ delete col;
+}
+/* HSYS : RuleBasedCollator::compare() performance enhancements
+ compare() does not create CollationElementIterator() anymore.*/
+
+class My4146160Collator : public RuleBasedCollator
+{
+public:
+ My4146160Collator(RuleBasedCollator &rbc, UErrorCode &status);
+ ~My4146160Collator();
+
+ CollationElementIterator *createCollationElementIterator(const UnicodeString &text) const;
+
+ CollationElementIterator *createCollationElementIterator(const CharacterIterator &text) const;
+
+ static int32_t count;
+};
+
+int32_t My4146160Collator::count = 0;
+
+My4146160Collator::My4146160Collator(RuleBasedCollator &rbc, UErrorCode &status)
+ : RuleBasedCollator(rbc.getRules(), status)
+{
+}
+
+My4146160Collator::~My4146160Collator()
+{
+}
+
+CollationElementIterator *My4146160Collator::createCollationElementIterator(const UnicodeString &text) const
+{
+ count += 1;
+ return RuleBasedCollator::createCollationElementIterator(text);
+}
+
+CollationElementIterator *My4146160Collator::createCollationElementIterator(const CharacterIterator &text) const
+{
+ count += 1;
+ return RuleBasedCollator::createCollationElementIterator(text);
+}
+
+// @bug 4146160
+//
+// RuleBasedCollator doesn't use createCollationElementIterator internally
+//
+void CollationRegressionTest::Test4146160(/* char* par */)
+{
+#if 0
+ //
+ // Use a custom collator class whose createCollationElementIterator
+ // methods increment a count....
+ //
+ UErrorCode status = U_ZERO_ERROR;
+ CollationKey key;
+
+ My4146160Collator::count = 0;
+ My4146160Collator *mc = NULL;
+
+ mc = new My4146160Collator(*en_us, status);
+
+ if (mc == NULL || U_FAILURE(status))
+ {
+ errln("Failed to create a My4146160Collator.");
+ delete mc;
+ return;
+ }
+
+ mc->getCollationKey("1", key, status);
+
+ if (key.isBogus() || U_FAILURE(status))
+ {
+ errln("Failure to get a CollationKey from a My4146160Collator.");
+ delete mc;
+ return;
+ }
+
+ if (My4146160Collator::count < 1)
+ {
+ errln("My4146160Collator::createCollationElementIterator not called for getCollationKey");
+ }
+
+ My4146160Collator::count = 0;
+ mc->compare("1", "2");
+
+ if (My4146160Collator::count < 1)
+ {
+ errln("My4146160Collator::createtCollationElementIterator not called for compare");
+ }
+
+ delete mc;
+#endif
+}
+void CollationRegressionTest::compareArray(Collator &c,
+ const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN],
+ int32_t testCount)
+{
+ int32_t i;
+ Collator::EComparisonResult expectedResult = Collator::EQUAL;
+
+ for (i = 0; i < testCount; i += 3)
+ {
+ UnicodeString source(tests[i]);
+ UnicodeString comparison(tests[i + 1]);
+ UnicodeString target(tests[i + 2]);
+
+ if (comparison == "<")
+ {
+ expectedResult = Collator::LESS;
+ }
+ else if (comparison == ">")
+ {
+ expectedResult = Collator::GREATER;
+ }
+ else if (comparison == "=")
+ {
+ expectedResult = Collator::EQUAL;
+ }
+ else
+ {
+ UnicodeString bogus1("Bogus comparison string \"");
+ UnicodeString bogus2("\"");
+ errln(bogus1 + comparison + bogus2);
+ }
+
+ Collator::EComparisonResult compareResult = c.compare(source, target);
+
+ CollationKey sourceKey, targetKey;
+ UErrorCode status = U_ZERO_ERROR;
+
+ c.getCollationKey(source, sourceKey, status);
+
+ if (U_FAILURE(status))
+ {
+ errln("Couldn't get collationKey for source");
+ continue;
+ }
+
+ c.getCollationKey(target, targetKey, status);
+
+ if (U_FAILURE(status))
+ {
+ errln("Couldn't get collationKey for target");
+ continue;
+ }
+
+ Collator::EComparisonResult keyResult = sourceKey.compareTo(targetKey);
+
+ reportCResult( source, target, sourceKey, targetKey, compareResult, keyResult, compareResult, expectedResult );
+
+ }
+}
+
+void CollationRegressionTest::assertEqual(CollationElementIterator &i1, CollationElementIterator &i2)
+{
+ int32_t c1, c2, count = 0;
+ UErrorCode status = U_ZERO_ERROR;
+
+ do
+ {
+ c1 = i1.next(status);
+ c2 = i2.next(status);
+
+ if (c1 != c2)
+ {
+ UnicodeString msg, msg1(" ");
+
+ msg += msg1 + count;
+ msg += ": strength(0x";
+ appendHex(c1, 8, msg);
+ msg += ") != strength(0x";
+ appendHex(c2, 8, msg);
+ msg += ")";
+
+ errln(msg);
+ break;
+ }
+
+ count += 1;
+ }
+ while (c1 != CollationElementIterator::NULLORDER);
+}
+
+void CollationRegressionTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /* par */)
+{
+ if (exec)
+ {
+ logln("Collation Regression Tests: ");
+ }
+
+ if(en_us) {
+ switch (index)
+ {
+ case 0: name = "Test4048446"; if (exec) Test4048446(/* par */); break;
+ case 1: name = "Test4051866"; if (exec) Test4051866(/* par */); break;
+ case 2: name = "Test4053636"; if (exec) Test4053636(/* par */); break;
+ case 3: name = "Test4054238"; if (exec) Test4054238(/* par */); break;
+ case 4: name = "Test4054734"; if (exec) Test4054734(/* par */); break;
+ case 5: name = "Test4054736"; if (exec) Test4054736(/* par */); break;
+ case 6: name = "Test4058613"; if (exec) Test4058613(/* par */); break;
+ case 7: name = "Test4059820"; if (exec) Test4059820(/* par */); break;
+ case 8: name = "Test4060154"; if (exec) Test4060154(/* par */); break;
+ case 9: name = "Test4062418"; if (exec) Test4062418(/* par */); break;
+ case 10: name = "Test4065540"; if (exec) Test4065540(/* par */); break;
+ case 11: name = "Test4066189"; if (exec) Test4066189(/* par */); break;
+ case 12: name = "Test4066696"; if (exec) Test4066696(/* par */); break;
+ case 13: name = "Test4076676"; if (exec) Test4076676(/* par */); break;
+ case 14: name = "Test4078588"; if (exec) Test4078588(/* par */); break;
+ case 15: name = "Test4079231"; if (exec) Test4079231(/* par */); break;
+ case 16: name = "Test4081866"; if (exec) Test4081866(/* par */); break;
+ case 17: name = "Test4087241"; if (exec) Test4087241(/* par */); break;
+ case 18: name = "Test4087243"; if (exec) Test4087243(/* par */); break;
+ case 19: name = "Test4092260"; if (exec) Test4092260(/* par */); break;
+ case 20: name = "Test4095316"; if (exec) Test4095316(/* par */); break;
+ case 21: name = "Test4101940"; if (exec) Test4101940(/* par */); break;
+ case 22: name = "Test4103436"; if (exec) Test4103436(/* par */); break;
+ case 23: name = "Test4114076"; if (exec) Test4114076(/* par */); break;
+ case 24: name = "Test4114077"; if (exec) Test4114077(/* par */); break;
+ case 25: name = "Test4124632"; if (exec) Test4124632(/* par */); break;
+ case 26: name = "Test4132736"; if (exec) Test4132736(/* par */); break;
+ case 27: name = "Test4133509"; if (exec) Test4133509(/* par */); break;
+ case 28: name = "Test4139572"; if (exec) Test4139572(/* par */); break;
+ case 29: name = "Test4141640"; if (exec) Test4141640(/* par */); break;
+ case 30: name = "Test4146160"; if (exec) Test4146160(/* par */); break;
+ default: name = ""; break;
+ }
+ } else {
+ errln("Class collator not instantiated");
+ name = "";
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/regcoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/regcoll.h
new file mode 100644
index 00000000000..a9a90e22018
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/regcoll.h
@@ -0,0 +1,244 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * Collation regression tests.
+ * (So we'll have no regrets later)
+ */
+
+#ifndef _REGCOLL
+#define _REGCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/coleitr.h"
+#include "tscoll.h"
+
+class CollationRegressionTest: public IntlTestCollator
+{
+public:
+
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 32 };
+
+ CollationRegressionTest();
+ virtual ~CollationRegressionTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // @bug 4048446
+ //
+ // CollationElementIterator.reset() doesn't work
+ //
+ void Test4048446(/* char* par */);
+
+ // @bug 4051866
+ //
+ // Collator -> rules -> Collator round-trip broken for expanding characters
+ //
+ void Test4051866(/* char* par */);
+
+ // @bug 4053636
+ //
+ // Collator thinks "black-bird" == "black"
+ //
+ void Test4053636(/* char* par */);
+
+
+ // @bug 4054238
+ //
+ // CollationElementIterator will not work correctly if the associated
+ // Collator object's mode is changed
+ //
+ void Test4054238(/* char* par */);
+
+ // @bug 4054734
+ //
+ // Collator.IDENTICAL documented but not implemented
+ //
+ void Test4054734(/* char* par */);
+
+ // @bug 4054736
+ //
+ // Full Decomposition mode not implemented
+ //
+ void Test4054736(/* char* par */);
+
+ // @bug 4058613
+ //
+ // Collator.getInstance() causes an ArrayIndexOutofBoundsException for Korean
+ //
+ void Test4058613(/* char* par */);
+
+ // @bug 4059820
+ //
+ // RuleBasedCollator.getRules does not return the exact pattern as input
+ // for expanding character sequences
+ //
+ void Test4059820(/* char* par */);
+
+ // @bug 4060154
+ //
+ // MergeCollation::fixEntry broken for "& H < \u0131, \u0130, i, I"
+ //
+ void Test4060154(/* char* par */);
+
+ // @bug 4062418
+ //
+ // Secondary/Tertiary comparison incorrect in French Secondary
+ //
+ void Test4062418(/* char* par */);
+
+ // @bug 4065540
+ //
+ // Collator.compare() method broken if either string contains spaces
+ //
+ void Test4065540(/* char* par */);
+
+ // @bug 4066189
+ //
+ // Unicode characters need to be recursively decomposed to get the
+ // correct result. For example,
+ // u1EB1 -> \u0103 + \u0300 -> a + \u0306 + \u0300.
+ //
+ void Test4066189(/* char* par */);
+
+ // @bug 4066696
+ //
+ // French secondary collation checking at the end of compare iteration fails
+ //
+ void Test4066696(/* char* par */);
+
+
+ // @bug 4076676
+ //
+ // Bad canonicalization of same-class combining characters
+ //
+ void Test4076676(/* char* par */);
+
+
+ // @bug 4078588
+ //
+ // RuleBasedCollator breaks on "< a < bb" rule
+ //
+ void Test4078588(/* char* par */);
+
+ // @bug 4079231
+ //
+ // RuleBasedCollator.equals(null) throws NullPointerException
+ //
+ void Test4079231(/* char* par */);
+
+ // @bug 4081866
+ //
+ // Combining characters in different classes not reordered properly.
+ //
+ void Test4081866(/* char* par */);
+
+ // @bug 4087241
+ //
+ // string comparison errors in Scandinavian collators
+ //
+ void Test4087241(/* char* par */);
+
+ // @bug 4087243
+ //
+ // CollationKey takes ignorable strings into account when it shouldn't
+ //
+ void Test4087243(/* char* par */);
+
+ // @bug 4092260
+ //
+ // Mu/micro conflict
+ // Micro symbol and greek lowercase letter Mu should sort identically
+ //
+ void Test4092260(/* char* par */);
+
+ // @bug 4095316
+ //
+ void Test4095316(/* char* par */);
+
+ // @bug 4101940
+ //
+ void Test4101940(/* char* par */);
+
+ // @bug 4103436
+ //
+ // Collator.compare not handling spaces properly
+ //
+ void Test4103436(/* char* par */);
+
+ // @bug 4114076
+ //
+ // Collation not Unicode conformant with Hangul syllables
+ //
+ void Test4114076(/* char* par */);
+
+
+ // @bug 4114077
+ //
+ // Collation with decomposition off doesn't work for Europe
+ //
+ void Test4114077(/* char* par */);
+
+ // @bug 4124632
+ //
+ // Collator.getCollationKey was hanging on certain character sequences
+ //
+ void Test4124632(/* char* par */);
+
+ // @bug 4132736
+ //
+ // sort order of french words with multiple accents has errors
+ //
+ void Test4132736(/* char* par */);
+
+ // @bug 4133509
+ //
+ // The sorting using java.text.CollationKey is not in the exact order
+ //
+ void Test4133509(/* char* par */);
+
+ // @bug 4139572
+ //
+ // getCollationKey throws exception for spanish text
+ // Cannot reproduce this bug on 1.2, however it DOES fail on 1.1.6
+ //
+ void Test4139572(/* char* par */);
+
+ // @bug 4141640
+ //
+ // Support for Swedish gone in 1.1.6 (Can't create Swedish collator)
+ //
+ void Test4141640(/* char* par */);
+
+ // @bug 4146160
+ //
+ // RuleBasedCollator doesn't use getCollationElementIterator internally
+ //
+ void Test4146160(/* char* par */);
+
+private:
+ //------------------------------------------------------------------------
+ // Internal utilities
+ //
+ void compareArray(Collator &c,
+ const UChar tests[][CollationRegressionTest::MAX_TOKEN_LEN],
+ int32_t testCount);
+
+ void assertEqual(CollationElementIterator &i1, CollationElementIterator &i2);
+
+
+ RuleBasedCollator *en_us;
+
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/regextst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/regextst.cpp
new file mode 100644
index 00000000000..04b437a4a94
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/regextst.cpp
@@ -0,0 +1,2127 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+//
+// regextst.cpp
+//
+// ICU Regular Expressions test, part of intltest.
+//
+
+#include "intltest.h"
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "unicode/regex.h"
+#include "unicode/uchar.h"
+#include "unicode/ucnv.h"
+#include "regextst.h"
+#include "uvector.h"
+#include "util.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+
+//---------------------------------------------------------------------------
+//
+// Test class boilerplate
+//
+//---------------------------------------------------------------------------
+RegexTest::RegexTest()
+{
+}
+
+
+RegexTest::~RegexTest()
+{
+}
+
+
+
+void RegexTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite RegexTest: ");
+ switch (index) {
+
+ case 0: name = "Basic";
+ if (exec) Basic();
+ break;
+ case 1: name = "API_Match";
+ if (exec) API_Match();
+ break;
+ case 2: name = "API_Replace";
+ if (exec) API_Replace();
+ break;
+ case 3: name = "API_Pattern";
+ if (exec) API_Pattern();
+ break;
+ case 4: name = "Extended";
+ if (exec) Extended();
+ break;
+ case 5: name = "Errors";
+ if (exec) Errors();
+ break;
+ case 6: name = "PerlTests";
+ if (exec) PerlTests();
+ break;
+
+
+ default: name = "";
+ break; //needed to end loop
+ }
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Error Checking / Reporting macros used in all of the tests.
+//
+//---------------------------------------------------------------------------
+#define REGEX_CHECK_STATUS {if (U_FAILURE(status)) {errln("RegexTest failure at line %d. status=%s\n", \
+__LINE__, u_errorName(status)); return;}}
+
+#define REGEX_ASSERT(expr) {if ((expr)==FALSE) {errln("RegexTest failure at line %d.\n", __LINE__);};}
+
+#define REGEX_ASSERT_FAIL(expr, errcode) {UErrorCode status=U_ZERO_ERROR; (expr);\
+if (status!=errcode) {errln("RegexTest failure at line %d. Expected status=%s, got %s\n", \
+ __LINE__, u_errorName(errcode), u_errorName(status));};}
+
+#define REGEX_CHECK_STATUS_L(line) {if (U_FAILURE(status)) {errln( \
+ "RegexTest failure at line %d, from %d. status=%d\n",__LINE__, (line), status); }}
+
+#define REGEX_ASSERT_L(expr, line) {if ((expr)==FALSE) { \
+ errln("RegexTest failure at line %d, from %d.", __LINE__, (line)); return;}}
+
+
+
+//---------------------------------------------------------------------------
+//
+// REGEX_TESTLM Macro + invocation function to simplify writing quick tests
+// for the LookingAt() and Match() functions.
+//
+// usage:
+// REGEX_TESTLM("pattern", "input text", lookingAt expected, matches expected);
+//
+// The expected results are UBool - TRUE or FALSE.
+// The input text is unescaped. The pattern is not.
+//
+//
+//---------------------------------------------------------------------------
+
+#define REGEX_TESTLM(pat, text, looking, match) doRegexLMTest(pat, text, looking, match, __LINE__);
+
+UBool RegexTest::doRegexLMTest(const char *pat, const char *text, UBool looking, UBool match, int32_t line) {
+ const UnicodeString pattern(pat);
+ const UnicodeString inputText(text);
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError pe;
+ RegexPattern *REPattern = NULL;
+ RegexMatcher *REMatcher = NULL;
+ UBool retVal = TRUE;
+
+ UnicodeString patString(pat);
+ REPattern = RegexPattern::compile(patString, 0, pe, status);
+ if (U_FAILURE(status)) {
+ errln("RegexTest failure in RegexPattern::compile() at line %d. Status = %s\n",
+ line, u_errorName(status));
+ return FALSE;
+ }
+ if (line==376) { RegexPatternDump(REPattern);}
+
+ UnicodeString inputString(inputText);
+ UnicodeString unEscapedInput = inputString.unescape();
+ REMatcher = REPattern->matcher(unEscapedInput, status);
+ if (U_FAILURE(status)) {
+ errln("RegexTest failure in REPattern::matcher() at line %d. Status = %s\n",
+ line, u_errorName(status));
+ return FALSE;
+ }
+
+ UBool actualmatch;
+ actualmatch = REMatcher->lookingAt(status);
+ if (U_FAILURE(status)) {
+ errln("RegexTest failure in lookingAt() at line %d. Status = %s\n",
+ line, u_errorName(status));
+ retVal = FALSE;
+ }
+ if (actualmatch != looking) {
+ errln("RegexTest: wrong return from lookingAt() at line %d.\n", line);
+ retVal = FALSE;
+ }
+
+ status = U_ZERO_ERROR;
+ actualmatch = REMatcher->matches(status);
+ if (U_FAILURE(status)) {
+ errln("RegexTest failure in matches() at line %d. Status = %s\n",
+ line, u_errorName(status));
+ retVal = FALSE;
+ }
+ if (actualmatch != match) {
+ errln("RegexTest: wrong return from matches() at line %d.\n", line);
+ retVal = FALSE;
+ }
+
+ if (retVal == FALSE) {
+ RegexPatternDump(REPattern);
+ }
+
+ delete REPattern;
+ delete REMatcher;
+ return retVal;
+}
+
+
+
+
+//---------------------------------------------------------------------------
+//
+// regex_find(pattern, inputString, lineNumber)
+//
+// function to simplify writing tests regex tests.
+//
+// The input text is unescaped. The pattern is not.
+// The input text is marked with the expected match positions
+// <0>text <1> more text </1> </0>
+// The <n> </n> tags are removed before trying the match.
+// The tags mark the start and end of the match and of any capture groups.
+//
+//
+//---------------------------------------------------------------------------
+
+
+// Set a value into a UVector at position specified by a decimal number in
+// a UnicodeString. This is a utility function needed by the actual test function,
+// which follows.
+static void set(UVector &vec, int32_t val, UnicodeString index) {
+ UErrorCode status=U_ZERO_ERROR;
+ int32_t idx = 0;
+ for (int32_t i=0; i<index.length(); i++) {
+ int32_t d=u_charDigitValue(index.charAt(i));
+ if (d<0) {return;}
+ idx = idx*10 + d;
+ }
+ while (vec.size()<idx+1) {vec.addElement(-1, status);}
+ vec.setElementAt(val, idx);
+}
+
+void RegexTest::regex_find(const UnicodeString &pattern,
+ const UnicodeString &flags,
+ const UnicodeString &inputString,
+ int32_t line) {
+ UnicodeString unEscapedInput;
+ UnicodeString deTaggedInput;
+
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError pe;
+ RegexPattern *parsePat = NULL;
+ RegexMatcher *parseMatcher = NULL;
+ RegexPattern *callerPattern = NULL;
+ RegexMatcher *matcher = NULL;
+ UVector groupStarts(status);
+ UVector groupEnds(status);
+ UBool isMatch = FALSE;
+ UBool failed = FALSE;
+ int32_t numFinds;
+ int32_t i;
+
+ //
+ // Compile the caller's pattern
+ //
+ uint32_t bflags = 0;
+ if (flags.indexOf((UChar)0x69) >= 0) { // 'i' flag
+ bflags |= UREGEX_CASE_INSENSITIVE;
+ }
+ if (flags.indexOf((UChar)0x78) >= 0) { // 'x' flag
+ bflags |= UREGEX_COMMENTS;
+ }
+ if (flags.indexOf((UChar)0x73) >= 0) { // 's' flag
+ bflags |= UREGEX_DOTALL;
+ }
+ if (flags.indexOf((UChar)0x6d) >= 0) { // 'm' flag
+ bflags |= UREGEX_MULTILINE;
+ }
+
+
+ callerPattern = RegexPattern::compile(pattern, bflags, pe, status);
+ if (status != U_ZERO_ERROR) {
+ #if UCONFIG_NO_BREAK_ITERATION==1
+ // 'v' test flag means that the test pattern should not compile if ICU was configured
+ // to not include break iteration. RBBI is needed for Unicode word boundaries.
+ if (flags.indexOf((UChar)0x76) >= 0 /*'v'*/ && status == U_UNSUPPORTED_ERROR) {
+ goto cleanupAndReturn;
+ }
+ #endif
+ errln("Line %d: error %s compiling pattern.", line, u_errorName(status));
+ goto cleanupAndReturn;
+ }
+
+ if (flags.indexOf((UChar)'d') >= 0) {
+ RegexPatternDump(callerPattern);
+ }
+
+ //
+ // Number of times find() should be called on the test string, default to 1
+ //
+ numFinds = 1;
+ for (i=2; i<=9; i++) {
+ if (flags.indexOf((UChar)(0x30 + i)) >= 0) { // digit flag
+ if (numFinds != 1) {
+ errln("Line %d: more than one digit flag. Scanning %d.", line, i);
+ goto cleanupAndReturn;
+ }
+ numFinds = i;
+ }
+ }
+
+ //
+ // Find the tags in the input data, remove them, and record the group boundary
+ // positions.
+ //
+ parsePat = RegexPattern::compile("<(/?)([0-9]+)>", 0, pe, status);
+ REGEX_CHECK_STATUS_L(line);
+
+ unEscapedInput = inputString.unescape();
+ parseMatcher = parsePat->matcher(unEscapedInput, status);
+ REGEX_CHECK_STATUS_L(line);
+ while(parseMatcher->find()) {
+ parseMatcher->appendReplacement(deTaggedInput, "", status);
+ REGEX_CHECK_STATUS;
+ UnicodeString groupNum = parseMatcher->group(2, status);
+ if (parseMatcher->group(1, status) == "/") {
+ // close tag
+ set(groupEnds, deTaggedInput.length(), groupNum);
+ } else {
+ set(groupStarts, deTaggedInput.length(), groupNum);
+ }
+ }
+ parseMatcher->appendTail(deTaggedInput);
+ REGEX_ASSERT_L(groupStarts.size() == groupEnds.size(), line);
+
+
+ //
+ // Do a find on the de-tagged input using the caller's pattern
+ //
+ matcher = callerPattern->matcher(deTaggedInput, status);
+ REGEX_CHECK_STATUS_L(line);
+ if (flags.indexOf((UChar)'t') >= 0) {
+ matcher->setTrace(TRUE);
+ }
+
+ for (i=0; i<numFinds; i++) {
+ isMatch = matcher->find();
+ }
+ matcher->setTrace(FALSE);
+
+ //
+ // Match up the groups from the find() with the groups from the tags
+ //
+
+ // number of tags should match number of groups from find operation.
+ // matcher->groupCount does not include group 0, the entire match, hence the +1.
+ // G option in test means that capture group data is not available in the
+ // expected results, so the check needs to be suppressed.
+ if (isMatch == FALSE && groupStarts.size() != 0) {
+ errln("Error at line %d: Match expected, but none found.\n", line);
+ failed = TRUE;
+ goto cleanupAndReturn;
+ }
+
+ if (flags.indexOf((UChar)0x47 /*G*/) >= 0) {
+ // Only check for match / no match. Don't check capture groups.
+ if (isMatch && groupStarts.size() == 0) {
+ errln("Error at line %d: No match expected, but one found.\n", line);
+ failed = TRUE;
+ }
+ goto cleanupAndReturn;
+ }
+
+ for (i=0; i<=matcher->groupCount(); i++) {
+ int32_t expectedStart = (i >= groupStarts.size()? -1 : groupStarts.elementAti(i));
+ if (matcher->start(i, status) != expectedStart) {
+ errln("Error at line %d: incorrect start position for group %d. Expected %d, got %d",
+ line, i, expectedStart, matcher->start(i, status));
+ failed = TRUE;
+ goto cleanupAndReturn; // Good chance of subsequent bogus errors. Stop now.
+ }
+ int32_t expectedEnd = (i >= groupEnds.size()? -1 : groupEnds.elementAti(i));
+ if (matcher->end(i, status) != expectedEnd) {
+ errln("Error at line %d: incorrect end position for group %d. Expected %d, got %d",
+ line, i, expectedEnd, matcher->end(i, status));
+ failed = TRUE;
+ // Error on end position; keep going; real error is probably yet to come as group
+ // end positions work from end of the input data towards the front.
+ }
+ }
+ if ( matcher->groupCount()+1 < groupStarts.size()) {
+ errln("Error at line %d: Expected %d capture groups, found %d.",
+ line, groupStarts.size()-1, matcher->groupCount());
+ failed = TRUE;
+ }
+
+cleanupAndReturn:
+ if (failed) {
+ errln((UnicodeString)"\""+pattern+(UnicodeString)"\" "
+ +flags+(UnicodeString)" \""+inputString+(UnicodeString)"\"");
+ // callerPattern->dump();
+ }
+ delete parseMatcher;
+ delete parsePat;
+ delete matcher;
+ delete callerPattern;
+}
+
+
+
+
+
+
+
+
+//---------------------------------------------------------------------------
+//
+// REGEX_ERR Macro + invocation function to simplify writing tests
+// regex tests for incorrect patterns
+//
+// usage:
+// REGEX_ERR("pattern", expected error line, column, expected status);
+//
+//---------------------------------------------------------------------------
+#define REGEX_ERR(pat, line, col, status) regex_err(pat, line, col, status, __LINE__);
+
+void RegexTest::regex_err(const char *pat, int32_t errLine, int32_t errCol,
+ UErrorCode expectedStatus, int32_t line) {
+ UnicodeString pattern(pat);
+
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError pe;
+ RegexPattern *callerPattern = NULL;
+
+ //
+ // Compile the caller's pattern
+ //
+ UnicodeString patString(pat);
+ callerPattern = RegexPattern::compile(patString, 0, pe, status);
+ if (status != expectedStatus) {
+ errln("Line %d: unexpected error %s compiling pattern.", line, u_errorName(status));
+ } else {
+ if (status != U_ZERO_ERROR) {
+ if (pe.line != errLine || pe.offset != errCol) {
+ errln("Line %d: incorrect line/offset from UParseError. Expected %d/%d; got %d/%d.\n",
+ line, errLine, errCol, pe.line, pe.offset);
+ }
+ }
+ }
+
+ delete callerPattern;
+}
+
+
+
+//---------------------------------------------------------------------------
+//
+// Basic Check for basic functionality of regex pattern matching.
+// Avoid the use of REGEX_FIND test macro, which has
+// substantial dependencies on basic Regex functionality.
+//
+//---------------------------------------------------------------------------
+void RegexTest::Basic() {
+
+
+//
+// Debug - slide failing test cases early
+//
+#if 0
+ {
+ // REGEX_TESTLM("a\N{LATIN SMALL LETTER B}c", "abc", FALSE, FALSE);
+ UParseError pe;
+ UErrorCode status = U_ZERO_ERROR;
+ RegexPattern::compile("^(?:a?b?)*$", 0, pe, status);
+ // REGEX_FIND("(?>(abc{2,4}?))(c*)", "<0>ab<1>cc</1><2>ccc</2></0>ddd");
+ // REGEX_FIND("(X([abc=X]+)+X)|(y[abc=]+)", "=XX====================");
+ }
+ exit(1);
+#endif
+
+
+ //
+ // Pattern with parentheses
+ //
+ REGEX_TESTLM("st(abc)ring", "stabcring thing", TRUE, FALSE);
+ REGEX_TESTLM("st(abc)ring", "stabcring", TRUE, TRUE);
+ REGEX_TESTLM("st(abc)ring", "stabcrung", FALSE, FALSE);
+
+ //
+ // Patterns with *
+ //
+ REGEX_TESTLM("st(abc)*ring", "string", TRUE, TRUE);
+ REGEX_TESTLM("st(abc)*ring", "stabcring", TRUE, TRUE);
+ REGEX_TESTLM("st(abc)*ring", "stabcabcring", TRUE, TRUE);
+ REGEX_TESTLM("st(abc)*ring", "stabcabcdring", FALSE, FALSE);
+ REGEX_TESTLM("st(abc)*ring", "stabcabcabcring etc.", TRUE, FALSE);
+
+ REGEX_TESTLM("a*", "", TRUE, TRUE);
+ REGEX_TESTLM("a*", "b", TRUE, FALSE);
+
+
+ //
+ // Patterns with "."
+ //
+ REGEX_TESTLM(".", "abc", TRUE, FALSE);
+ REGEX_TESTLM("...", "abc", TRUE, TRUE);
+ REGEX_TESTLM("....", "abc", FALSE, FALSE);
+ REGEX_TESTLM(".*", "abcxyz123", TRUE, TRUE);
+ REGEX_TESTLM("ab.*xyz", "abcdefghij", FALSE, FALSE);
+ REGEX_TESTLM("ab.*xyz", "abcdefg...wxyz", TRUE, TRUE);
+ REGEX_TESTLM("ab.*xyz", "abcde...wxyz...abc..xyz", TRUE, TRUE);
+ REGEX_TESTLM("ab.*xyz", "abcde...wxyz...abc..xyz...", TRUE, FALSE);
+
+ //
+ // Patterns with * applied to chars at end of literal string
+ //
+ REGEX_TESTLM("abc*", "ab", TRUE, TRUE);
+ REGEX_TESTLM("abc*", "abccccc", TRUE, TRUE);
+
+ //
+ // Supplemental chars match as single chars, not a pair of surrogates.
+ //
+ REGEX_TESTLM(".", "\\U00011000", TRUE, TRUE);
+ REGEX_TESTLM("...", "\\U00011000x\\U00012002", TRUE, TRUE);
+ REGEX_TESTLM("...", "\\U00011000x\\U00012002y", TRUE, FALSE);
+
+
+ //
+ // UnicodeSets in the pattern
+ //
+ REGEX_TESTLM("[1-6]", "1", TRUE, TRUE);
+ REGEX_TESTLM("[1-6]", "3", TRUE, TRUE);
+ REGEX_TESTLM("[1-6]", "7", FALSE, FALSE);
+ REGEX_TESTLM("a[1-6]", "a3", TRUE, TRUE);
+ REGEX_TESTLM("a[1-6]", "a3", TRUE, TRUE);
+ REGEX_TESTLM("a[1-6]b", "a3b", TRUE, TRUE);
+
+ REGEX_TESTLM("a[0-9]*b", "a123b", TRUE, TRUE);
+ REGEX_TESTLM("a[0-9]*b", "abc", TRUE, FALSE);
+ REGEX_TESTLM("[\\p{Nd}]*", "123456", TRUE, TRUE);
+ REGEX_TESTLM("[\\p{Nd}]*", "a123456", TRUE, FALSE); // note that * matches 0 occurences.
+ REGEX_TESTLM("[a][b][[:Zs:]]*", "ab ", TRUE, TRUE);
+
+ //
+ // OR operator in patterns
+ //
+ REGEX_TESTLM("(a|b)", "a", TRUE, TRUE);
+ REGEX_TESTLM("(a|b)", "b", TRUE, TRUE);
+ REGEX_TESTLM("(a|b)", "c", FALSE, FALSE);
+ REGEX_TESTLM("a|b", "b", TRUE, TRUE);
+
+ REGEX_TESTLM("(a|b|c)*", "aabcaaccbcabc", TRUE, TRUE);
+ REGEX_TESTLM("(a|b|c)*", "aabcaaccbcabdc", TRUE, FALSE);
+ REGEX_TESTLM("(a(b|c|d)(x|y|z)*|123)", "ac", TRUE, TRUE);
+ REGEX_TESTLM("(a(b|c|d)(x|y|z)*|123)", "123", TRUE, TRUE);
+ REGEX_TESTLM("(a|(1|2)*)(b|c|d)(x|y|z)*|123", "123", TRUE, TRUE);
+ REGEX_TESTLM("(a|(1|2)*)(b|c|d)(x|y|z)*|123", "222211111czzzzw", TRUE, FALSE);
+
+ //
+ // +
+ //
+ REGEX_TESTLM("ab+", "abbc", TRUE, FALSE);
+ REGEX_TESTLM("ab+c", "ac", FALSE, FALSE);
+ REGEX_TESTLM("b+", "", FALSE, FALSE);
+ REGEX_TESTLM("(abc|def)+", "defabc", TRUE, TRUE);
+ REGEX_TESTLM(".+y", "zippity dooy dah ", TRUE, FALSE);
+ REGEX_TESTLM(".+y", "zippity dooy", TRUE, TRUE);
+
+ //
+ // ?
+ //
+ REGEX_TESTLM("ab?", "ab", TRUE, TRUE);
+ REGEX_TESTLM("ab?", "a", TRUE, TRUE);
+ REGEX_TESTLM("ab?", "ac", TRUE, FALSE);
+ REGEX_TESTLM("ab?", "abb", TRUE, FALSE);
+ REGEX_TESTLM("a(b|c)?d", "abd", TRUE, TRUE);
+ REGEX_TESTLM("a(b|c)?d", "acd", TRUE, TRUE);
+ REGEX_TESTLM("a(b|c)?d", "ad", TRUE, TRUE);
+ REGEX_TESTLM("a(b|c)?d", "abcd", FALSE, FALSE);
+ REGEX_TESTLM("a(b|c)?d", "ab", FALSE, FALSE);
+
+ //
+ // Escape sequences that become single literal chars, handled internally
+ // by ICU's Unescape.
+ //
+
+ // REGEX_TESTLM("\101\142", "Ab", TRUE, TRUE); // Octal TODO: not implemented yet.
+ REGEX_TESTLM("\\a", "\\u0007", TRUE, TRUE); // BEL
+ REGEX_TESTLM("\\cL", "\\u000c", TRUE, TRUE); // Control-L
+ REGEX_TESTLM("\\e", "\\u001b", TRUE, TRUE); // Escape
+ REGEX_TESTLM("\\f", "\\u000c", TRUE, TRUE); // Form Feed
+ REGEX_TESTLM("\\n", "\\u000a", TRUE, TRUE); // new line
+ REGEX_TESTLM("\\r", "\\u000d", TRUE, TRUE); // CR
+ REGEX_TESTLM("\\t", "\\u0009", TRUE, TRUE); // Tab
+ REGEX_TESTLM("\\u1234", "\\u1234", TRUE, TRUE);
+ REGEX_TESTLM("\\U00001234", "\\u1234", TRUE, TRUE);
+
+ REGEX_TESTLM(".*\\Ax", "xyz", TRUE, FALSE); // \A matches only at the beginning of input
+ REGEX_TESTLM(".*\\Ax", " xyz", FALSE, FALSE); // \A matches only at the beginning of input
+
+ // Escape of special chars in patterns
+ REGEX_TESTLM("\\\\\\|\\(\\)\\[\\{\\~\\$\\*\\+\\?\\.", "\\\\|()[{~$*+?.", TRUE, TRUE);
+
+
+}
+
+
+//---------------------------------------------------------------------------
+//
+// API_Match Test that the API for class RegexMatcher
+// is present and nominally working, but excluding functions
+// implementing replace operations.
+//
+//---------------------------------------------------------------------------
+void RegexTest::API_Match() {
+ UParseError pe;
+ UErrorCode status=U_ZERO_ERROR;
+ int32_t flags = 0;
+
+ //
+ // Debug - slide failing test cases early
+ //
+#if 0
+ {
+ }
+ return;
+#endif
+
+ //
+ // Simple pattern compilation
+ //
+ {
+ UnicodeString re("abc");
+ RegexPattern *pat2;
+ pat2 = RegexPattern::compile(re, flags, pe, status);
+ REGEX_CHECK_STATUS;
+
+ UnicodeString inStr1 = "abcdef this is a test";
+ UnicodeString instr2 = "not abc";
+ UnicodeString empty = "";
+
+
+ //
+ // Matcher creation and reset.
+ //
+ RegexMatcher *m1 = pat2->matcher(inStr1, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(m1->lookingAt(status) == TRUE);
+ REGEX_ASSERT(m1->input() == inStr1);
+ m1->reset(instr2);
+ REGEX_ASSERT(m1->lookingAt(status) == FALSE);
+ REGEX_ASSERT(m1->input() == instr2);
+ m1->reset(inStr1);
+ REGEX_ASSERT(m1->input() == inStr1);
+ REGEX_ASSERT(m1->lookingAt(status) == TRUE);
+ m1->reset(empty);
+ REGEX_ASSERT(m1->lookingAt(status) == FALSE);
+ REGEX_ASSERT(m1->input() == empty);
+ REGEX_ASSERT(&m1->pattern() == pat2);
+
+ //
+ // reset(pos, status)
+ //
+ m1->reset(inStr1);
+ m1->reset(4, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(m1->input() == inStr1);
+ REGEX_ASSERT(m1->lookingAt(status) == TRUE);
+
+ m1->reset(-1, status);
+ REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+ status = U_ZERO_ERROR;
+
+ m1->reset(0, status);
+ REGEX_CHECK_STATUS;
+ status = U_ZERO_ERROR;
+
+ int32_t len = m1->input().length();
+ m1->reset(len-1, status);
+ REGEX_CHECK_STATUS;
+ status = U_ZERO_ERROR;
+
+ m1->reset(len, status);
+ REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+ status = U_ZERO_ERROR;
+
+ //
+ // match(pos, status)
+ //
+ m1->reset(instr2);
+ REGEX_ASSERT(m1->matches(4, status) == TRUE);
+ m1->reset();
+ REGEX_ASSERT(m1->matches(3, status) == FALSE);
+ m1->reset();
+ REGEX_ASSERT(m1->matches(5, status) == FALSE);
+ REGEX_ASSERT(m1->matches(4, status) == TRUE);
+ REGEX_ASSERT(m1->matches(-1, status) == FALSE);
+ REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+
+ // Match() at end of string should fail, but should not
+ // be an error.
+ status = U_ZERO_ERROR;
+ len = m1->input().length();
+ REGEX_ASSERT(m1->matches(len, status) == FALSE);
+ REGEX_CHECK_STATUS;
+
+ // Match beyond end of string should fail with an error.
+ status = U_ZERO_ERROR;
+ REGEX_ASSERT(m1->matches(len+1, status) == FALSE);
+ REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+
+ // Successful match at end of string.
+ {
+ status = U_ZERO_ERROR;
+ RegexMatcher m("A?", 0, status); // will match zero length string.
+ REGEX_CHECK_STATUS;
+ m.reset(inStr1);
+ len = inStr1.length();
+ REGEX_ASSERT(m.matches(len, status) == TRUE);
+ REGEX_CHECK_STATUS;
+ m.reset(empty);
+ REGEX_ASSERT(m.matches(0, status) == TRUE);
+ REGEX_CHECK_STATUS;
+ }
+
+
+ //
+ // lookingAt(pos, status)
+ //
+ status = U_ZERO_ERROR;
+ m1->reset(instr2); // "not abc"
+ REGEX_ASSERT(m1->lookingAt(4, status) == TRUE);
+ REGEX_ASSERT(m1->lookingAt(5, status) == FALSE);
+ REGEX_ASSERT(m1->lookingAt(3, status) == FALSE);
+ REGEX_ASSERT(m1->lookingAt(4, status) == TRUE);
+ REGEX_ASSERT(m1->lookingAt(-1, status) == FALSE);
+ REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+ status = U_ZERO_ERROR;
+ len = m1->input().length();
+ REGEX_ASSERT(m1->lookingAt(len, status) == FALSE);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(m1->lookingAt(len+1, status) == FALSE);
+ REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+
+ delete m1;
+ delete pat2;
+ }
+
+
+ //
+ // Capture Group.
+ // RegexMatcher::start();
+ // RegexMatcher::end();
+ // RegexMatcher::groupCount();
+ //
+ {
+ int32_t flags=0;
+ UParseError pe;
+ UErrorCode status=U_ZERO_ERROR;
+
+ UnicodeString re("01(23(45)67)(.*)");
+ RegexPattern *pat = RegexPattern::compile(re, flags, pe, status);
+ REGEX_CHECK_STATUS;
+ UnicodeString data = "0123456789";
+
+ RegexMatcher *matcher = pat->matcher(data, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(matcher->lookingAt(status) == TRUE);
+ static const int32_t matchStarts[] = {0, 2, 4, 8};
+ static const int32_t matchEnds[] = {10, 8, 6, 10};
+ int32_t i;
+ for (i=0; i<4; i++) {
+ int32_t actualStart = matcher->start(i, status);
+ REGEX_CHECK_STATUS;
+ if (actualStart != matchStarts[i]) {
+ errln("RegexTest failure at line %d, index %d. Expected %d, got %d\n",
+ __LINE__, i, matchStarts[i], actualStart);
+ }
+ int32_t actualEnd = matcher->end(i, status);
+ REGEX_CHECK_STATUS;
+ if (actualEnd != matchEnds[i]) {
+ errln("RegexTest failure at line %d index %d. Expected %d, got %d\n",
+ __LINE__, i, matchEnds[i], actualEnd);
+ }
+ }
+
+ REGEX_ASSERT(matcher->start(0, status) == matcher->start(status));
+ REGEX_ASSERT(matcher->end(0, status) == matcher->end(status));
+
+ REGEX_ASSERT_FAIL(matcher->start(-1, status), U_INDEX_OUTOFBOUNDS_ERROR);
+ REGEX_ASSERT_FAIL(matcher->start( 4, status), U_INDEX_OUTOFBOUNDS_ERROR);
+ matcher->reset();
+ REGEX_ASSERT_FAIL(matcher->start( 0, status), U_REGEX_INVALID_STATE);
+
+ matcher->lookingAt(status);
+ REGEX_ASSERT(matcher->group(status) == "0123456789");
+ REGEX_ASSERT(matcher->group(0, status) == "0123456789");
+ REGEX_ASSERT(matcher->group(1, status) == "234567" );
+ REGEX_ASSERT(matcher->group(2, status) == "45" );
+ REGEX_ASSERT(matcher->group(3, status) == "89" );
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT_FAIL(matcher->group(-1, status), U_INDEX_OUTOFBOUNDS_ERROR);
+ REGEX_ASSERT_FAIL(matcher->group( 4, status), U_INDEX_OUTOFBOUNDS_ERROR);
+ matcher->reset();
+ REGEX_ASSERT_FAIL(matcher->group( 0, status), U_REGEX_INVALID_STATE);
+
+ delete matcher;
+ delete pat;
+
+ }
+
+ //
+ // find
+ //
+ {
+ int32_t flags=0;
+ UParseError pe;
+ UErrorCode status=U_ZERO_ERROR;
+
+ UnicodeString re("abc");
+ RegexPattern *pat = RegexPattern::compile(re, flags, pe, status);
+ REGEX_CHECK_STATUS;
+ UnicodeString data = ".abc..abc...abc..";
+ // 012345678901234567
+
+ RegexMatcher *matcher = pat->matcher(data, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(matcher->find());
+ REGEX_ASSERT(matcher->start(status) == 1);
+ REGEX_ASSERT(matcher->find());
+ REGEX_ASSERT(matcher->start(status) == 6);
+ REGEX_ASSERT(matcher->find());
+ REGEX_ASSERT(matcher->start(status) == 12);
+ REGEX_ASSERT(matcher->find() == FALSE);
+ REGEX_ASSERT(matcher->find() == FALSE);
+
+ matcher->reset();
+ REGEX_ASSERT(matcher->find());
+ REGEX_ASSERT(matcher->start(status) == 1);
+
+ REGEX_ASSERT(matcher->find(0, status));
+ REGEX_ASSERT(matcher->start(status) == 1);
+ REGEX_ASSERT(matcher->find(1, status));
+ REGEX_ASSERT(matcher->start(status) == 1);
+ REGEX_ASSERT(matcher->find(2, status));
+ REGEX_ASSERT(matcher->start(status) == 6);
+ REGEX_ASSERT(matcher->find(12, status));
+ REGEX_ASSERT(matcher->start(status) == 12);
+ REGEX_ASSERT(matcher->find(13, status) == FALSE);
+ REGEX_ASSERT(matcher->find(16, status) == FALSE);
+ REGEX_ASSERT(matcher->find(17, status) == FALSE);
+ REGEX_ASSERT_FAIL(matcher->start(status), U_REGEX_INVALID_STATE);
+
+ status = U_ZERO_ERROR;
+ REGEX_ASSERT_FAIL(matcher->find(-1, status), U_INDEX_OUTOFBOUNDS_ERROR);
+ status = U_ZERO_ERROR;
+ REGEX_ASSERT_FAIL(matcher->find(18, status), U_INDEX_OUTOFBOUNDS_ERROR);
+
+ REGEX_ASSERT(matcher->groupCount() == 0);
+
+ delete matcher;
+ delete pat;
+ }
+
+
+ //
+ // find, with \G in pattern (true if at the end of a previous match).
+ //
+ {
+ int32_t flags=0;
+ UParseError pe;
+ UErrorCode status=U_ZERO_ERROR;
+
+ UnicodeString re(".*?(?:(\\Gabc)|(abc))");
+ RegexPattern *pat = RegexPattern::compile(re, flags, pe, status);
+ REGEX_CHECK_STATUS;
+ UnicodeString data = ".abcabc.abc..";
+ // 012345678901234567
+
+ RegexMatcher *matcher = pat->matcher(data, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(matcher->find());
+ REGEX_ASSERT(matcher->start(status) == 0);
+ REGEX_ASSERT(matcher->start(1, status) == -1);
+ REGEX_ASSERT(matcher->start(2, status) == 1);
+
+ REGEX_ASSERT(matcher->find());
+ REGEX_ASSERT(matcher->start(status) == 4);
+ REGEX_ASSERT(matcher->start(1, status) == 4);
+ REGEX_ASSERT(matcher->start(2, status) == -1);
+ REGEX_CHECK_STATUS;
+
+ delete matcher;
+ delete pat;
+ }
+
+ //
+ // find with zero length matches, match position should bump ahead
+ // to prevent loops.
+ //
+ {
+ int32_t i;
+ UErrorCode status=U_ZERO_ERROR;
+ RegexMatcher m("(?= ?)", 0, status); // This pattern will zero-length matches anywhere,
+ // using an always-true look-ahead.
+ REGEX_CHECK_STATUS;
+ UnicodeString s(" ");
+ m.reset(s);
+ for (i=0; ; i++) {
+ if (m.find() == FALSE) {
+ break;
+ }
+ REGEX_ASSERT(m.start(status) == i);
+ REGEX_ASSERT(m.end(status) == i);
+ }
+ REGEX_ASSERT(i==5);
+
+ // Check that the bump goes over surrogate pairs OK
+ s = "\\U00010001\\U00010002\\U00010003\\U00010004";
+ s = s.unescape();
+ m.reset(s);
+ for (i=0; ; i+=2) {
+ if (m.find() == FALSE) {
+ break;
+ }
+ REGEX_ASSERT(m.start(status) == i);
+ REGEX_ASSERT(m.end(status) == i);
+ }
+ REGEX_ASSERT(i==10);
+ }
+ {
+ // find() loop breaking test.
+ // with pattern of /.?/, should see a series of one char matches, then a single
+ // match of zero length at the end of the input string.
+ int32_t i;
+ UErrorCode status=U_ZERO_ERROR;
+ RegexMatcher m(".?", 0, status);
+ REGEX_CHECK_STATUS;
+ UnicodeString s(" ");
+ m.reset(s);
+ for (i=0; ; i++) {
+ if (m.find() == FALSE) {
+ break;
+ }
+ REGEX_ASSERT(m.start(status) == i);
+ REGEX_ASSERT(m.end(status) == (i<4 ? i+1 : i));
+ }
+ REGEX_ASSERT(i==5);
+ }
+
+
+ //
+ // Matchers with no input string behave as if they had an empty input string.
+ //
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ RegexMatcher m(".?", 0, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(m.find());
+ REGEX_ASSERT(m.start(status) == 0);
+ REGEX_ASSERT(m.input() == "");
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ RegexPattern *p = RegexPattern::compile(".", 0, status);
+ RegexMatcher *m = p->matcher(status);
+ REGEX_CHECK_STATUS;
+
+ REGEX_ASSERT(m->find() == FALSE);
+ REGEX_ASSERT(m->input() == "");
+ delete m;
+ delete p;
+ }
+
+ //
+ // Compilation error on reset with UChar *
+ // These were a hazard that people were stumbling over with runtime errors.
+ // Changed them to compiler errors by adding private methods that more closely
+ // matched the incorrect use of the functions.
+ //
+#if 0
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UChar ucharString[20];
+ RegexMatcher m(".", 0, status);
+ m.reset(ucharString); // should not compile.
+
+ RegexPattern *p = RegexPattern::compile(".", 0, status);
+ RegexMatcher *m2 = p->matcher(ucharString, status); // should not compile.
+
+ RegexMatcher m3(".", ucharString, 0, status); // Should not compile
+ }
+#endif
+
+}
+
+
+
+
+
+
+//---------------------------------------------------------------------------
+//
+// API_Replace API test for class RegexMatcher, testing the
+// Replace family of functions.
+//
+//---------------------------------------------------------------------------
+void RegexTest::API_Replace() {
+ //
+ // Replace
+ //
+ int32_t flags=0;
+ UParseError pe;
+ UErrorCode status=U_ZERO_ERROR;
+
+ UnicodeString re("abc");
+ RegexPattern *pat = RegexPattern::compile(re, flags, pe, status);
+ REGEX_CHECK_STATUS;
+ UnicodeString data = ".abc..abc...abc..";
+ // 012345678901234567
+ RegexMatcher *matcher = pat->matcher(data, status);
+
+ //
+ // Plain vanilla matches.
+ //
+ UnicodeString dest;
+ dest = matcher->replaceFirst("yz", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == ".yz..abc...abc..");
+
+ dest = matcher->replaceAll("yz", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == ".yz..yz...yz..");
+
+ //
+ // Plain vanilla non-matches.
+ //
+ UnicodeString d2 = ".abx..abx...abx..";
+ matcher->reset(d2);
+ dest = matcher->replaceFirst("yz", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == ".abx..abx...abx..");
+
+ dest = matcher->replaceAll("yz", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == ".abx..abx...abx..");
+
+ //
+ // Empty source string
+ //
+ UnicodeString d3 = "";
+ matcher->reset(d3);
+ dest = matcher->replaceFirst("yz", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "");
+
+ dest = matcher->replaceAll("yz", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "");
+
+ //
+ // Empty substitution string
+ //
+ matcher->reset(data); // ".abc..abc...abc.."
+ dest = matcher->replaceFirst("", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "...abc...abc..");
+
+ dest = matcher->replaceAll("", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "........");
+
+ //
+ // match whole string
+ //
+ UnicodeString d4 = "abc";
+ matcher->reset(d4);
+ dest = matcher->replaceFirst("xyz", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "xyz");
+
+ dest = matcher->replaceAll("xyz", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "xyz");
+
+ //
+ // Capture Group, simple case
+ //
+ UnicodeString re2("a(..)");
+ RegexPattern *pat2 = RegexPattern::compile(re2, flags, pe, status);
+ REGEX_CHECK_STATUS;
+ UnicodeString d5 = "abcdefg";
+ RegexMatcher *matcher2 = pat2->matcher(d5, status);
+ REGEX_CHECK_STATUS;
+ dest = matcher2->replaceFirst("$1$1", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "bcbcdefg");
+
+ dest = matcher2->replaceFirst("The value of \\$1 is $1.", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "The value of $1 is bc.defg");
+
+ dest = matcher2->replaceFirst("$ by itself, no group number $$$", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "$ by itself, no group number $$$defg");
+
+ UnicodeString replacement = "Supplemental Digit 1 $\\U0001D7CF.";
+ replacement = replacement.unescape();
+ dest = matcher2->replaceFirst(replacement, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(dest == "Supplemental Digit 1 bc.defg");
+
+ REGEX_ASSERT_FAIL(matcher2->replaceFirst("bad capture group number $5...",status), U_INDEX_OUTOFBOUNDS_ERROR);
+
+
+ //
+ // Replacement String with \u hex escapes
+ //
+ {
+ UnicodeString src = "abc 1 abc 2 abc 3";
+ UnicodeString substitute = "--\\u0043--";
+ matcher->reset(src);
+ UnicodeString result = matcher->replaceAll(substitute, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(result == "--C-- 1 --C-- 2 --C-- 3");
+ }
+ {
+ UnicodeString src = "abc !";
+ UnicodeString substitute = "--\\U00010000--";
+ matcher->reset(src);
+ UnicodeString result = matcher->replaceAll(substitute, status);
+ REGEX_CHECK_STATUS;
+ UnicodeString expected = UnicodeString("--");
+ expected.append((UChar32)0x10000);
+ expected.append("-- !");
+ REGEX_ASSERT(result == expected);
+ }
+ // TODO: need more through testing of capture substitutions.
+
+ // Bug 4057
+ //
+ {
+ status = U_ZERO_ERROR;
+ UnicodeString s = "The matches start with ss and end with ee ss stuff ee fin";
+ RegexMatcher m("ss(.*?)ee", 0, status);
+ REGEX_CHECK_STATUS;
+ UnicodeString result;
+
+ // Multiple finds do NOT bump up the previous appendReplacement postion.
+ m.reset(s);
+ m.find();
+ m.find();
+ m.appendReplacement(result, "ooh", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(result == "The matches start with ss and end with ee ooh");
+
+ // After a reset into the interior of a string, appendReplacemnt still starts at beginning.
+ status = U_ZERO_ERROR;
+ result.truncate(0);
+ m.reset(10, status);
+ m.find();
+ m.find();
+ m.appendReplacement(result, "ooh", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(result == "The matches start with ss and end with ee ooh");
+
+ // find() at interior of string, appendReplacemnt still starts at beginning.
+ status = U_ZERO_ERROR;
+ result.truncate(0);
+ m.reset();
+ m.find(10, status);
+ m.find();
+ m.appendReplacement(result, "ooh", status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(result == "The matches start with ss and end with ee ooh");
+
+ m.appendTail(result);
+ REGEX_ASSERT(result == "The matches start with ss and end with ee ooh fin");
+
+ }
+
+ delete matcher2;
+ delete pat2;
+ delete matcher;
+ delete pat;
+}
+
+
+//---------------------------------------------------------------------------
+//
+// API_Pattern Test that the API for class RegexPattern is
+// present and nominally working.
+//
+//---------------------------------------------------------------------------
+void RegexTest::API_Pattern() {
+ RegexPattern pata; // Test default constructor to not crash.
+ RegexPattern patb;
+
+ REGEX_ASSERT(pata == patb);
+ REGEX_ASSERT(pata == pata);
+
+ UnicodeString re1("abc[a-l][m-z]");
+ UnicodeString re2("def");
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError pe;
+
+ RegexPattern *pat1 = RegexPattern::compile(re1, 0, pe, status);
+ RegexPattern *pat2 = RegexPattern::compile(re2, 0, pe, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(*pat1 == *pat1);
+ REGEX_ASSERT(*pat1 != pata);
+
+ // Assign
+ patb = *pat1;
+ REGEX_ASSERT(patb == *pat1);
+
+ // Copy Construct
+ RegexPattern patc(*pat1);
+ REGEX_ASSERT(patc == *pat1);
+ REGEX_ASSERT(patb == patc);
+ REGEX_ASSERT(pat1 != pat2);
+ patb = *pat2;
+ REGEX_ASSERT(patb != patc);
+ REGEX_ASSERT(patb == *pat2);
+
+ // Compile with no flags.
+ RegexPattern *pat1a = RegexPattern::compile(re1, pe, status);
+ REGEX_ASSERT(*pat1a == *pat1);
+
+ REGEX_ASSERT(pat1a->flags() == 0);
+
+ // Compile with different flags should be not equal
+ RegexPattern *pat1b = RegexPattern::compile(re1, UREGEX_CASE_INSENSITIVE, pe, status);
+ REGEX_CHECK_STATUS;
+
+ REGEX_ASSERT(*pat1b != *pat1a);
+ REGEX_ASSERT(pat1b->flags() == UREGEX_CASE_INSENSITIVE);
+ REGEX_ASSERT(pat1a->flags() == 0);
+ delete pat1b;
+
+ // clone
+ RegexPattern *pat1c = pat1->clone();
+ REGEX_ASSERT(*pat1c == *pat1);
+ REGEX_ASSERT(*pat1c != *pat2);
+
+ delete pat1c;
+ delete pat1a;
+ delete pat1;
+ delete pat2;
+
+
+ //
+ // Verify that a matcher created from a cloned pattern works.
+ // (Jitterbug 3423)
+ //
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ RegexPattern *pSource = RegexPattern::compile("\\p{L}+", 0, status);
+ RegexPattern *pClone = pSource->clone();
+ delete pSource;
+ RegexMatcher *mFromClone = pClone->matcher(status);
+ REGEX_CHECK_STATUS;
+ UnicodeString s = "Hello World";
+ mFromClone->reset(s);
+ REGEX_ASSERT(mFromClone->find() == TRUE);
+ REGEX_ASSERT(mFromClone->group(status) == "Hello");
+ REGEX_ASSERT(mFromClone->find() == TRUE);
+ REGEX_ASSERT(mFromClone->group(status) == "World");
+ REGEX_ASSERT(mFromClone->find() == FALSE);
+ delete mFromClone;
+ delete pClone;
+ }
+
+ //
+ // matches convenience API
+ //
+ REGEX_ASSERT(RegexPattern::matches(".*", "random input", pe, status) == TRUE);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(RegexPattern::matches("abc", "random input", pe, status) == FALSE);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(RegexPattern::matches(".*nput", "random input", pe, status) == TRUE);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(RegexPattern::matches("random input", "random input", pe, status) == TRUE);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(RegexPattern::matches(".*u", "random input", pe, status) == FALSE);
+ REGEX_CHECK_STATUS;
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ REGEX_ASSERT(RegexPattern::matches("abc", "abc", pe, status) == FALSE);
+ REGEX_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+
+
+ //
+ // Split()
+ //
+ status = U_ZERO_ERROR;
+ pat1 = RegexPattern::compile(" +", pe, status);
+ REGEX_CHECK_STATUS;
+ UnicodeString fields[10];
+
+ int32_t n;
+ n = pat1->split("Now is the time", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==4);
+ REGEX_ASSERT(fields[0]=="Now");
+ REGEX_ASSERT(fields[1]=="is");
+ REGEX_ASSERT(fields[2]=="the");
+ REGEX_ASSERT(fields[3]=="time");
+ REGEX_ASSERT(fields[4]=="");
+
+ n = pat1->split("Now is the time", fields, 2, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==2);
+ REGEX_ASSERT(fields[0]=="Now");
+ REGEX_ASSERT(fields[1]=="is the time");
+ REGEX_ASSERT(fields[2]=="the"); // left over from previous test
+
+ fields[1] = "*";
+ status = U_ZERO_ERROR;
+ n = pat1->split("Now is the time", fields, 1, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==1);
+ REGEX_ASSERT(fields[0]=="Now is the time");
+ REGEX_ASSERT(fields[1]=="*");
+ status = U_ZERO_ERROR;
+
+ n = pat1->split(" Now is the time ", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==5);
+ REGEX_ASSERT(fields[0]=="");
+ REGEX_ASSERT(fields[1]=="Now");
+ REGEX_ASSERT(fields[2]=="is");
+ REGEX_ASSERT(fields[3]=="the");
+ REGEX_ASSERT(fields[4]=="time");
+ REGEX_ASSERT(fields[5]=="");
+
+ n = pat1->split(" ", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==1);
+ REGEX_ASSERT(fields[0]=="");
+
+ fields[0] = "foo";
+ n = pat1->split("", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==0);
+ REGEX_ASSERT(fields[0]=="foo");
+
+ delete pat1;
+
+ // split, with a pattern with (capture)
+ pat1 = RegexPattern::compile("<(\\w*)>", pe, status);
+ REGEX_CHECK_STATUS;
+
+ status = U_ZERO_ERROR;
+ n = pat1->split("<a>Now is <b>the time<c>", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==6);
+ REGEX_ASSERT(fields[0]=="");
+ REGEX_ASSERT(fields[1]=="a");
+ REGEX_ASSERT(fields[2]=="Now is ");
+ REGEX_ASSERT(fields[3]=="b");
+ REGEX_ASSERT(fields[4]=="the time");
+ REGEX_ASSERT(fields[5]=="c");
+ REGEX_ASSERT(fields[6]=="");
+ REGEX_ASSERT(status==U_ZERO_ERROR);
+
+ n = pat1->split(" <a>Now is <b>the time<c>", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==6);
+ REGEX_ASSERT(fields[0]==" ");
+ REGEX_ASSERT(fields[1]=="a");
+ REGEX_ASSERT(fields[2]=="Now is ");
+ REGEX_ASSERT(fields[3]=="b");
+ REGEX_ASSERT(fields[4]=="the time");
+ REGEX_ASSERT(fields[5]=="c");
+ REGEX_ASSERT(fields[6]=="");
+
+ status = U_ZERO_ERROR;
+ fields[6] = "foo";
+ n = pat1->split(" <a>Now is <b>the time<c>", fields, 6, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==6);
+ REGEX_ASSERT(fields[0]==" ");
+ REGEX_ASSERT(fields[1]=="a");
+ REGEX_ASSERT(fields[2]=="Now is ");
+ REGEX_ASSERT(fields[3]=="b");
+ REGEX_ASSERT(fields[4]=="the time");
+ REGEX_ASSERT(fields[5]=="c");
+ REGEX_ASSERT(fields[6]=="foo");
+
+ status = U_ZERO_ERROR;
+ fields[5] = "foo";
+ n = pat1->split(" <a>Now is <b>the time<c>", fields, 5, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==5);
+ REGEX_ASSERT(fields[0]==" ");
+ REGEX_ASSERT(fields[1]=="a");
+ REGEX_ASSERT(fields[2]=="Now is ");
+ REGEX_ASSERT(fields[3]=="b");
+ REGEX_ASSERT(fields[4]=="the time<c>");
+ REGEX_ASSERT(fields[5]=="foo");
+
+ status = U_ZERO_ERROR;
+ fields[5] = "foo";
+ n = pat1->split(" <a>Now is <b>the time", fields, 5, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==5);
+ REGEX_ASSERT(fields[0]==" ");
+ REGEX_ASSERT(fields[1]=="a");
+ REGEX_ASSERT(fields[2]=="Now is ");
+ REGEX_ASSERT(fields[3]=="b");
+ REGEX_ASSERT(fields[4]=="the time");
+ REGEX_ASSERT(fields[5]=="foo");
+
+ status = U_ZERO_ERROR;
+ n = pat1->split(" <a>Now is <b>the time<c>", fields, 4, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==4);
+ REGEX_ASSERT(fields[0]==" ");
+ REGEX_ASSERT(fields[1]=="a");
+ REGEX_ASSERT(fields[2]=="Now is ");
+ REGEX_ASSERT(fields[3]=="the time<c>");
+ status = U_ZERO_ERROR;
+ delete pat1;
+
+ pat1 = RegexPattern::compile("([-,])", pe, status);
+ REGEX_CHECK_STATUS;
+ n = pat1->split("1-10,20", fields, 10, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(n==5);
+ REGEX_ASSERT(fields[0]=="1");
+ REGEX_ASSERT(fields[1]=="-");
+ REGEX_ASSERT(fields[2]=="10");
+ REGEX_ASSERT(fields[3]==",");
+ REGEX_ASSERT(fields[4]=="20");
+ delete pat1;
+
+
+ //
+ // RegexPattern::pattern()
+ //
+ pat1 = new RegexPattern();
+ REGEX_ASSERT(pat1->pattern() == "");
+ delete pat1;
+
+ pat1 = RegexPattern::compile("(Hello, world)*", pe, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(pat1->pattern() == "(Hello, world)*");
+ delete pat1;
+
+
+ //
+ // classID functions
+ //
+ pat1 = RegexPattern::compile("(Hello, world)*", pe, status);
+ REGEX_CHECK_STATUS;
+ REGEX_ASSERT(pat1->getDynamicClassID() == RegexPattern::getStaticClassID());
+ REGEX_ASSERT(pat1->getDynamicClassID() != NULL);
+ UnicodeString Hello("Hello, world.");
+ RegexMatcher *m = pat1->matcher(Hello, status);
+ REGEX_ASSERT(pat1->getDynamicClassID() != m->getDynamicClassID());
+ REGEX_ASSERT(m->getDynamicClassID() == RegexMatcher::getStaticClassID());
+ REGEX_ASSERT(m->getDynamicClassID() != NULL);
+ delete m;
+ delete pat1;
+
+}
+
+//---------------------------------------------------------------------------
+//
+// Extended A more thorough check for features of regex patterns
+// The test cases are in a separate data file,
+// source/tests/testdata/regextst.txt
+// A description of the test data format is included in that file.
+//
+//---------------------------------------------------------------------------
+
+const char *
+RegexTest::getPath(char buffer[2048], const char *filename) {
+ UErrorCode status=U_ZERO_ERROR;
+ const char *testDataDirectory = IntlTest::getSourceTestData(status);
+ if (U_FAILURE(status)) {
+ errln("ERROR: loadTestData() failed - %s", u_errorName(status));
+ return NULL;
+ }
+
+ strcpy(buffer, testDataDirectory);
+ strcat(buffer, filename);
+ return buffer;
+}
+
+void RegexTest::Extended() {
+ char tdd[2048];
+ const char *srcPath;
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t lineNum = 0;
+
+ //
+ // Open and read the test data file.
+ //
+ srcPath=getPath(tdd, "regextst.txt");
+ if(srcPath==NULL) {
+ return; /* something went wrong, error already output */
+ }
+
+ int32_t len;
+ UChar *testData = ReadAndConvertFile(srcPath, len, status);
+ if (U_FAILURE(status)) {
+ return; /* something went wrong, error already output */
+ }
+
+ //
+ // Put the test data into a UnicodeString
+ //
+ UnicodeString testString(FALSE, testData, len);
+
+ RegexMatcher quotedStuffMat("\\s*([\\'\\\"/])(.*?)\\1", 0, status);
+ RegexMatcher commentMat ("\\s*(#.*)?$", 0, status);
+ RegexMatcher flagsMat ("\\s*([ixsmdtGv2-9]*)([:letter:]*)", 0, status);
+
+ RegexMatcher lineMat("(.*?)\\r?\\n", testString, 0, status);
+ UnicodeString testPattern; // The pattern for test from the test file.
+ UnicodeString testFlags; // the flags for a test.
+ UnicodeString matchString; // The marked up string to be used as input
+
+ if (U_FAILURE(status)){
+ dataerrln("Construct RegexMatcher() error.");
+ delete [] testData;
+ return;
+ }
+
+ //
+ // Loop over the test data file, once per line.
+ //
+ while (lineMat.find()) {
+ lineNum++;
+ if (U_FAILURE(status)) {
+ errln("line %d: ICU Error \"%s\"", lineNum, u_errorName(status));
+ }
+
+ status = U_ZERO_ERROR;
+ UnicodeString testLine = lineMat.group(1, status);
+ if (testLine.length() == 0) {
+ continue;
+ }
+
+ //
+ // Parse the test line. Skip blank and comment only lines.
+ // Separate out the three main fields - pattern, flags, target.
+ //
+
+ commentMat.reset(testLine);
+ if (commentMat.lookingAt(status)) {
+ // This line is a comment, or blank.
+ continue;
+ }
+
+ //
+ // Pull out the pattern field, remove it from the test file line.
+ //
+ quotedStuffMat.reset(testLine);
+ if (quotedStuffMat.lookingAt(status)) {
+ testPattern = quotedStuffMat.group(2, status);
+ testLine.remove(0, quotedStuffMat.end(0, status));
+ } else {
+ errln("Bad pattern (missing quotes?) at test file line %d", lineNum);
+ continue;
+ }
+
+
+ //
+ // Pull out the flags from the test file line.
+ //
+ flagsMat.reset(testLine);
+ flagsMat.lookingAt(status); // Will always match, possibly an empty string.
+ testFlags = flagsMat.group(1, status);
+ if (flagsMat.group(2, status).length() > 0) {
+ errln("Bad Match flag at line %d. Scanning %c\n",
+ lineNum, flagsMat.group(2, status).charAt(0));
+ continue;
+ }
+ testLine.remove(0, flagsMat.end(0, status));
+
+ //
+ // Pull out the match string, as a whole.
+ // We'll process the <tags> later.
+ //
+ quotedStuffMat.reset(testLine);
+ if (quotedStuffMat.lookingAt(status)) {
+ matchString = quotedStuffMat.group(2, status);
+ testLine.remove(0, quotedStuffMat.end(0, status));
+ } else {
+ errln("Bad match string at test file line %d", lineNum);
+ continue;
+ }
+
+ //
+ // The only thing left from the input line should be an optional trailing comment.
+ //
+ commentMat.reset(testLine);
+ if (commentMat.lookingAt(status) == FALSE) {
+ errln("Line %d: unexpected characters at end of test line.", lineNum);
+ continue;
+ }
+
+ //
+ // Run the test
+ //
+ regex_find(testPattern, testFlags, matchString, lineNum);
+ }
+
+ delete [] testData;
+
+}
+
+
+
+//---------------------------------------------------------------------------
+//
+// Errors Check for error handling in patterns.
+//
+//---------------------------------------------------------------------------
+void RegexTest::Errors() {
+ // \escape sequences that aren't implemented yet.
+ //REGEX_ERR("hex format \\x{abcd} not implemented", 1, 13, U_REGEX_UNIMPLEMENTED);
+
+ // Missing close parentheses
+ REGEX_ERR("Comment (?# with no close", 1, 25, U_REGEX_MISMATCHED_PAREN);
+ REGEX_ERR("Capturing Parenthesis(...", 1, 25, U_REGEX_MISMATCHED_PAREN);
+ REGEX_ERR("Grouping only parens (?: blah blah", 1, 34, U_REGEX_MISMATCHED_PAREN);
+
+ // Extra close paren
+ REGEX_ERR("Grouping only parens (?: blah)) blah", 1, 31, U_REGEX_MISMATCHED_PAREN);
+ REGEX_ERR(")))))))", 1, 1, U_REGEX_MISMATCHED_PAREN);
+ REGEX_ERR("(((((((", 1, 7, U_REGEX_MISMATCHED_PAREN);
+
+ // Look-ahead, Look-behind
+ // TODO: add tests for unbounded length look-behinds.
+ REGEX_ERR("abc(?<@xyz).*", 1, 7, U_REGEX_RULE_SYNTAX); // illegal construct
+
+ // Attempt to use non-default flags
+ {
+ UParseError pe;
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t flags = UREGEX_CANON_EQ |
+ UREGEX_COMMENTS | UREGEX_DOTALL |
+ UREGEX_MULTILINE;
+ RegexPattern *pat1= RegexPattern::compile(".*", flags, pe, status);
+ REGEX_ASSERT(status == U_REGEX_UNIMPLEMENTED);
+ delete pat1;
+ }
+
+
+ // Quantifiers are allowed only after something that can be quantified.
+ REGEX_ERR("+", 1, 1, U_REGEX_RULE_SYNTAX);
+ REGEX_ERR("abc\ndef(*2)", 2, 5, U_REGEX_RULE_SYNTAX);
+ REGEX_ERR("abc**", 1, 5, U_REGEX_RULE_SYNTAX);
+
+ // Mal-formed {min,max} quantifiers
+ REGEX_ERR("abc{a,2}",1,5, U_REGEX_BAD_INTERVAL);
+ REGEX_ERR("abc{4,2}",1,8, U_REGEX_MAX_LT_MIN);
+ REGEX_ERR("abc{1,b}",1,7, U_REGEX_BAD_INTERVAL);
+ REGEX_ERR("abc{1,,2}",1,7, U_REGEX_BAD_INTERVAL);
+ REGEX_ERR("abc{1,2a}",1,8, U_REGEX_BAD_INTERVAL);
+ REGEX_ERR("abc{222222222222222222222}",1,14, U_REGEX_NUMBER_TOO_BIG);
+ REGEX_ERR("abc{5,50000000000}", 1, 17, U_REGEX_NUMBER_TOO_BIG); // Overflows int during scan
+ REGEX_ERR("abc{5,687865858}", 1, 16, U_REGEX_NUMBER_TOO_BIG); // Overflows regex binary format
+ REGEX_ERR("abc{687865858,687865859}", 1, 24, U_REGEX_NUMBER_TOO_BIG);
+
+
+ // UnicodeSet containing a string
+ REGEX_ERR("abc[{def}]xyz", 1, 10, U_REGEX_SET_CONTAINS_STRING);
+
+ // Ticket 5389
+ REGEX_ERR("*c", 1, 1, U_REGEX_RULE_SYNTAX);
+
+}
+
+
+//-------------------------------------------------------------------------------
+//
+// Read a text data file, convert it to UChars, and return the data
+// in one big UChar * buffer, which the caller must delete.
+//
+//--------------------------------------------------------------------------------
+UChar *RegexTest::ReadAndConvertFile(const char *fileName, int32_t &ulen, UErrorCode &status) {
+ UChar *retPtr = NULL;
+ char *fileBuf = NULL;
+ UConverter* conv = NULL;
+ FILE *f = NULL;
+
+ ulen = 0;
+ if (U_FAILURE(status)) {
+ return retPtr;
+ }
+
+ //
+ // Open the file.
+ //
+ f = fopen(fileName, "rb");
+ if (f == 0) {
+ errln("Error opening test data file %s\n", fileName);
+ status = U_FILE_ACCESS_ERROR;
+ return NULL;
+ }
+ //
+ // Read it in
+ //
+ int32_t fileSize;
+ int32_t amt_read;
+
+ fseek( f, 0, SEEK_END);
+ fileSize = ftell(f);
+ fileBuf = new char[fileSize];
+ fseek(f, 0, SEEK_SET);
+ amt_read = fread(fileBuf, 1, fileSize, f);
+ if (amt_read != fileSize || fileSize <= 0) {
+ errln("Error reading test data file.");
+ goto cleanUpAndReturn;
+ }
+
+ //
+ // Look for a Unicode Signature (BOM) on the data just read
+ //
+ int32_t signatureLength;
+ const char * fileBufC;
+ const char* encoding;
+
+ fileBufC = fileBuf;
+ encoding = ucnv_detectUnicodeSignature(
+ fileBuf, fileSize, &signatureLength, &status);
+ if(encoding!=NULL ){
+ fileBufC += signatureLength;
+ fileSize -= signatureLength;
+ }
+
+ //
+ // Open a converter to take the rule file to UTF-16
+ //
+ conv = ucnv_open(encoding, &status);
+ if (U_FAILURE(status)) {
+ goto cleanUpAndReturn;
+ }
+
+ //
+ // Convert the rules to UChar.
+ // Preflight first to determine required buffer size.
+ //
+ ulen = ucnv_toUChars(conv,
+ NULL, // dest,
+ 0, // destCapacity,
+ fileBufC,
+ fileSize,
+ &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ // Buffer Overflow is expected from the preflight operation.
+ status = U_ZERO_ERROR;
+
+ retPtr = new UChar[ulen+1];
+ ucnv_toUChars(conv,
+ retPtr, // dest,
+ ulen+1,
+ fileBufC,
+ fileSize,
+ &status);
+ }
+
+cleanUpAndReturn:
+ fclose(f);
+ delete[] fileBuf;
+ ucnv_close(conv);
+ if (U_FAILURE(status)) {
+ errln("ucnv_toUChars: ICU Error \"%s\"\n", u_errorName(status));
+ delete retPtr;
+ retPtr = 0;
+ ulen = 0;
+ };
+ return retPtr;
+}
+
+
+//-------------------------------------------------------------------------------
+//
+// PerlTests - Run Perl's regular expression tests
+// The input file for this test is re_tests, the standard regular
+// expression test data distributed with the Perl source code.
+//
+// Here is Perl's description of the test data file:
+//
+// # The tests are in a separate file 't/op/re_tests'.
+// # Each line in that file is a separate test.
+// # There are five columns, separated by tabs.
+// #
+// # Column 1 contains the pattern, optionally enclosed in C<''>.
+// # Modifiers can be put after the closing C<'>.
+// #
+// # Column 2 contains the string to be matched.
+// #
+// # Column 3 contains the expected result:
+// # y expect a match
+// # n expect no match
+// # c expect an error
+// # B test exposes a known bug in Perl, should be skipped
+// # b test exposes a known bug in Perl, should be skipped if noamp
+// #
+// # Columns 4 and 5 are used only if column 3 contains C<y> or C<c>.
+// #
+// # Column 4 contains a string, usually C<$&>.
+// #
+// # Column 5 contains the expected result of double-quote
+// # interpolating that string after the match, or start of error message.
+// #
+// # Column 6, if present, contains a reason why the test is skipped.
+// # This is printed with "skipped", for harness to pick up.
+// #
+// # \n in the tests are interpolated, as are variables of the form ${\w+}.
+// #
+// # If you want to add a regular expression test that can't be expressed
+// # in this format, don't add it here: put it in op/pat.t instead.
+//
+// For ICU, if field 3 contains an 'i', the test will be skipped.
+// The test exposes is some known incompatibility between ICU and Perl regexps.
+// (The i is in addition to whatever was there before.)
+//
+//-------------------------------------------------------------------------------
+void RegexTest::PerlTests() {
+ char tdd[2048];
+ const char *srcPath;
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError pe;
+
+ //
+ // Open and read the test data file.
+ //
+ srcPath=getPath(tdd, "re_tests.txt");
+ if(srcPath==NULL) {
+ return; /* something went wrong, error already output */
+ }
+
+ int32_t len;
+ UChar *testData = ReadAndConvertFile(srcPath, len, status);
+ if (U_FAILURE(status)) {
+ return; /* something went wrong, error already output */
+ }
+
+ //
+ // Put the test data into a UnicodeString
+ //
+ UnicodeString testDataString(FALSE, testData, len);
+
+ //
+ // Regex to break the input file into lines, and strip the new lines.
+ // One line per match, capture group one is the desired data.
+ //
+ RegexPattern* linePat = RegexPattern::compile("(.+?)[\\r\\n]+", 0, pe, status);
+ if (U_FAILURE(status)) {
+ dataerrln("RegexPattern::compile() error");
+ return;
+ }
+ RegexMatcher* lineMat = linePat->matcher(testDataString, status);
+
+ //
+ // Regex to split a test file line into fields.
+ // There are six fields, separated by tabs.
+ //
+ RegexPattern* fieldPat = RegexPattern::compile("\\t", 0, pe, status);
+
+ //
+ // Regex to identify test patterns with flag settings, and to separate them.
+ // Test patterns with flags look like 'pattern'i
+ // Test patterns without flags are not quoted: pattern
+ // Coming out, capture group 2 is the pattern, capture group 3 is the flags.
+ //
+ RegexPattern *flagPat = RegexPattern::compile("('?)(.*)\\1(.*)", 0, pe, status);
+ RegexMatcher* flagMat = flagPat->matcher(status);
+
+ //
+ // The Perl tests reference several perl-isms, which are evaluated/substituted
+ // in the test data. Not being perl, this must be done explicitly. Here
+ // are string constants and REs for these constructs.
+ //
+ UnicodeString nulnulSrc("${nulnul}");
+ UnicodeString nulnul("\\u0000\\u0000");
+ nulnul = nulnul.unescape();
+
+ UnicodeString ffffSrc("${ffff}");
+ UnicodeString ffff("\\uffff");
+ ffff = ffff.unescape();
+
+ // regexp for $-[0], $+[2], etc.
+ RegexPattern *groupsPat = RegexPattern::compile("\\$([+\\-])\\[(\\d+)\\]", 0, pe, status);
+ RegexMatcher *groupsMat = groupsPat->matcher(status);
+
+ // regexp for $0, $1, $2, etc.
+ RegexPattern *cgPat = RegexPattern::compile("\\$(\\d+)", 0, pe, status);
+ RegexMatcher *cgMat = cgPat->matcher(status);
+
+
+ //
+ // Main Loop for the Perl Tests, runs once per line from the
+ // test data file.
+ //
+ int32_t lineNum = 0;
+ int32_t skippedUnimplementedCount = 0;
+ while (lineMat->find()) {
+ lineNum++;
+
+ //
+ // Get a line, break it into its fields, do the Perl
+ // variable substitutions.
+ //
+ UnicodeString line = lineMat->group(1, status);
+ UnicodeString fields[7];
+ fieldPat->split(line, fields, 7, status);
+
+ flagMat->reset(fields[0]);
+ flagMat->matches(status);
+ UnicodeString pattern = flagMat->group(2, status);
+ pattern.findAndReplace("${bang}", "!");
+ pattern.findAndReplace(nulnulSrc, "\\u0000\\u0000");
+ pattern.findAndReplace(ffffSrc, ffff);
+
+ //
+ // Identify patterns that include match flag settings,
+ // split off the flags, remove the extra quotes.
+ //
+ UnicodeString flagStr = flagMat->group(3, status);
+ if (U_FAILURE(status)) {
+ errln("ucnv_toUChars: ICU Error \"%s\"\n", u_errorName(status));
+ return;
+ }
+ int32_t flags = 0;
+ const UChar UChar_c = 0x63; // Char constants for the flag letters.
+ const UChar UChar_i = 0x69; // (Damn the lack of Unicode support in C)
+ const UChar UChar_m = 0x6d;
+ const UChar UChar_x = 0x78;
+ const UChar UChar_y = 0x79;
+ if (flagStr.indexOf(UChar_i) != -1) {
+ flags |= UREGEX_CASE_INSENSITIVE;
+ }
+ if (flagStr.indexOf(UChar_m) != -1) {
+ flags |= UREGEX_MULTILINE;
+ }
+ if (flagStr.indexOf(UChar_x) != -1) {
+ flags |= UREGEX_COMMENTS;
+ }
+
+ //
+ // Compile the test pattern.
+ //
+ status = U_ZERO_ERROR;
+ RegexPattern *testPat = RegexPattern::compile(pattern, flags, pe, status);
+ if (status == U_REGEX_UNIMPLEMENTED) {
+ //
+ // Test of a feature that is planned for ICU, but not yet implemented.
+ // skip the test.
+ skippedUnimplementedCount++;
+ delete testPat;
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ if (U_FAILURE(status)) {
+ // Some tests are supposed to generate errors.
+ // Only report an error for tests that are supposed to succeed.
+ if (fields[2].indexOf(UChar_c) == -1 && // Compilation is not supposed to fail AND
+ fields[2].indexOf(UChar_i) == -1) // it's not an accepted ICU incompatibility
+ {
+ errln("line %d: ICU Error \"%s\"\n", lineNum, u_errorName(status));
+ }
+ status = U_ZERO_ERROR;
+ delete testPat;
+ continue;
+ }
+
+ if (fields[2].indexOf(UChar_i) >= 0) {
+ // ICU should skip this test.
+ delete testPat;
+ continue;
+ }
+
+ if (fields[2].indexOf(UChar_c) >= 0) {
+ // This pattern should have caused a compilation error, but didn't/
+ errln("line %d: Expected a pattern compile error, got success.", lineNum);
+ delete testPat;
+ continue;
+ }
+
+ //
+ // replace the Perl variables that appear in some of the
+ // match data strings.
+ //
+ UnicodeString matchString = fields[1];
+ matchString.findAndReplace(nulnulSrc, nulnul);
+ matchString.findAndReplace(ffffSrc, ffff);
+
+ // Replace any \n in the match string with an actual new-line char.
+ // Don't do full unescape, as this unescapes more than Perl does, which
+ // causes other spurious failures in the tests.
+ matchString.findAndReplace("\\n", "\n");
+
+
+
+ //
+ // Run the test, check for expected match/don't match result.
+ //
+ RegexMatcher *testMat = testPat->matcher(matchString, status);
+ UBool found = testMat->find();
+ UBool expected = FALSE;
+ if (fields[2].indexOf(UChar_y) >=0) {
+ expected = TRUE;
+ }
+ if (expected != found) {
+ errln("line %d: Expected %smatch, got %smatch",
+ lineNum, expected?"":"no ", found?"":"no " );
+ continue;
+ }
+
+ //
+ // Interpret the Perl expression from the fourth field of the data file,
+ // building up an ICU string from the results of the ICU match.
+ // The Perl expression will contain references to the results of
+ // a regex match, including the matched string, capture group strings,
+ // group starting and ending indicies, etc.
+ //
+ UnicodeString resultString;
+ UnicodeString perlExpr = fields[3];
+ groupsMat->reset(perlExpr);
+ cgMat->reset(perlExpr);
+
+ while (perlExpr.length() > 0) {
+ if (perlExpr.startsWith("$&")) {
+ resultString.append(testMat->group(status));
+ perlExpr.remove(0, 2);
+ }
+
+ else if (groupsMat->lookingAt(status)) {
+ // $-[0] $+[2] etc.
+ UnicodeString digitString = groupsMat->group(2, status);
+ int32_t t = 0;
+ int32_t groupNum = ICU_Utility::parseNumber(digitString, t, 10);
+ UnicodeString plusOrMinus = groupsMat->group(1, status);
+ int32_t matchPosition;
+ if (plusOrMinus.compare("+") == 0) {
+ matchPosition = testMat->end(groupNum, status);
+ } else {
+ matchPosition = testMat->start(groupNum, status);
+ }
+ if (matchPosition != -1) {
+ ICU_Utility::appendNumber(resultString, matchPosition);
+ }
+ perlExpr.remove(0, groupsMat->end(status));
+ }
+
+ else if (cgMat->lookingAt(status)) {
+ // $1, $2, $3, etc.
+ UnicodeString digitString = cgMat->group(1, status);
+ int32_t t = 0;
+ int32_t groupNum = ICU_Utility::parseNumber(digitString, t, 10);
+ if (U_SUCCESS(status)) {
+ resultString.append(testMat->group(groupNum, status));
+ status = U_ZERO_ERROR;
+ }
+ perlExpr.remove(0, cgMat->end(status));
+ }
+
+ else if (perlExpr.startsWith("@-")) {
+ int32_t i;
+ for (i=0; i<=testMat->groupCount(); i++) {
+ if (i>0) {
+ resultString.append(" ");
+ }
+ ICU_Utility::appendNumber(resultString, testMat->start(i, status));
+ }
+ perlExpr.remove(0, 2);
+ }
+
+ else if (perlExpr.startsWith("@+")) {
+ int32_t i;
+ for (i=0; i<=testMat->groupCount(); i++) {
+ if (i>0) {
+ resultString.append(" ");
+ }
+ ICU_Utility::appendNumber(resultString, testMat->end(i, status));
+ }
+ perlExpr.remove(0, 2);
+ }
+
+ else if (perlExpr.startsWith("\\")) { // \Escape. Take following char as a literal.
+ // or as an escaped sequence (e.g. \n)
+ if (perlExpr.length() > 1) {
+ perlExpr.remove(0, 1); // Remove the '\', but only if not last char.
+ }
+ UChar c = perlExpr.charAt(0);
+ switch (c) {
+ case 'n': c = '\n'; break;
+ // add any other escape sequences that show up in the test expected results.
+ }
+ resultString.append(c);
+ perlExpr.remove(0, 1);
+ }
+
+ else {
+ // Any characters from the perl expression that we don't explicitly
+ // recognize before here are assumed to be literals and copied
+ // as-is to the expected results.
+ resultString.append(perlExpr.charAt(0));
+ perlExpr.remove(0, 1);
+ }
+
+ if (U_FAILURE(status)) {
+ errln("Line %d: ICU Error \"%s\"", lineNum, u_errorName(status));
+ break;
+ }
+ }
+
+ //
+ // Expected Results Compare
+ //
+ UnicodeString expectedS(fields[4]);
+ expectedS.findAndReplace(nulnulSrc, nulnul);
+ expectedS.findAndReplace(ffffSrc, ffff);
+ expectedS.findAndReplace("\\n", "\n");
+
+
+ if (expectedS.compare(resultString) != 0) {
+ err("Line %d: Incorrect perl expression results.", lineNum);
+ errln((UnicodeString)"Expected \""+expectedS+(UnicodeString)"\"; got \""+resultString+(UnicodeString)"\"");
+ }
+
+ delete testMat;
+ delete testPat;
+ }
+
+ //
+ // All done. Clean up allocated stuff.
+ //
+ delete cgMat;
+ delete cgPat;
+
+ delete groupsMat;
+ delete groupsPat;
+
+ delete flagMat;
+ delete flagPat;
+
+ delete lineMat;
+ delete linePat;
+
+ delete fieldPat;
+ delete [] testData;
+
+
+ logln("%d tests skipped because of unimplemented regexp features.", skippedUnimplementedCount);
+
+}
+
+
+
+#endif /* !UCONFIG_NO_REGULAR_EXPRESSIONS */
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/regextst.h b/Build/source/libs/icu/icu-xetex/test/intltest/regextst.h
new file mode 100644
index 00000000000..6636a622d48
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/regextst.h
@@ -0,0 +1,46 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#ifndef REGEXTST_H
+#define REGEXTST_H
+
+#include "unicode/utypes.h"
+#if !UCONFIG_NO_REGULAR_EXPRESSIONS
+
+#include "intltest.h"
+
+
+class RegexTest: public IntlTest {
+public:
+
+ RegexTest();
+ virtual ~RegexTest();
+
+ virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // The following are test functions that are visible from the intltest test framework.
+ virtual void API_Match();
+ virtual void API_Pattern();
+ virtual void API_Replace();
+ virtual void Basic();
+ virtual void Extended();
+ virtual void Errors();
+ virtual void PerlTests();
+
+ // The following functions are internal to the regexp tests.
+ virtual UBool doRegexLMTest(const char *pat, const char *text, UBool looking, UBool match, int32_t line);
+ virtual void regex_find(const UnicodeString &pat, const UnicodeString &flags,
+ const UnicodeString &input, int32_t line);
+ virtual void regex_err(const char *pat, int32_t errline, int32_t errcol,
+ UErrorCode expectedStatus, int32_t line);
+ virtual UChar *ReadAndConvertFile(const char *fileName, int32_t &len, UErrorCode &status);
+ virtual const char *getPath(char buffer[2048], const char *filename);
+
+};
+
+#endif // !UCONFIG_NO_REGULAR_EXPRESSIONS
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/reptest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/reptest.cpp
new file mode 100644
index 00000000000..d203fed5347
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/reptest.cpp
@@ -0,0 +1,322 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2001-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/************************************************************************
+* This test program is intended for testing Replaceable class.
+*
+* Date Name Description
+* 11/28/2001 hshih Ported back from Java.
+*
+************************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "ittrans.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "unicode/rep.h"
+#include "reptest.h"
+
+//---------------------------------------------
+// runIndexedTest
+//---------------------------------------------
+
+ /**
+ * This is a test class that simulates styled text.
+ * It associates a style number (0..65535) with each character,
+ * and maintains that style in the normal fashion:
+ * When setting text from raw string or characters,<br>
+ * Set the styles to the style of the first character replaced.<br>
+ * If no characters are replaced, use the style of the previous character.<br>
+ * If at start, use the following character<br>
+ * Otherwise use NO_STYLE.
+ */
+class TestReplaceable : public Replaceable {
+ UnicodeString chars;
+ UnicodeString styles;
+
+ static const UChar NO_STYLE;
+
+ static const UChar NO_STYLE_MARK;
+
+ /**
+ * The address of this static class variable serves as this class's ID
+ * for ICU "poor man's RTTI".
+ */
+ static const char fgClassID;
+
+public:
+ TestReplaceable (const UnicodeString& text,
+ const UnicodeString& newStyles) {
+ chars = text;
+ UnicodeString s;
+ for (int i = 0; i < text.length(); ++i) {
+ if (i < newStyles.length()) {
+ s.append(newStyles.charAt(i));
+ } else {
+ if (text.charAt(i) == NO_STYLE_MARK) {
+ s.append(NO_STYLE);
+ } else {
+ s.append((UChar)(i + 0x0031));
+ }
+ }
+ }
+ this->styles = s;
+ }
+
+ virtual Replaceable *clone() const {
+ return new TestReplaceable(chars, styles);
+ }
+
+ ~TestReplaceable(void) {}
+
+ UnicodeString getStyles() {
+ return styles;
+ }
+
+ UnicodeString toString() {
+ UnicodeString s = chars;
+ s.append("{");
+ s.append(styles);
+ s.append("}");
+ return s;
+ }
+
+ void extractBetween(int32_t start, int32_t limit, UnicodeString& result) const {
+ chars.extractBetween(start, limit, result);
+ }
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+protected:
+ virtual int32_t getLength() const {
+ return chars.length();
+ }
+
+ virtual UChar getCharAt(int32_t offset) const{
+ return chars.charAt(offset);
+ }
+
+ virtual UChar32 getChar32At(int32_t offset) const{
+ return chars.char32At(offset);
+ }
+
+ void fixStyles(int32_t start, int32_t limit, int32_t newLen) {
+ UChar newStyle = NO_STYLE;
+ if (start != limit && styles.charAt(start) != NO_STYLE) {
+ newStyle = styles.charAt(start);
+ } else if (start > 0 && getCharAt(start-1) != NO_STYLE_MARK) {
+ newStyle = styles.charAt(start-1);
+ } else if (limit < styles.length()) {
+ newStyle = styles.charAt(limit);
+ }
+ // dumb implementation for now.
+ UnicodeString s;
+ for (int i = 0; i < newLen; ++i) {
+ // this doesn't really handle an embedded NO_STYLE_MARK
+ // in the middle of a long run of characters right -- but
+ // that case shouldn't happen anyway
+ if (getCharAt(start+i) == NO_STYLE_MARK) {
+ s.append(NO_STYLE);
+ } else {
+ s.append(newStyle);
+ }
+ }
+ styles.replaceBetween(start, limit, s);
+ }
+
+ virtual void handleReplaceBetween(int32_t start, int32_t limit, const UnicodeString& text) {
+ UnicodeString s;
+ this->extractBetween(start, limit, s);
+ if (s == text) return; // NO ACTION!
+ this->chars.replaceBetween(start, limit, text);
+ fixStyles(start, limit, text.length());
+ }
+
+
+ virtual void copy(int32_t start, int32_t limit, int32_t dest) {
+ chars.copy(start, limit, dest);
+ styles.copy(start, limit, dest);
+ }
+};
+
+const char TestReplaceable::fgClassID=0;
+
+const UChar TestReplaceable::NO_STYLE = 0x005F;
+
+const UChar TestReplaceable::NO_STYLE_MARK = 0xFFFF;
+
+void
+ReplaceableTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ TESTCASE(0,TestReplaceableClass);
+ default: name = ""; break;
+ }
+}
+
+/*
+ * Dummy Replaceable implementation for better API/code coverage.
+ */
+class NoopReplaceable : public Replaceable {
+public:
+ virtual int32_t getLength() const {
+ return 0;
+ }
+
+ virtual UChar getCharAt(int32_t /*offset*/) const{
+ return 0xffff;
+ }
+
+ virtual UChar32 getChar32At(int32_t /*offset*/) const{
+ return 0xffff;
+ }
+
+ void extractBetween(int32_t /*start*/, int32_t /*limit*/, UnicodeString& result) const {
+ result.remove();
+ }
+
+ virtual void handleReplaceBetween(int32_t /*start*/, int32_t /*limit*/, const UnicodeString &/*text*/) {
+ /* do nothing */
+ }
+
+ virtual void copy(int32_t /*start*/, int32_t /*limit*/, int32_t /*dest*/) {
+ /* do nothing */
+ }
+
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+private:
+ static const char fgClassID;
+};
+
+const char NoopReplaceable::fgClassID=0;
+
+void ReplaceableTest::TestReplaceableClass(void) {
+ UChar rawTestArray[][6] = {
+ {0x0041, 0x0042, 0x0043, 0x0044, 0x0000, 0x0000}, // ABCD
+ {0x0061, 0x0062, 0x0063, 0x0064, 0x00DF, 0x0000}, // abcd\u00DF
+ {0x0061, 0x0042, 0x0043, 0x0044, 0x0000, 0x0000}, // aBCD
+ {0x0041, 0x0300, 0x0045, 0x0300, 0x0000, 0x0000}, // A\u0300E\u0300
+ {0x00C0, 0x00C8, 0x0000, 0x0000, 0x0000, 0x0000}, // \u00C0\u00C8
+ {0x0077, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "wxy" */
+ {0x0077, 0x0078, 0x0079, 0x007A, 0x0000, 0x0000}, /* "wxyz" */
+ {0x0077, 0x0078, 0x0079, 0x007A, 0x0075, 0x0000}, /* "wxyzu" */
+ {0x0078, 0x0079, 0x007A, 0x0000, 0x0000, 0x0000}, /* "xyz" */
+ {0x0077, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "wxy" */
+ {0xFFFF, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "*xy" */
+ {0xFFFF, 0x0078, 0x0079, 0x0000, 0x0000, 0x0000}, /* "*xy" */
+ };
+ check("Lower", rawTestArray[0], "1234");
+ check("Upper", rawTestArray[1], "123455"); // must map 00DF to SS
+ check("Title", rawTestArray[2], "1234");
+ check("NFC", rawTestArray[3], "13");
+ check("NFD", rawTestArray[4], "1122");
+ check("*(x) > A $1 B", rawTestArray[5], "11223");
+ check("*(x)(y) > A $2 B $1 C $2 D", rawTestArray[6], "113322334");
+ check("*(x)(y)(z) > A $3 B $2 C $1 D", rawTestArray[7], "114433225");
+ // Disabled for 2.4. TODO Revisit in 2.6 or later.
+ //check("*x > a", rawTestArray[8], "223"); // expect "123"?
+ //check("*x > a", rawTestArray[9], "113"); // expect "123"?
+ //check("*x > a", rawTestArray[10], "_33"); // expect "_23"?
+ //check("*(x) > A $1 B", rawTestArray[11], "__223");
+
+ // improve API/code coverage
+ NoopReplaceable noop;
+ Replaceable *p;
+ if((p=noop.clone())!=NULL) {
+ errln("Replaceable::clone() does not return NULL");
+ delete p;
+ }
+
+ if(!noop.hasMetaData()) {
+ errln("Replaceable::hasMetaData() does not return TRUE");
+ }
+
+ // try to call the compiler-provided
+ // UMemory/UObject/Replaceable assignment operators
+ NoopReplaceable noop2;
+ noop2=noop;
+ if((p=noop2.clone())!=NULL) {
+ errln("noop2.Replaceable::clone() does not return NULL");
+ delete p;
+ }
+
+ // try to call the compiler-provided
+ // UMemory/UObject/Replaceable copy constructors
+ NoopReplaceable noop3(noop);
+ if((p=noop3.clone())!=NULL) {
+ errln("noop3.Replaceable::clone() does not return NULL");
+ delete p;
+ }
+}
+
+void ReplaceableTest::check(const UnicodeString& transliteratorName,
+ const UnicodeString& test,
+ const UnicodeString& shouldProduceStyles)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ TestReplaceable *tr = new TestReplaceable(test, "");
+ UnicodeString expectedStyles = shouldProduceStyles;
+ UnicodeString original = tr->toString();
+
+ Transliterator* t;
+ if (transliteratorName.charAt(0) == 0x2A /*'*'*/) {
+ UnicodeString rules(transliteratorName);
+ rules.remove(0,1);
+ UParseError pe;
+ t = Transliterator::createFromRules("test", rules, UTRANS_FORWARD,
+ pe, status);
+
+ // test clone()
+ TestReplaceable *tr2 = (TestReplaceable *)tr->clone();
+ if(tr2 != NULL) {
+ delete tr;
+ tr = tr2;
+ }
+ } else {
+ t = Transliterator::createInstance(transliteratorName, UTRANS_FORWARD, status);
+ }
+ if (U_FAILURE(status)) {
+ log("FAIL: failed to create the ");
+ log(transliteratorName);
+ errln(" transliterator.");
+ delete tr;
+ return;
+ }
+ t->transliterate(*tr);
+ UnicodeString newStyles = tr->getStyles();
+ if (newStyles != expectedStyles) {
+ errln("FAIL Styles: " + transliteratorName + "{" + original + "} => "
+ + tr->toString() + "; should be {" + expectedStyles + "}!");
+ } else {
+ log("OK: ");
+ log(transliteratorName);
+ log("(");
+ log(original);
+ log(") => ");
+ logln(tr->toString());
+ }
+ delete tr;
+ delete t;
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/reptest.h b/Build/source/libs/icu/icu-xetex/test/intltest/reptest.h
new file mode 100644
index 00000000000..4ab39412c30
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/reptest.h
@@ -0,0 +1,43 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/************************************************************************
+* This test program is intended for testing Replaceable class.
+*
+* Date Name Description
+* 11/28/2001 hshih Creation.
+*
+************************************************************************/
+
+
+#ifndef REPTEST_H
+#define REPTEST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "intltest.h"
+
+/**
+ * @test
+ * @summary Testing the Replaceable class
+ */
+class ReplaceableTest : public IntlTest {
+public:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par=NULL);
+
+ /*Tests the Replaceable class according to the API documentation. */
+ void TestReplaceableClass(void);
+private:
+ void check( const UnicodeString& transliteratorName,
+ const UnicodeString& test,
+ const UnicodeString& shouldProduceStyles);
+};
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/restest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/restest.cpp
new file mode 100644
index 00000000000..3250303c238
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/restest.cpp
@@ -0,0 +1,628 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#include "cstring.h"
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#include "unicode/resbund.h"
+#include "restest.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <limits.h>
+
+//***************************************************************************************
+
+static const UChar kErrorUChars[] = { 0x45, 0x52, 0x52, 0x4f, 0x52, 0 };
+static const int32_t kErrorLength = 5;
+static const int32_t kERROR_COUNT = -1234567;
+
+//***************************************************************************************
+
+enum E_Where
+{
+ e_Root,
+ e_te,
+ e_te_IN,
+ e_Where_count
+};
+
+//***************************************************************************************
+
+#define CONFIRM_EQ(actual, expected, myAction) if ((expected)==(actual)) { record_pass(myAction); } else { record_fail(myAction + (UnicodeString)" returned " + (actual) + (UnicodeString)" instead of " + (expected) + "\n");}
+#define CONFIRM_GE(actual, expected, myAction) if ((actual)>=(expected)) { record_pass(myAction); } else { record_fail(myAction + (UnicodeString)" returned " + (actual) + (UnicodeString)" instead of x >= " + (expected) + "\n");}
+#define CONFIRM_NE(actual, expected, myAction) if ((expected)!=(actual)) { record_pass(myAction); } else { record_fail(myAction + (UnicodeString)" returned " + (actual) + (UnicodeString)" instead of x != " + (expected) + "\n");}
+
+#define CONFIRM_UErrorCode(actual, expected, myAction) if ((expected)==(actual)) { record_pass(myAction); } else { record_fail(myAction + (UnicodeString)" returned " + u_errorName(actual) + " instead of " + u_errorName(expected) + "\n"); }
+
+//***************************************************************************************
+
+/**
+ * Convert an integer, positive or negative, to a character string radix 10.
+ */
+char*
+itoa(int32_t i, char* buf)
+{
+ char* result = buf;
+
+ // Handle negative
+ if (i < 0)
+ {
+ *buf++ = '-';
+ i = -i;
+ }
+
+ // Output digits in reverse order
+ char* p = buf;
+ do
+ {
+ *p++ = (char)('0' + (i % 10));
+ i /= 10;
+ }
+ while (i);
+ *p-- = 0;
+
+ // Reverse the string
+ while (buf < p)
+ {
+ char c = *buf;
+ *buf++ = *p;
+ *p-- = c;
+ }
+
+ return result;
+}
+
+
+
+//***************************************************************************************
+
+// Array of our test objects
+
+static struct
+{
+ const char* name;
+ Locale *locale;
+ UErrorCode expected_constructor_status;
+ E_Where where;
+ UBool like[e_Where_count];
+ UBool inherits[e_Where_count];
+}
+param[] =
+{
+ // "te" means test
+ // "IN" means inherits
+ // "NE" or "ne" means "does not exist"
+
+ { "root", NULL, U_ZERO_ERROR, e_Root, { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } },
+ { "te", NULL, U_ZERO_ERROR, e_te, { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } },
+ { "te_IN", NULL, U_ZERO_ERROR, e_te_IN, { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } },
+ { "te_NE", NULL, U_USING_FALLBACK_WARNING, e_te, { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } },
+ { "te_IN_NE", NULL, U_USING_FALLBACK_WARNING, e_te_IN, { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } },
+ { "ne", NULL, U_USING_DEFAULT_WARNING, e_Root, { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } }
+};
+
+static const int32_t bundles_count = sizeof(param) / sizeof(param[0]);
+
+//***************************************************************************************
+
+/**
+ * Return a random unsigned long l where 0N <= l <= ULONG_MAX.
+ */
+
+uint32_t
+randul()
+{
+ static UBool initialized = FALSE;
+ if (!initialized)
+ {
+ srand((unsigned)time(NULL));
+ initialized = TRUE;
+ }
+ // Assume rand has at least 12 bits of precision
+ uint32_t l = 0;
+ for (uint32_t i=0; i<sizeof(l); ++i)
+ ((char*)&l)[i] = (char)((rand() & 0x0FF0) >> 4);
+ return l;
+}
+
+/**
+ * Return a random double x where 0.0 <= x < 1.0.
+ */
+double
+randd()
+{
+ return (double)(randul() / ULONG_MAX);
+}
+
+/**
+ * Return a random integer i where 0 <= i < n.
+ */
+int32_t randi(int32_t n)
+{
+ return (int32_t)(randd() * n);
+}
+
+//***************************************************************************************
+
+/*
+ Don't use more than one of these at a time because of the Locale names
+*/
+ResourceBundleTest::ResourceBundleTest()
+: pass(0),
+ fail(0)
+{
+ if (param[5].locale == NULL) {
+ param[0].locale = new Locale("root");
+ param[1].locale = new Locale("te");
+ param[2].locale = new Locale("te", "IN");
+ param[3].locale = new Locale("te", "NE");
+ param[4].locale = new Locale("te", "IN", "NE");
+ param[5].locale = new Locale("ne");
+ }
+}
+
+ResourceBundleTest::~ResourceBundleTest()
+{
+ if (param[5].locale) {
+ int idx;
+ for (idx = 0; idx < (int)(sizeof(param)/sizeof(param[0])); idx++) {
+ delete param[idx].locale;
+ param[idx].locale = NULL;
+ }
+ }
+}
+
+void ResourceBundleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite ResourceBundleTest: ");
+ switch (index) {
+ case 0: name = "TestResourceBundles"; if (exec) TestResourceBundles(); break;
+ case 1: name = "TestConstruction"; if (exec) TestConstruction(); break;
+ case 2: name = "TestExemplar"; if (exec) TestExemplar(); break;
+ case 3: name = "TestGetSize"; if (exec) TestGetSize(); break;
+ case 4: name = "TestGetLocaleByType"; if (exec) TestGetLocaleByType(); break;
+ default: name = ""; break; //needed to end loop
+ }
+}
+
+//***************************************************************************************
+
+void
+ResourceBundleTest::TestResourceBundles()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ loadTestData(status);
+ if(U_FAILURE(status))
+ {
+ errln("Could not load testdata.dat %s " + UnicodeString(u_errorName(status)));
+ return;
+ }
+
+ /* Make sure that users using te_IN for the default locale don't get test failures. */
+ Locale originalDefault;
+ if (Locale::getDefault() == Locale("te_IN")) {
+ Locale::setDefault(Locale("en_US"), status);
+ }
+
+ testTag("only_in_Root", TRUE, FALSE, FALSE);
+ testTag("only_in_te", FALSE, TRUE, FALSE);
+ testTag("only_in_te_IN", FALSE, FALSE, TRUE);
+ testTag("in_Root_te", TRUE, TRUE, FALSE);
+ testTag("in_Root_te_te_IN", TRUE, TRUE, TRUE);
+ testTag("in_Root_te_IN", TRUE, FALSE, TRUE);
+ testTag("in_te_te_IN", FALSE, TRUE, TRUE);
+ testTag("nonexistent", FALSE, FALSE, FALSE);
+ logln("Passed: %d\nFailed: %d", pass, fail);
+
+ /* Restore the default locale for the other tests. */
+ Locale::setDefault(originalDefault, status);
+}
+
+void
+ResourceBundleTest::TestConstruction()
+{
+ UErrorCode err = U_ZERO_ERROR;
+ Locale locale("te", "IN");
+
+ const char* testdatapath=loadTestData(err);
+ if(U_FAILURE(err))
+ {
+ errln("Could not load testdata.dat " + UnicodeString(testdatapath) + ", " + UnicodeString(u_errorName(err)));
+ return;
+ }
+
+ /* Make sure that users using te_IN for the default locale don't get test failures. */
+ Locale originalDefault;
+ if (Locale::getDefault() == Locale("te_IN")) {
+ Locale::setDefault(Locale("en_US"), err);
+ }
+
+ ResourceBundle test1((UnicodeString)testdatapath, err);
+ ResourceBundle test2(testdatapath, locale, err);
+ //ResourceBundle test1("c:\\icu\\icu\\source\\test\\testdata\\testdata", err);
+ //ResourceBundle test2("c:\\icu\\icu\\source\\test\\testdata\\testdata", locale, err);
+
+ UnicodeString result1(test1.getStringEx("string_in_Root_te_te_IN", err));
+ UnicodeString result2(test2.getStringEx("string_in_Root_te_te_IN", err));
+
+ if (U_FAILURE(err)) {
+ errln("Something threw an error in TestConstruction()");
+ return;
+ }
+
+ logln("for string_in_Root_te_te_IN, default.txt had " + result1);
+ logln("for string_in_Root_te_te_IN, te_IN.txt had " + result2);
+
+ if (result1 != "ROOT" || result2 != "TE_IN")
+ errln("Construction test failed; run verbose for more information");
+
+ const char* version1;
+ const char* version2;
+
+ version1 = test1.getVersionNumber();
+ version2 = test2.getVersionNumber();
+
+ char *versionID1 = new char[1+strlen(version1)]; // + 1 for zero byte
+ char *versionID2 = new char[1+ strlen(version2)]; // + 1 for zero byte
+
+ strcpy(versionID1, "44.0"); // hardcoded, please change if the default.txt file or ResourceBundle::kVersionSeparater is changed.
+
+ strcpy(versionID2, "55.0"); // hardcoded, please change if the te_IN.txt file or ResourceBundle::kVersionSeparater is changed.
+
+ logln(UnicodeString("getVersionNumber on default.txt returned ") + version1);
+ logln(UnicodeString("getVersionNumber on te_IN.txt returned ") + version2);
+
+ if (strcmp(version1, versionID1) != 0 || strcmp(version2, versionID2) != 0)
+ errln("getVersionNumber() failed");
+
+ delete[] versionID1;
+ delete[] versionID2;
+
+ /* Restore the default locale for the other tests. */
+ Locale::setDefault(originalDefault, err);
+}
+
+//***************************************************************************************
+
+UBool
+ResourceBundleTest::testTag(const char* frag,
+ UBool in_Root,
+ UBool in_te,
+ UBool in_te_IN)
+{
+ int32_t failOrig = fail;
+
+ // Make array from input params
+
+ UBool is_in[] = { in_Root, in_te, in_te_IN };
+
+ const char* NAME[] = { "ROOT", "TE", "TE_IN" };
+
+ // Now try to load the desired items
+
+ char tag[100];
+ UnicodeString action;
+
+ int32_t i,j,actual_bundle;
+// int32_t row,col;
+ int32_t index;
+ UErrorCode status = U_ZERO_ERROR;
+ const char* testdatapath;
+ testdatapath=loadTestData(status);
+ if(U_FAILURE(status))
+ {
+ errln("Could not load testdata.dat %s " + UnicodeString(u_errorName(status)));
+ return FALSE;
+ }
+
+ for (i=0; i<bundles_count; ++i)
+ {
+ action = "Constructor for ";
+ action += param[i].name;
+
+ status = U_ZERO_ERROR;
+ ResourceBundle theBundle( testdatapath, *param[i].locale, status);
+ //ResourceBundle theBundle( "c:\\icu\\icu\\source\\test\\testdata\\testdata", *param[i].locale, status);
+ CONFIRM_UErrorCode(status, param[i].expected_constructor_status, action);
+
+ if(i == 5)
+ actual_bundle = 0; /* ne -> default */
+ else if(i == 3)
+ actual_bundle = 1; /* te_NE -> te */
+ else if(i == 4)
+ actual_bundle = 2; /* te_IN_NE -> te_IN */
+ else
+ actual_bundle = i;
+
+
+ UErrorCode expected_resource_status = U_MISSING_RESOURCE_ERROR;
+ for (j=e_te_IN; j>=e_Root; --j)
+ {
+ if (is_in[j] && param[i].inherits[j])
+ {
+ if(j == actual_bundle) /* it's in the same bundle OR it's a nonexistent=default bundle (5) */
+ expected_resource_status = U_ZERO_ERROR;
+ else if(j == 0)
+ expected_resource_status = U_USING_DEFAULT_WARNING;
+ else
+ expected_resource_status = U_USING_FALLBACK_WARNING;
+
+ break;
+ }
+ }
+
+ UErrorCode expected_status;
+
+ UnicodeString base;
+ for (j=param[i].where; j>=0; --j)
+ {
+ if (is_in[j])
+ {
+ base = NAME[j];
+ break;
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // string
+
+ uprv_strcpy(tag, "string_");
+ uprv_strcat(tag, frag);
+
+ action = param[i].name;
+ action += ".getString(";
+ action += tag;
+ action += ")";
+
+
+ status = U_ZERO_ERROR;
+
+ UnicodeString string(theBundle.getStringEx(tag, status));
+
+ if(U_FAILURE(status)) {
+ string.setTo(TRUE, kErrorUChars, kErrorLength);
+ }
+
+ CONFIRM_UErrorCode(status, expected_resource_status, action);
+
+ UnicodeString expected_string(kErrorUChars);
+ if (U_SUCCESS(status)) {
+ expected_string = base;
+ }
+
+ CONFIRM_EQ(string, expected_string, action);
+
+ //--------------------------------------------------------------------------
+ // array
+
+ uprv_strcpy(tag, "array_");
+ uprv_strcat(tag, frag);
+
+ action = param[i].name;
+ action += ".get(";
+ action += tag;
+ action += ")";
+
+ status = U_ZERO_ERROR;
+ ResourceBundle arrayBundle(theBundle.get(tag, status));
+ CONFIRM_UErrorCode(status, expected_resource_status, action);
+ int32_t count = arrayBundle.getSize();
+
+ if (U_SUCCESS(status))
+ {
+ CONFIRM_GE(count, 1, action);
+
+ for (j=0; j < count; ++j)
+ {
+ char buf[32];
+ UnicodeString value(arrayBundle.getStringEx(j, status));
+ expected_string = base;
+ expected_string += itoa(j,buf);
+ CONFIRM_EQ(value, expected_string, action);
+ }
+
+ action = param[i].name;
+ action += ".getStringEx(";
+ action += tag;
+ action += ")";
+
+ for (j=0; j<100; ++j)
+ {
+ index = count ? (randi(count * 3) - count) : (randi(200) - 100);
+ status = U_ZERO_ERROR;
+ string = kErrorUChars;
+ UnicodeString t(arrayBundle.getStringEx(index, status));
+ expected_status = (index >= 0 && index < count) ? expected_resource_status : U_MISSING_RESOURCE_ERROR;
+ CONFIRM_UErrorCode(status, expected_status, action);
+
+ if (U_SUCCESS(status))
+ {
+ char buf[32];
+ expected_string = base;
+ expected_string += itoa(index,buf);
+ }
+ else
+ {
+ expected_string = kErrorUChars;
+ }
+ CONFIRM_EQ(string, expected_string, action);
+ }
+ }
+ else if (status != expected_resource_status)
+ {
+ record_fail("Error getting " + (UnicodeString)tag);
+ return (UBool)(failOrig != fail);
+ }
+
+ }
+
+ return (UBool)(failOrig != fail);
+}
+
+void
+ResourceBundleTest::record_pass(UnicodeString passMessage)
+{
+ logln(passMessage);
+ ++pass;
+}
+void
+ResourceBundleTest::record_fail(UnicodeString errMessage)
+{
+ err(errMessage);
+ ++fail;
+}
+
+void
+ResourceBundleTest::TestExemplar(){
+
+ int32_t locCount = uloc_countAvailable();
+ int32_t locIndex=0;
+ int num=0;
+ UErrorCode status = U_ZERO_ERROR;
+ for(;locIndex<locCount;locIndex++){
+ const char* locale = uloc_getAvailable(locIndex);
+ UResourceBundle *resb =ures_open(NULL,locale,&status);
+ if(U_SUCCESS(status) && status!=U_USING_FALLBACK_WARNING && status!=U_USING_DEFAULT_WARNING){
+ int32_t len=0;
+ const UChar* strSet = ures_getStringByKey(resb,"ExemplarCharacters",&len,&status);
+ UnicodeSet set(strSet,status);
+ if(U_FAILURE(status)){
+ errln("Could not construct UnicodeSet from pattern for ExemplarCharacters in locale : %s. Error: %s",locale,u_errorName(status));
+ status=U_ZERO_ERROR;
+ }
+ num++;
+ }
+ ures_close(resb);
+ }
+ logln("Number of installed locales with exemplar characters that could be tested: %d",num);
+
+}
+
+void
+ResourceBundleTest::TestGetSize(void)
+{
+ const struct {
+ const char* key;
+ int32_t size;
+ } test[] = {
+ { "zerotest", 1},
+ { "one", 1},
+ { "importtest", 1},
+ { "integerarray", 1},
+ { "emptyarray", 0},
+ { "emptytable", 0},
+ { "emptystring", 1}, /* empty string is still a string */
+ { "emptyint", 1},
+ { "emptybin", 1},
+ { "testinclude", 1},
+ { "collations", 1}, /* not 2 - there is hidden %%CollationBin */
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const char* testdatapath = loadTestData(status);
+ int32_t i = 0, j = 0;
+ int32_t size = 0;
+
+ if(U_FAILURE(status))
+ {
+ err("Could not load testdata.dat %s\n", u_errorName(status));
+ return;
+ }
+
+ ResourceBundle rb(testdatapath, "testtypes", status);
+ if(U_FAILURE(status))
+ {
+ err("Could not testtypes resource bundle %s\n", u_errorName(status));
+ return;
+ }
+
+ for(i = 0; i < (int32_t)(sizeof(test)/sizeof(test[0])); i++) {
+ ResourceBundle res = rb.get(test[i].key, status);
+ if(U_FAILURE(status))
+ {
+ err("Couldn't find the key %s. Error: %s\n", u_errorName(status));
+ return;
+ }
+ size = res.getSize();
+ if(size != test[i].size) {
+ err("Expected size %i, got size %i for key %s\n", test[i].size, size, test[i].key);
+ for(j = 0; j < size; j++) {
+ ResourceBundle helper = res.get(j, status);
+ err("%s\n", helper.getKey());
+ }
+ }
+ }
+}
+
+void
+ResourceBundleTest::TestGetLocaleByType(void)
+{
+ const struct {
+ const char *requestedLocale;
+ const char *resourceKey;
+ const char *validLocale;
+ const char *actualLocale;
+ } test[] = {
+ { "te_IN_BLAH", "string_only_in_te_IN", "te_IN", "te_IN" },
+ { "te_IN_BLAH", "string_only_in_te", "te_IN", "te" },
+ { "te_IN_BLAH", "string_only_in_Root", "te_IN", "root" },
+ { "te_IN_BLAH_01234567890_01234567890_01234567890_01234567890_01234567890_01234567890", "array_2d_only_in_Root", "te_IN", "root" },
+ { "te_IN_BLAH@currency=euro", "array_2d_only_in_te_IN", "te_IN", "te_IN" },
+ { "te_IN_BLAH@calendar=thai;collation=phonebook", "array_2d_only_in_te", "te_IN", "te" }
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ const char* testdatapath = loadTestData(status);
+ int32_t i = 0;
+ Locale locale;
+
+ if(U_FAILURE(status))
+ {
+ err("Could not load testdata.dat %s\n", u_errorName(status));
+ return;
+ }
+
+ for(i = 0; i < (int32_t)(sizeof(test)/sizeof(test[0])); i++) {
+ ResourceBundle rb(testdatapath, test[i].requestedLocale, status);
+ if(U_FAILURE(status))
+ {
+ err("Could not open resource bundle %s (error %s)\n", test[i].requestedLocale, u_errorName(status));
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ ResourceBundle res = rb.get(test[i].resourceKey, status);
+ if(U_FAILURE(status))
+ {
+ err("Couldn't find the key %s. Error: %s\n", test[i].resourceKey, u_errorName(status));
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ locale = res.getLocale(ULOC_REQUESTED_LOCALE, status);
+ if(locale != Locale::getDefault()) {
+ err("Expected requested locale to be %s. Got %s\n", test[i].requestedLocale, locale.getName());
+ }
+ locale = res.getLocale(ULOC_VALID_LOCALE, status);
+ if(strcmp(locale.getName(), test[i].validLocale) != 0) {
+ err("Expected valid locale to be %s. Got %s\n", test[i].requestedLocale, locale.getName());
+ }
+ locale = res.getLocale(ULOC_ACTUAL_LOCALE, status);
+ if(strcmp(locale.getName(), test[i].actualLocale) != 0) {
+ err("Expected actual locale to be %s. Got %s\n", test[i].requestedLocale, locale.getName());
+ }
+ }
+}
+
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/restest.h b/Build/source/libs/icu/icu-xetex/test/intltest/restest.h
new file mode 100644
index 00000000000..78ee08d9822
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/restest.h
@@ -0,0 +1,55 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef RESOURCEBUNDLETEST_H
+#define RESOURCEBUNDLETEST_H
+
+#include "intltest.h"
+
+/**
+ * Tests for class ResourceBundle
+ **/
+class ResourceBundleTest: public IntlTest {
+public:
+ ResourceBundleTest();
+ virtual ~ResourceBundleTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ /**
+ * Perform several extensive tests using the subtest routine testTag
+ **/
+ void TestResourceBundles(void);
+ /**
+ * Test construction of ResourceBundle accessing a custom test resource-file
+ **/
+ void TestConstruction(void);
+
+ void TestExemplar(void);
+
+ void TestGetSize(void);
+ void TestGetLocaleByType(void);
+
+private:
+ /**
+ * The assignment operator has no real implementation.
+ * It is provided to make the compiler happy. Do not call.
+ */
+ ResourceBundleTest& operator=(const ResourceBundleTest&) { return *this; }
+
+ /**
+ * extensive subtests called by TestResourceBundles
+ **/
+ UBool testTag(const char* frag, UBool in_Root, UBool in_te, UBool in_te_IN);
+
+ void record_pass(UnicodeString passMessage);
+ void record_fail(UnicodeString errMessage);
+
+ int32_t pass;
+ int32_t fail;
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/restsnew.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/restsnew.cpp
new file mode 100644
index 00000000000..3bb62459bef
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/restsnew.cpp
@@ -0,0 +1,1180 @@
+/********************************************************************
+ * Copyright (c) 1997-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#include "cstring.h"
+#include "unicode/unistr.h"
+#include "unicode/resbund.h"
+#include "restsnew.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <limits.h>
+
+//***************************************************************************************
+
+static const UChar kErrorUChars[] = { 0x45, 0x52, 0x52, 0x4f, 0x52, 0 };
+static const int32_t kErrorLength = 5;
+static const int32_t kERROR_COUNT = -1234567;
+
+//***************************************************************************************
+
+enum E_Where
+{
+ e_Root,
+ e_te,
+ e_te_IN,
+ e_Where_count
+};
+
+//***************************************************************************************
+
+#define CONFIRM_EQ(actual,expected) if ((expected)==(actual)) { record_pass(); } else { record_fail(); errln(action + (UnicodeString)" returned " + (actual) + (UnicodeString)" instead of " + (expected)); }
+#define CONFIRM_GE(actual,expected) if ((actual)>=(expected)) { record_pass(); } else { record_fail(); errln(action + (UnicodeString)" returned " + (actual) + (UnicodeString)" instead of x >= " + (expected)); }
+#define CONFIRM_NE(actual,expected) if ((expected)!=(actual)) { record_pass(); } else { record_fail(); errln(action + (UnicodeString)" returned " + (actual) + (UnicodeString)" instead of x != " + (expected)); }
+
+#define CONFIRM_UErrorCode(actual,expected) if ((expected)==(actual)) { record_pass(); } else { record_fail(); errln(action + (UnicodeString)" returned " + (UnicodeString)u_errorName(actual) + (UnicodeString)" instead of " + (UnicodeString)u_errorName(expected)); }
+
+//***************************************************************************************
+
+/**
+ * Convert an integer, positive or negative, to a character string radix 10.
+ */
+static char*
+itoa(int32_t i, char* buf)
+{
+ char* result = buf;
+
+ // Handle negative
+ if (i < 0)
+ {
+ *buf++ = '-';
+ i = -i;
+ }
+
+ // Output digits in reverse order
+ char* p = buf;
+ do
+ {
+ *p++ = (char)('0' + (i % 10));
+ i /= 10;
+ }
+ while (i);
+ *p-- = 0;
+
+ // Reverse the string
+ while (buf < p)
+ {
+ char c = *buf;
+ *buf++ = *p;
+ *p-- = c;
+ }
+
+ return result;
+}
+
+
+
+//***************************************************************************************
+
+// Array of our test objects
+
+static struct
+{
+ const char* name;
+ Locale *locale;
+ UErrorCode expected_constructor_status;
+ E_Where where;
+ UBool like[e_Where_count];
+ UBool inherits[e_Where_count];
+}
+param[] =
+{
+ // "te" means test
+ // "IN" means inherits
+ // "NE" or "ne" means "does not exist"
+
+ { "root", 0, U_ZERO_ERROR, e_Root, { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } },
+ { "te", 0, U_ZERO_ERROR, e_te, { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } },
+ { "te_IN", 0, U_ZERO_ERROR, e_te_IN, { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } },
+ { "te_NE", 0, U_USING_FALLBACK_WARNING, e_te, { FALSE, TRUE, FALSE }, { TRUE, TRUE, FALSE } },
+ { "te_IN_NE", 0, U_USING_FALLBACK_WARNING, e_te_IN, { FALSE, FALSE, TRUE }, { TRUE, TRUE, TRUE } },
+ { "ne", 0, U_USING_DEFAULT_WARNING, e_Root, { TRUE, FALSE, FALSE }, { TRUE, FALSE, FALSE } }
+};
+
+static int32_t bundles_count = sizeof(param) / sizeof(param[0]);
+
+//***************************************************************************************
+
+/**
+ * Return a random unsigned long l where 0N <= l <= ULONG_MAX.
+ */
+
+static uint32_t
+randul()
+{
+ static UBool initialized = FALSE;
+ if (!initialized)
+ {
+ srand((unsigned)time(NULL));
+ initialized = TRUE;
+ }
+ // Assume rand has at least 12 bits of precision
+ uint32_t l = 0;
+ for (uint32_t i=0; i<sizeof(l); ++i)
+ ((char*)&l)[i] = (char)((rand() & 0x0FF0) >> 4);
+ return l;
+}
+
+/**
+ * Return a random double x where 0.0 <= x < 1.0.
+ */
+static double
+randd()
+{
+ return (double)(randul() / ULONG_MAX);
+}
+
+/**
+ * Return a random integer i where 0 <= i < n.
+ */
+static int32_t randi(int32_t n)
+{
+ return (int32_t)(randd() * n);
+}
+
+//***************************************************************************************
+
+/*
+ Don't use more than one of these at a time because of the Locale names
+*/
+NewResourceBundleTest::NewResourceBundleTest()
+: pass(0),
+ fail(0)
+{
+ if (param[5].locale == NULL) {
+ param[0].locale = new Locale("root");
+ param[1].locale = new Locale("te");
+ param[2].locale = new Locale("te", "IN");
+ param[3].locale = new Locale("te", "NE");
+ param[4].locale = new Locale("te", "IN", "NE");
+ param[5].locale = new Locale("ne");
+ }
+}
+
+NewResourceBundleTest::~NewResourceBundleTest()
+{
+ if (param[5].locale) {
+ int idx;
+ for (idx = 0; idx < (int)(sizeof(param)/sizeof(param[0])); idx++) {
+ delete param[idx].locale;
+ param[idx].locale = NULL;
+ }
+ }
+}
+
+void NewResourceBundleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite ResourceBundleTest: ");
+ switch (index) {
+ case 0: name = "TestResourceBundles"; if (exec) TestResourceBundles(); break;
+ case 1: name = "TestConstruction"; if (exec) TestConstruction(); break;
+ case 2: name = "TestIteration"; if (exec) TestIteration(); break;
+ case 3: name = "TestOtherAPI"; if(exec) TestOtherAPI(); break;
+ case 4: name = "TestNewTypes"; if(exec) TestNewTypes(); break;
+ case 5: name = "TestGetByFallback"; if(exec) TestGetByFallback(); break;
+ default: name = ""; break; //needed to end loop
+ }
+}
+
+//***************************************************************************************
+
+void
+NewResourceBundleTest::TestResourceBundles()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ loadTestData(status);
+ if(U_FAILURE(status))
+ {
+ errln("Could not load testdata.dat %s " + UnicodeString(u_errorName(status)));
+ return;
+ }
+
+ /* Make sure that users using te_IN for the default locale don't get test failures. */
+ Locale originalDefault;
+ if (Locale::getDefault() == Locale("te_IN")) {
+ Locale::setDefault(Locale("en_US"), status);
+ }
+
+ testTag("only_in_Root", TRUE, FALSE, FALSE);
+ testTag("only_in_te", FALSE, TRUE, FALSE);
+ testTag("only_in_te_IN", FALSE, FALSE, TRUE);
+ testTag("in_Root_te", TRUE, TRUE, FALSE);
+ testTag("in_Root_te_te_IN", TRUE, TRUE, TRUE);
+ testTag("in_Root_te_IN", TRUE, FALSE, TRUE);
+ testTag("in_te_te_IN", FALSE, TRUE, TRUE);
+ testTag("nonexistent", FALSE, FALSE, FALSE);
+ logln("Passed: %d\nFailed: %d", pass, fail);
+
+ /* Restore the default locale for the other tests. */
+ Locale::setDefault(originalDefault, status);
+}
+
+void
+NewResourceBundleTest::TestConstruction()
+{
+ UErrorCode err = U_ZERO_ERROR;
+ Locale locale("te", "IN");
+
+ const char* testdatapath;
+ testdatapath=loadTestData(err);
+ if(U_FAILURE(err))
+ {
+ errln("Could not load testdata.dat %s " + UnicodeString(u_errorName(err)));
+ return;
+ }
+
+ /* Make sure that users using te_IN for the default locale don't get test failures. */
+ Locale originalDefault;
+ if (Locale::getDefault() == Locale("te_IN")) {
+ Locale::setDefault(Locale("en_US"), err);
+ }
+
+ ResourceBundle test1((UnicodeString)testdatapath, err);
+ ResourceBundle test2(testdatapath, locale, err);
+
+ UnicodeString result1;
+ UnicodeString result2;
+
+ result1 = test1.getStringEx("string_in_Root_te_te_IN", err);
+ result2 = test2.getStringEx("string_in_Root_te_te_IN", err);
+ if (U_FAILURE(err)) {
+ errln("Something threw an error in TestConstruction()");
+ return;
+ }
+
+ logln("for string_in_Root_te_te_IN, root.txt had " + result1);
+ logln("for string_in_Root_te_te_IN, te_IN.txt had " + result2);
+
+ if (result1 != "ROOT" || result2 != "TE_IN") {
+ errln("Construction test failed; run verbose for more information");
+ }
+
+ const char* version1;
+ const char* version2;
+
+ version1 = test1.getVersionNumber();
+ version2 = test2.getVersionNumber();
+
+ char *versionID1 = new char[1 + strlen(U_ICU_VERSION) + strlen(version1)]; // + 1 for zero byte
+ char *versionID2 = new char[1 + strlen(U_ICU_VERSION) + strlen(version2)]; // + 1 for zero byte
+
+ strcpy(versionID1, "44.0"); // hardcoded, please change if the default.txt file or ResourceBundle::kVersionSeparater is changed.
+
+ strcpy(versionID2, "55.0"); // hardcoded, please change if the te_IN.txt file or ResourceBundle::kVersionSeparater is changed.
+
+ logln(UnicodeString("getVersionNumber on default.txt returned ") + version1 + UnicodeString(" Expect: " ) + versionID1);
+ logln(UnicodeString("getVersionNumber on te_IN.txt returned ") + version2 + UnicodeString(" Expect: " ) + versionID2);
+
+ if (strcmp(version1, versionID1) != 0) {
+ errln("getVersionNumber(version1) failed. %s != %s", version1, versionID1);
+ }
+ if (strcmp(version2, versionID2) != 0) {
+ errln("getVersionNumber(version2) failed. %s != %s", version2, versionID2);
+ }
+ delete[] versionID1;
+ delete[] versionID2;
+
+ /* Restore the default locale for the other tests. */
+ Locale::setDefault(originalDefault, err);
+}
+
+void
+NewResourceBundleTest::TestIteration()
+{
+ UErrorCode err = U_ZERO_ERROR;
+ const char* testdatapath;
+ const char* data[]={
+ "string_in_Root_te_te_IN", "1",
+ "array_in_Root_te_te_IN", "5",
+ "array_2d_in_Root_te_te_IN", "4",
+ };
+
+ Locale *locale=new Locale("te_IN");
+
+ testdatapath=loadTestData(err);
+ if(U_FAILURE(err))
+ {
+ errln("Could not load testdata.dat %s " + UnicodeString(u_errorName(err)));
+ return;
+ }
+
+ ResourceBundle test1(testdatapath, *locale, err);
+ if(U_FAILURE(err)){
+ errln("Construction failed");
+ }
+ uint32_t i;
+ int32_t count, row=0, col=0;
+ char buf[5];
+ UnicodeString expected;
+ UnicodeString element("TE_IN");
+ UnicodeString action;
+
+
+ for(i=0; i<sizeof(data)/sizeof(data[0]); i=i+2){
+ action = "te_IN";
+ action +=".get(";
+ action += data[i];
+ action +=", err)";
+ err=U_ZERO_ERROR;
+ ResourceBundle bundle = test1.get(data[i], err);
+ if(!U_FAILURE(err)){
+ action = "te_IN";
+ action +=".getKey()";
+
+ CONFIRM_EQ((UnicodeString)bundle.getKey(), (UnicodeString)data[i]);
+
+ count=0;
+ row=0;
+ while(bundle.hasNext()){
+ action = data[i];
+ action +=".getNextString(err)";
+ row=count;
+ UnicodeString got=bundle.getNextString(err);
+ if(U_SUCCESS(err)){
+ expected=element;
+ if(bundle.getSize() > 1){
+ CONFIRM_EQ(bundle.getType(), URES_ARRAY);
+ expected+=itoa(row, buf);
+ ResourceBundle rowbundle=bundle.get(row, err);
+ if(!U_FAILURE(err) && rowbundle.getSize()>1){
+ col=0;
+ while(rowbundle.hasNext()){
+ expected=element;
+ got=rowbundle.getNextString(err);
+ if(!U_FAILURE(err)){
+ expected+=itoa(row, buf);
+ expected+=itoa(col, buf);
+ col++;
+ CONFIRM_EQ(got, expected);
+ }
+ }
+ CONFIRM_EQ(col, rowbundle.getSize());
+ }
+ }
+ else{
+ CONFIRM_EQ(bundle.getType(), (int32_t)URES_STRING);
+ }
+ }
+ CONFIRM_EQ(got, expected);
+ count++;
+ }
+ action = data[i];
+ action +=".getSize()";
+ CONFIRM_EQ(bundle.getSize(), count);
+ CONFIRM_EQ(count, atoi(data[i+1]));
+ //after reaching the end
+ err=U_ZERO_ERROR;
+ ResourceBundle errbundle=bundle.getNext(err);
+ action = "After reaching the end of the Iterator:- ";
+ action +=data[i];
+ action +=".getNext()";
+ CONFIRM_NE(err, (int32_t)U_ZERO_ERROR);
+ CONFIRM_EQ(u_errorName(err), u_errorName(U_INDEX_OUTOFBOUNDS_ERROR));
+ //reset the iterator
+ err = U_ZERO_ERROR;
+ bundle.resetIterator();
+ /* The following code is causing a crash
+ ****CRASH******
+ */
+
+ bundle.getNext(err);
+ if(U_FAILURE(err)){
+ errln("ERROR: getNext() throw an error");
+ }
+ }
+ }
+ delete locale;
+}
+
+// TODO: add operator== and != to ResourceBundle
+static UBool
+equalRB(ResourceBundle &a, ResourceBundle &b) {
+ UResType type;
+ UErrorCode status;
+
+ type=a.getType();
+ status=U_ZERO_ERROR;
+ return
+ type==b.getType() &&
+ a.getLocale()==b.getLocale() &&
+ 0==strcmp(a.getName(), b.getName()) &&
+ type==URES_STRING ?
+ a.getString(status)==b.getString(status) :
+ type==URES_INT ?
+ a.getInt(status)==b.getInt(status) :
+ TRUE;
+}
+
+void
+NewResourceBundleTest::TestOtherAPI(){
+ UErrorCode err = U_ZERO_ERROR;
+ const char* testdatapath=loadTestData(err);
+ UnicodeString tDataPathUS = UnicodeString(testdatapath, "");
+
+ if(U_FAILURE(err))
+ {
+ errln("Could not load testdata.dat %s " + UnicodeString(u_errorName(err)));
+ return;
+ }
+
+ /* Make sure that users using te_IN for the default locale don't get test failures. */
+ Locale originalDefault;
+ if (Locale::getDefault() == Locale("te_IN")) {
+ Locale::setDefault(Locale("en_US"), err);
+ }
+
+ Locale *locale=new Locale("te_IN");
+
+ ResourceBundle test0(tDataPathUS, *locale, err);
+ if(U_FAILURE(err)){
+ errln("Construction failed");
+ return;
+ }
+
+ ResourceBundle test1(testdatapath, *locale, err);
+ if(U_FAILURE(err)){
+ errln("Construction failed");
+ return;
+ }
+
+ logln("Testing getLocale()\n");
+ if(strcmp(test1.getLocale().getName(), locale->getName()) !=0 ){
+ errln("FAIL: ResourceBundle::getLocale() failed\n");
+ }
+
+ delete locale;
+
+ logln("Testing ResourceBundle(UErrorCode)\n");
+ ResourceBundle defaultresource(err);
+ ResourceBundle explicitdefaultresource(NULL, Locale::getDefault(), err);
+ if(U_FAILURE(err)){
+ errln("Construction of default resourcebundle failed");
+ return;
+ }
+ // You can't compare the default locale to the resolved locale in the
+ // resource bundle due to aliasing, keywords in the default locale
+ // or the chance that the machine running these tests is using a locale
+ // that isn't available in ICU.
+ if(strcmp(defaultresource.getLocale().getName(), explicitdefaultresource.getLocale().getName()) != 0){
+ errln("Construction of default resourcebundle didn't take the defaultlocale. Expected %s Got %s err=%s\n",
+ explicitdefaultresource.getLocale().getName(), defaultresource.getLocale().getName(), u_errorName(err));
+ }
+
+
+ ResourceBundle copyRes(defaultresource);
+ if(strcmp(copyRes.getName(), defaultresource.getName() ) !=0 ||
+ strcmp(test1.getName(), defaultresource.getName() ) ==0 ||
+ strcmp(copyRes.getLocale().getName(), defaultresource.getLocale().getName() ) !=0 ||
+ strcmp(test1.getLocale().getName(), defaultresource.getLocale().getName() ) ==0 )
+ {
+ errln("copy construction failed\n");
+ }
+
+ ResourceBundle defaultSub = defaultresource.get((int32_t)0, err);
+ ResourceBundle defSubCopy(defaultSub);
+ if(strcmp(defSubCopy.getName(), defaultSub.getName() ) !=0 ||
+ strcmp(defSubCopy.getLocale().getName(), defaultSub.getLocale().getName() ) !=0 ){
+ errln("copy construction for subresource failed\n");
+ }
+
+ ResourceBundle *p;
+
+ p = defaultresource.clone();
+ if(p == &defaultresource || !equalRB(*p, defaultresource)) {
+ errln("ResourceBundle.clone() failed");
+ }
+ delete p;
+
+ p = defaultSub.clone();
+ if(p == &defaultSub || !equalRB(*p, defaultSub)) {
+ errln("2nd ResourceBundle.clone() failed");
+ }
+ delete p;
+
+ UVersionInfo ver;
+ copyRes.getVersion(ver);
+
+ logln("Version returned: [%d.%d.%d.%d]\n", ver[0], ver[1], ver[2], ver[3]);
+
+ logln("Testing C like UnicodeString APIs\n");
+
+ UResourceBundle *testCAPI = NULL, *bundle = NULL, *rowbundle = NULL, *temp = NULL;
+ err = U_ZERO_ERROR;
+ const char* data[]={
+ "string_in_Root_te_te_IN", "1",
+ "array_in_Root_te_te_IN", "5",
+ "array_2d_in_Root_te_te_IN", "4",
+ };
+
+
+ testCAPI = ures_open(testdatapath, "te_IN", &err);
+
+ if(U_SUCCESS(err)) {
+ // Do the testing
+ // first iteration
+
+ uint32_t i;
+ int32_t count, row=0, col=0;
+ char buf[5];
+ UnicodeString expected;
+ UnicodeString element("TE_IN");
+ UnicodeString action;
+
+
+ for(i=0; i<sizeof(data)/sizeof(data[0]); i=i+2){
+ action = "te_IN";
+ action +=".get(";
+ action += data[i];
+ action +=", err)";
+ err=U_ZERO_ERROR;
+ bundle = ures_getByKey(testCAPI, data[i], bundle, &err);
+ if(!U_FAILURE(err)){
+ const char* key = NULL;
+ action = "te_IN";
+ action +=".getKey()";
+
+ CONFIRM_EQ((UnicodeString)ures_getKey(bundle), (UnicodeString)data[i]);
+
+ count=0;
+ row=0;
+ while(ures_hasNext(bundle)){
+ action = data[i];
+ action +=".getNextString(err)";
+ row=count;
+ UnicodeString got=ures_getNextUnicodeString(bundle, &key, &err);
+ if(U_SUCCESS(err)){
+ expected=element;
+ if(ures_getSize(bundle) > 1){
+ CONFIRM_EQ(ures_getType(bundle), URES_ARRAY);
+ expected+=itoa(row, buf);
+ rowbundle=ures_getByIndex(bundle, row, rowbundle, &err);
+ if(!U_FAILURE(err) && ures_getSize(rowbundle)>1){
+ col=0;
+ while(ures_hasNext(rowbundle)){
+ expected=element;
+ got=ures_getNextUnicodeString(rowbundle, &key, &err);
+ temp = ures_getByIndex(rowbundle, col, temp, &err);
+ UnicodeString bla = ures_getUnicodeString(temp, &err);
+ UnicodeString bla2 = ures_getUnicodeStringByIndex(rowbundle, col, &err);
+ if(!U_FAILURE(err)){
+ expected+=itoa(row, buf);
+ expected+=itoa(col, buf);
+ col++;
+ CONFIRM_EQ(got, expected);
+ CONFIRM_EQ(bla, expected);
+ CONFIRM_EQ(bla2, expected);
+ }
+ }
+ CONFIRM_EQ(col, ures_getSize(rowbundle));
+ }
+ }
+ else{
+ CONFIRM_EQ(ures_getType(bundle), (int32_t)URES_STRING);
+ }
+ }
+ CONFIRM_EQ(got, expected);
+ count++;
+ }
+ }
+ }
+ ures_close(temp);
+ ures_close(rowbundle);
+ ures_close(bundle);
+ ures_close(testCAPI);
+ } else {
+ errln("failed to open a resource bundle\n");
+ }
+
+ /* Restore the default locale for the other tests. */
+ Locale::setDefault(originalDefault, err);
+}
+
+
+
+
+//***************************************************************************************
+
+UBool
+NewResourceBundleTest::testTag(const char* frag,
+ UBool in_Root,
+ UBool in_te,
+ UBool in_te_IN)
+{
+ int32_t failOrig = fail;
+
+ // Make array from input params
+
+ UBool is_in[] = { in_Root, in_te, in_te_IN };
+
+ const char* NAME[] = { "ROOT", "TE", "TE_IN" };
+
+ // Now try to load the desired items
+
+ char tag[100];
+ UnicodeString action;
+
+ int32_t i,j,row,col, actual_bundle;
+ int32_t index;
+ const char* testdatapath;
+
+ UErrorCode status = U_ZERO_ERROR;
+ testdatapath=loadTestData(status);
+ if(U_FAILURE(status))
+ {
+ errln("Could not load testdata.dat %s " + UnicodeString(u_errorName(status)));
+ return FALSE;
+ }
+
+ for (i=0; i<bundles_count; ++i)
+ {
+ action = "Constructor for ";
+ action += param[i].name;
+
+ status = U_ZERO_ERROR;
+ ResourceBundle theBundle( testdatapath, *param[i].locale, status);
+ //ResourceBundle theBundle( "c:\\icu\\icu\\source\\test\\testdata\\testdata", *param[i].locale, status);
+ CONFIRM_UErrorCode(status,param[i].expected_constructor_status);
+
+ if(i == 5)
+ actual_bundle = 0; /* ne -> default */
+ else if(i == 3)
+ actual_bundle = 1; /* te_NE -> te */
+ else if(i == 4)
+ actual_bundle = 2; /* te_IN_NE -> te_IN */
+ else
+ actual_bundle = i;
+
+
+ UErrorCode expected_resource_status = U_MISSING_RESOURCE_ERROR;
+ for (j=e_te_IN; j>=e_Root; --j)
+ {
+ if (is_in[j] && param[i].inherits[j])
+ {
+ if(j == actual_bundle) /* it's in the same bundle OR it's a nonexistent=default bundle (5) */
+ expected_resource_status = U_ZERO_ERROR;
+ else if(j == 0)
+ expected_resource_status = U_USING_DEFAULT_WARNING;
+ else
+ expected_resource_status = U_USING_FALLBACK_WARNING;
+
+ break;
+ }
+ }
+
+ UErrorCode expected_status;
+
+ UnicodeString base;
+ for (j=param[i].where; j>=0; --j)
+ {
+ if (is_in[j])
+ {
+ base = NAME[j];
+ break;
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ // string
+
+ uprv_strcpy(tag, "string_");
+ uprv_strcat(tag, frag);
+
+ action = param[i].name;
+ action += ".getStringEx(";
+ action += tag;
+ action += ")";
+
+
+ status = U_ZERO_ERROR;
+ UnicodeString string = theBundle.getStringEx(tag, status);
+ if(U_FAILURE(status)) {
+ string.setTo(TRUE, kErrorUChars, kErrorLength);
+ }
+
+ CONFIRM_UErrorCode(status, expected_resource_status);
+
+ UnicodeString expected_string(kErrorUChars);
+ if (U_SUCCESS(status)) {
+ expected_string = base;
+ }
+
+ CONFIRM_EQ(string, expected_string);
+
+ //--------------------------------------------------------------------------
+ // array ResourceBundle using the key
+
+ uprv_strcpy(tag, "array_");
+ uprv_strcat(tag, frag);
+
+ action = param[i].name;
+ action += ".get(";
+ action += tag;
+ action += ")";
+
+ int32_t count = kERROR_COUNT;
+ status = U_ZERO_ERROR;
+ ResourceBundle array = theBundle.get(tag, status);
+ CONFIRM_UErrorCode(status,expected_resource_status);
+
+
+ if (U_SUCCESS(status))
+ {
+ //confirm the resource type is an array
+ UResType bundleType=array.getType();
+ CONFIRM_EQ(bundleType, URES_ARRAY);
+
+ count=array.getSize();
+ CONFIRM_GE(count,1);
+
+ for (j=0; j<count; ++j)
+ {
+ char buf[32];
+ expected_string = base;
+ expected_string += itoa(j,buf);
+ CONFIRM_EQ(array.getNextString(status),expected_string);
+ }
+
+ }
+ else
+ {
+ CONFIRM_EQ(count,kERROR_COUNT);
+ // CONFIRM_EQ((int32_t)(unsigned long)array,(int32_t)0);
+ count = 0;
+ }
+
+ //--------------------------------------------------------------------------
+ // arrayItem ResourceBundle using the index
+
+
+ for (j=0; j<100; ++j)
+ {
+ index = count ? (randi(count * 3) - count) : (randi(200) - 100);
+ status = U_ZERO_ERROR;
+ string = kErrorUChars;
+ ResourceBundle array = theBundle.get(tag, status);
+ if(!U_FAILURE(status)){
+ UnicodeString t = array.getStringEx(index, status);
+ if(!U_FAILURE(status)) {
+ string=t;
+ }
+ }
+
+ expected_status = (index >= 0 && index < count) ? expected_resource_status : U_MISSING_RESOURCE_ERROR;
+ CONFIRM_UErrorCode(status,expected_status);
+
+ if (U_SUCCESS(status)){
+ char buf[32];
+ expected_string = base;
+ expected_string += itoa(index,buf);
+ } else {
+ expected_string = kErrorUChars;
+ }
+ CONFIRM_EQ(string,expected_string);
+
+ }
+
+ //--------------------------------------------------------------------------
+ // 2dArray
+
+ uprv_strcpy(tag, "array_2d_");
+ uprv_strcat(tag, frag);
+
+ action = param[i].name;
+ action += ".get(";
+ action += tag;
+ action += ")";
+
+
+ int32_t row_count = kERROR_COUNT, column_count = kERROR_COUNT;
+ status = U_ZERO_ERROR;
+ ResourceBundle array2d=theBundle.get(tag, status);
+
+ //const UnicodeString** array2d = theBundle.get2dArray(tag, row_count, column_count, status);
+ CONFIRM_UErrorCode(status,expected_resource_status);
+
+ if (U_SUCCESS(status))
+ {
+ //confirm the resource type is an 2darray
+ UResType bundleType=array2d.getType();
+ CONFIRM_EQ(bundleType, URES_ARRAY);
+
+ row_count=array2d.getSize();
+ CONFIRM_GE(row_count,1);
+
+ for(row=0; row<row_count; ++row){
+ ResourceBundle tablerow=array2d.get(row, status);
+ CONFIRM_UErrorCode(status, expected_resource_status);
+ if(U_SUCCESS(status)){
+ //confirm the resourcetype of each table row is an array
+ UResType rowType=tablerow.getType();
+ CONFIRM_EQ(rowType, URES_ARRAY);
+
+ column_count=tablerow.getSize();
+ CONFIRM_GE(column_count,1);
+
+ for (col=0; j<column_count; ++j) {
+ char buf[32];
+ expected_string = base;
+ expected_string += itoa(row,buf);
+ expected_string += itoa(col,buf);
+ CONFIRM_EQ(tablerow.getNextString(status),expected_string);
+ }
+ }
+ }
+ }else{
+ CONFIRM_EQ(row_count,kERROR_COUNT);
+ CONFIRM_EQ(column_count,kERROR_COUNT);
+ row_count=column_count=0;
+ }
+
+
+
+
+ //--------------------------------------------------------------------------
+ // 2dArrayItem
+ for (j=0; j<200; ++j)
+ {
+ row = row_count ? (randi(row_count * 3) - row_count) : (randi(200) - 100);
+ col = column_count ? (randi(column_count * 3) - column_count) : (randi(200) - 100);
+ status = U_ZERO_ERROR;
+ string = kErrorUChars;
+ ResourceBundle array2d=theBundle.get(tag, status);
+ if(U_SUCCESS(status)){
+ ResourceBundle tablerow=array2d.get(row, status);
+ if(U_SUCCESS(status)) {
+ UnicodeString t=tablerow.getStringEx(col, status);
+ if(U_SUCCESS(status)){
+ string=t;
+ }
+ }
+ }
+ expected_status = (row >= 0 && row < row_count && col >= 0 && col < column_count) ?
+ expected_resource_status: U_MISSING_RESOURCE_ERROR;
+ CONFIRM_UErrorCode(status,expected_status);
+
+ if (U_SUCCESS(status)){
+ char buf[32];
+ expected_string = base;
+ expected_string += itoa(row,buf);
+ expected_string += itoa(col,buf);
+ } else {
+ expected_string = kErrorUChars;
+ }
+ CONFIRM_EQ(string,expected_string);
+
+ }
+
+ //--------------------------------------------------------------------------
+ // taggedArray
+
+ uprv_strcpy(tag, "tagged_array_");
+ uprv_strcat(tag, frag);
+
+ action = param[i].name;
+ action += ".get(";
+ action += tag;
+ action += ")";
+
+ int32_t tag_count;
+ status = U_ZERO_ERROR;
+
+ ResourceBundle tags=theBundle.get(tag, status);
+ CONFIRM_UErrorCode(status, expected_resource_status);
+
+ if (U_SUCCESS(status)) {
+ UResType bundleType=tags.getType();
+ CONFIRM_EQ(bundleType, URES_TABLE);
+
+ tag_count=tags.getSize();
+ CONFIRM_GE((int32_t)tag_count, (int32_t)0);
+
+ for(index=0; index <tag_count; index++){
+ ResourceBundle tagelement=tags.get(index, status);
+ UnicodeString key=tagelement.getKey();
+ UnicodeString value=tagelement.getNextString(status);
+ logln("tag = " + key + ", value = " + value );
+ if(key.startsWith("tag") && value.startsWith(base)){
+ record_pass();
+ }else{
+ record_fail();
+ }
+
+ }
+
+ for(index=0; index <tag_count; index++){
+ ResourceBundle tagelement=tags.get(index, status);
+ const char *tkey=NULL;
+ UnicodeString value=tagelement.getNextString(&tkey, status);
+ UnicodeString key(tkey);
+ logln("tag = " + key + ", value = " + value );
+ if(value.startsWith(base)){
+ record_pass();
+ }else{
+ record_fail();
+ }
+ }
+
+ }else{
+ tag_count=0;
+ }
+
+
+
+
+ //--------------------------------------------------------------------------
+ // taggedArrayItem
+
+ action = param[i].name;
+ action += ".get(";
+ action += tag;
+ action += ")";
+
+ count = 0;
+ for (index=-20; index<20; ++index)
+ {
+ char buf[32];
+ status = U_ZERO_ERROR;
+ string = kErrorUChars;
+ char item_tag[8];
+ uprv_strcpy(item_tag, "tag");
+ uprv_strcat(item_tag, itoa(index,buf));
+ ResourceBundle tags=theBundle.get(tag, status);
+ if(U_SUCCESS(status)){
+ ResourceBundle tagelement=tags.get(item_tag, status);
+ if(!U_FAILURE(status)){
+ UResType elementType=tagelement.getType();
+ CONFIRM_EQ(elementType, (int32_t)URES_STRING);
+ const char* key=tagelement.getKey();
+ CONFIRM_EQ((UnicodeString)key, (UnicodeString)item_tag);
+ UnicodeString t=tagelement.getString(status);
+ if(!U_FAILURE(status)){
+ string=t;
+ }
+ }
+ if (index < 0) {
+ CONFIRM_UErrorCode(status,U_MISSING_RESOURCE_ERROR);
+ }
+ else{
+ if (status != U_MISSING_RESOURCE_ERROR) {
+ count++;
+ expected_string = base;
+ expected_string += buf;
+ CONFIRM_EQ(string,expected_string);
+ }
+ }
+ }
+
+ }
+ CONFIRM_EQ(count, tag_count);
+
+ }
+ return (UBool)(failOrig == fail);
+}
+
+void
+NewResourceBundleTest::record_pass()
+{
+ ++pass;
+}
+void
+NewResourceBundleTest::record_fail()
+{
+ err();
+ ++fail;
+}
+
+
+void
+NewResourceBundleTest::TestNewTypes() {
+ char action[256];
+ const char* testdatapath;
+ UErrorCode status = U_ZERO_ERROR;
+ uint8_t *binResult = NULL;
+ int32_t len = 0;
+ int32_t i = 0;
+ int32_t intResult = 0;
+ uint32_t uintResult = 0;
+ UChar expected[] = { 'a','b','c','\0','d','e','f' };
+ const char* expect ="tab:\t cr:\r ff:\f newline:\n backslash:\\\\ quote=\\\' doubleQuote=\\\" singlequoutes=''";
+ UChar uExpect[200];
+
+ testdatapath=loadTestData(status);
+
+ if(U_FAILURE(status))
+ {
+ logln("Could not load testdata.dat %s \n",u_errorName(status));
+ return;
+ }
+
+ ResourceBundle theBundle(testdatapath, "testtypes", status);
+ ResourceBundle bundle(testdatapath, Locale("te_IN"),status);
+
+ UnicodeString emptyStr = theBundle.getStringEx("emptystring", status);
+ if(!emptyStr.length()==0) {
+ logln("Empty string returned invalid value\n");
+ }
+
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+
+ /* This test reads the string "abc\u0000def" from the bundle */
+ /* if everything is working correctly, the size of this string */
+ /* should be 7. Everything else is a wrong answer, esp. 3 and 6*/
+
+ strcpy(action, "getting and testing of string with embeded zero");
+ ResourceBundle res = theBundle.get("zerotest", status);
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(res.getType(), URES_STRING);
+ UnicodeString zeroString=res.getString(status);
+ len = zeroString.length();
+ if(U_SUCCESS(status)){
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(len, 7);
+ CONFIRM_NE(len, 3);
+ }
+ for(i=0;i<len;i++){
+ if(zeroString[i]!= expected[i]){
+ logln("Output didnot match Expected: \\u%4X Got: \\u%4X", expected[i], zeroString[i]);
+ }
+ }
+
+ strcpy(action, "getting and testing of binary type");
+ res = theBundle.get("binarytest", status);
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(res.getType(), URES_BINARY);
+ binResult=(uint8_t*)res.getBinary(len, status);
+ if(U_SUCCESS(status)){
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(len, 15);
+ for(i = 0; i<15; i++) {
+ CONFIRM_EQ(binResult[i], i);
+ }
+ }
+
+ strcpy(action, "getting and testing of imported binary type");
+ res = theBundle.get("importtest",status);
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(res.getType(), URES_BINARY);
+ binResult=(uint8_t*)res.getBinary(len, status);
+ if(U_SUCCESS(status)){
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(len, 15);
+ for(i = 0; i<15; i++) {
+ CONFIRM_EQ(binResult[i], i);
+ }
+ }
+
+ strcpy(action, "getting and testing of integer types");
+ res = theBundle.get("one", status);
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(res.getType(), URES_INT);
+ intResult=res.getInt(status);
+ uintResult = res.getUInt(status);
+ if(U_SUCCESS(status)){
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(uintResult, (uint32_t)intResult);
+ CONFIRM_EQ(intResult, 1);
+ }
+
+ strcpy(action, "getting minusone");
+ res = theBundle.get((const char*)"minusone", status);
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(res.getType(), URES_INT);
+ intResult=res.getInt(status);
+ uintResult = res.getUInt(status);
+ if(U_SUCCESS(status)){
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(uintResult, 0x0FFFFFFF); /* a 28 bit integer */
+ CONFIRM_EQ(intResult, -1);
+ CONFIRM_NE(uintResult, (uint32_t)intResult);
+ }
+
+ strcpy(action, "getting plusone");
+ res = theBundle.get("plusone",status);
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(res.getType(), URES_INT);
+ intResult=res.getInt(status);
+ uintResult = res.getUInt(status);
+ if(U_SUCCESS(status)){
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(uintResult, (uint32_t)intResult);
+ CONFIRM_EQ(intResult, 1);
+ }
+
+ res = theBundle.get("onehundredtwentythree",status);
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(res.getType(), URES_INT);
+ intResult=res.getInt(status);
+ if(U_SUCCESS(status)){
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ CONFIRM_EQ(intResult, 123);
+ }
+
+ /* this tests if escapes are preserved or not */
+ {
+ UnicodeString str = theBundle.getStringEx("testescape",status);
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ if(U_SUCCESS(status)){
+ u_charsToUChars(expect,uExpect,(int32_t)uprv_strlen(expect)+1);
+ if(str.compare(uExpect)!=0){
+ errln("Did not get the expected string for testescape expected. Expected : "
+ +UnicodeString(uExpect )+ " Got: " + str);
+ }
+ }
+ }
+ /* test for jitterbug#1435 */
+ {
+ UnicodeString str = theBundle.getStringEx("test_underscores",status);
+ expect ="test message ....";
+ CONFIRM_UErrorCode(status, U_ZERO_ERROR);
+ u_charsToUChars(expect,uExpect,(int32_t)uprv_strlen(expect)+1);
+ if(str.compare(uExpect)!=0){
+ errln("Did not get the expected string for test_underscores.\n");
+ }
+ }
+
+
+}
+
+void
+NewResourceBundleTest::TestGetByFallback() {
+ UErrorCode status = U_ZERO_ERROR;
+
+ ResourceBundle heRes(NULL, "he", status);
+
+ heRes.getWithFallback("calendar", status).getWithFallback("islamic-civil", status).getWithFallback("DateTime", status);
+ if(U_SUCCESS(status)) {
+ errln("he locale's Islamic-civil DateTime resource exists. How did it get here?\n");
+ }
+ status = U_ZERO_ERROR;
+
+ heRes.getWithFallback("calendar", status).getWithFallback("islamic-civil", status).getWithFallback("eras", status);
+ if(U_FAILURE(status)) {
+ errln("Didn't get Islamic Eras. I know they are there!\n");
+ }
+ status = U_ZERO_ERROR;
+
+ ResourceBundle rootRes(NULL, "root", status);
+ rootRes.getWithFallback("calendar", status).getWithFallback("islamic-civil", status).getWithFallback("DateTime", status);
+ if(U_SUCCESS(status)) {
+ errln("Root's Islamic-civil's DateTime resource exists. How did it get here?\n");
+ }
+ status = U_ZERO_ERROR;
+
+}
+//eof
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/restsnew.h b/Build/source/libs/icu/icu-xetex/test/intltest/restsnew.h
new file mode 100644
index 00000000000..efc850c7faf
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/restsnew.h
@@ -0,0 +1,59 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef NEW_RESOURCEBUNDLETEST_H
+#define NEW_RESOURCEBUNDLETEST_H
+
+#include "intltest.h"
+
+/**
+ * Tests for class ResourceBundle
+ **/
+class NewResourceBundleTest: public IntlTest {
+public:
+ NewResourceBundleTest();
+ virtual ~NewResourceBundleTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ /**
+ * Perform several extensive tests using the subtest routine testTag
+ **/
+ void TestResourceBundles(void);
+ /**
+ * Test construction of ResourceBundle accessing a custom test resource-file
+ **/
+ void TestConstruction(void);
+
+ void TestIteration(void);
+
+ void TestOtherAPI(void);
+
+ void TestNewTypes(void);
+
+ void TestGetByFallback(void);
+
+private:
+ /**
+ * The assignment operator has no real implementation.
+ * It is provided to make the compiler happy. Do not call.
+ */
+ NewResourceBundleTest& operator=(const NewResourceBundleTest&) { return *this; }
+
+ /**
+ * extensive subtests called by TestResourceBundles
+ **/
+ UBool testTag(const char* frag, UBool in_Root, UBool in_te, UBool in_te_IN);
+
+ void record_pass(void);
+ void record_fail(void);
+
+ int32_t pass;
+ int32_t fail;
+
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/rndmcoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/rndmcoll.cpp
new file mode 100644
index 00000000000..be15570c67b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/rndmcoll.cpp
@@ -0,0 +1,176 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 2005-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ ******************************************************************************
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include "rndmcoll.h"
+#include "wbnf.h"
+
+
+#if !UCONFIG_NO_COLLATION
+
+//Raymond: Following comments are copied from Java implementation
+//
+// each rule can be:
+// "[" command "]"
+// "& [" position "]"
+// "&" before chars
+// relation "[variable top]"
+// relation (chars "|")? chars ("/" chars)?
+// plus, a reset must come before a relation
+
+
+static const char collationBNF[] =
+ "$s = ' '? 50%;"
+ "$crlf = '\r\n';"
+
+ "$alternateOptions = non'-'ignorable | shifted;"
+ "$onoff = on | off;"
+ "$caseFirstOptions = off | upper | lower;"
+ "$strengthOptions = '1' | '2' | '3' | '4' | 'I';"
+ "$commandList = '['"
+ " ( alternate ' ' $alternateOptions"
+ " | backwards' 2'"
+ " | normalization ' ' $onoff "
+ " | caseLevel ' ' $onoff "
+ " | hiraganaQ ' ' $onoff"
+ " | caseFirst ' ' $caseFirstOptions"
+ " | strength ' ' $strengthOptions"
+ " ) ']';"
+ "$command = $commandList $crlf;"
+
+ "$ignorableTypes = (tertiary | secondary | primary) ' ' ignorable;"
+ "$allTypes = variable | regular | implicit | trailing | $ignorableTypes;"
+ "$positionList = '[' (first | last) ' ' $allTypes ']';"
+
+ "$beforeList = '[before ' ('1' | '2' | '3') ']';"
+
+ "$relationList = ("
+ " '<'"
+ " | '<<'"
+ " | ';'"
+ " | '<<<'"
+ " | ','"
+ " | '='"
+ ");"
+ "$string = $chars{1,5}~@;"
+ "$chars = a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z| '<'| '&'| '['| ']';"
+ "$rel1 = '[variable top]' $s;"
+ "$p1 = ($string $s '|' $s)? 25%;"
+ "$p2 = ('/' $s $string $s)? 25%;"
+ "$rel2 = $p1 $string $s $p2;"
+ "$relation = $relationList $s ($rel1 | $rel2) $crlf;"
+
+ "$reset = '&' $s ($beforeList $s)? 10% ($positionList 1% | $string 10%) $crlf;"
+ "$mostRules = $command 1% | $reset 5% | $relation 25%;"
+ "$root = $command{0,5} $reset $mostRules{1,20};";
+
+
+void RandomCollatorTest::Test2(){
+ // See ticket 5747 about reenabling this test.
+ errln("TestWbnf is incorrectly implemented.\nThis test should be modeled to use the existing test frame work for naming tests.\n");
+ TestWbnf();
+}
+
+
+void RandomCollatorTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* ){
+ if (exec) logln("TestSuite RandomCollatorTest: ");
+ switch (index) {
+ TESTCASE(0, Test);
+ TESTCASE(1, Test2);
+ default: name = ""; break;
+ }
+}
+
+/*
+class TestColltorCompare{
+public:
+ UBool operator()(Collator &coll, int count = 1000){
+ UnicodeString a(test_string.get_a_string());
+ UnicodeString b(test_string.get_a_string());
+ UnicodeString c(test_string.get_a_string());
+ do{
+ if (check_transitivity(coll, a, b, c)){
+ a = b;
+ b = c;
+ c = UnicodeString(test_string.get_a_string());
+ }
+ }while(count-- >= 0 );
+
+ return FALSE;
+ }
+ TestColltorCompare():test_string("$s = $c{1,8};", "$s", "$c", new Magic_SelectOneChar("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ[]&<")){
+ }
+private:
+ UBool check_transitivity(const Collator & coll, const UnicodeString &a, const UnicodeString &b, const UnicodeString &c){
+ int ab = coll.compare(a,b), ba = coll.compare(b,a);
+ int bc = coll.compare(b,c), cb = coll.compare(c,b);
+ int ca = coll.compare(c,a), ac = coll.compare(a,c);
+ // a
+ // / \
+ // b - c
+ //
+ if (//counter-clockwise, maximum
+ (ab >=0 && bc >=0 && ac <0)
+ ||(bc >=0 && ca >=0 && ba <0)
+ ||(ca >=0 && ab >=0 && cb <0)
+
+ //counter-clockwise, minimum
+ ||(ab <=0 && bc <=0 && ca >0)
+ ||(bc <=0 && ca <=0 && ba >0)
+ ||(ca <=0 && ab <=0 && cb >0)
+ ){
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ LanguageGenerator test_string;
+};*/
+
+void RandomCollatorTest::Test(){
+ // See ticket 5747 about reenabling this test.
+ errln("This test needs to be fixed.\n");
+
+ LanguageGenerator test_rule;
+ if (test_rule.parseBNF(collationBNF, "$root", TRUE) != LanguageGenerator::OK){
+ errln("The test code itself is wrong.");
+ return;
+ };
+
+ //TestColltorCompare coll_test;
+
+ static const int CONSTRUCT_RANDOM_COUNT = 1000;
+ int i;
+ for (i=0; i < CONSTRUCT_RANDOM_COUNT; i++){
+ const char * rule = test_rule.next();
+ logln("\n-----------------------------------%d\n",i);
+ logln(UnicodeString(rule, strlen(rule)));
+
+ UnicodeString newRule(rule); // potential bug
+ UErrorCode status = U_ZERO_ERROR;
+ logln( "===========================================\n");
+ fwrite(rule, strlen(rule),1,stdout);
+ logln("\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
+
+ Collator * c = new RuleBasedCollator(newRule,status);
+
+ if (U_FAILURE(status)) {
+ errln( "Could not create Collator for the %d(th) generated rule.\n"
+ "Error Name: %s\n"
+ "The rule is ",
+ i, u_errorName(status));
+ return;
+ }
+
+ delete c;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/rndmcoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/rndmcoll.h
new file mode 100644
index 00000000000..d216af3b1f7
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/rndmcoll.h
@@ -0,0 +1,29 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2005-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * RandomCollatorTest is ported from RandomCollatorTest.java of ICU4J
+ */
+
+#ifndef _RANDCOLL
+#define _RANDCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class RandomCollatorTest: public IntlTestCollator {
+public:
+ virtual void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+ void Test();
+ void Test2();
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif /* _RANDCOLL */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/sdtfmtts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/sdtfmtts.cpp
new file mode 100644
index 00000000000..064acba30ab
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/sdtfmtts.cpp
@@ -0,0 +1,238 @@
+
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "sdtfmtts.h"
+
+#include "unicode/smpdtfmt.h"
+#include "unicode/dtfmtsym.h"
+
+// This is an API test, not a unit test. It doesn't test very many cases, and doesn't
+// try to test the full functionality. It just calls each function in the class and
+// verifies that it works on a basic level.
+
+void IntlTestSimpleDateFormatAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite SimpleDateFormatAPI");
+ switch (index) {
+ case 0: name = "SimpleDateFormat API test";
+ if (exec) {
+ logln("SimpleDateFormat API test---"); logln("");
+ UErrorCode status = U_ZERO_ERROR;
+ Locale saveLocale;
+ Locale::setDefault(Locale::getEnglish(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not set default locale, test may not give correct results");
+ }
+ testAPI(/*par*/);
+ Locale::setDefault(saveLocale, status);
+ }
+ break;
+
+ default: name = ""; break;
+ }
+}
+
+/**
+ * Test various generic API methods of SimpleDateFormat for API coverage.
+ */
+void IntlTestSimpleDateFormatAPI::testAPI(/*char *par*/)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+// ======= Test constructors
+
+ logln("Testing SimpleDateFormat constructors");
+
+ SimpleDateFormat def(status);
+ if(U_FAILURE(status)) {
+ dataerrln("ERROR: Could not create SimpleDateFormat (default) - exitting");
+ return;
+ }
+
+ status = U_ZERO_ERROR;
+ const UnicodeString pattern("yyyy.MM.dd G 'at' hh:mm:ss z");
+ SimpleDateFormat pat(pattern, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create SimpleDateFormat (pattern)");
+ }
+
+ status = U_ZERO_ERROR;
+ SimpleDateFormat pat_fr(pattern, Locale::getFrench(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create SimpleDateFormat (pattern French)");
+ }
+
+ status = U_ZERO_ERROR;
+ DateFormatSymbols *symbols = new DateFormatSymbols(Locale::getFrench(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create DateFormatSymbols (French)");
+ }
+
+ status = U_ZERO_ERROR;
+ SimpleDateFormat cust1(pattern, symbols, status);
+ if(U_FAILURE(status)) {
+ dataerrln("ERROR: Could not create SimpleDateFormat (pattern, symbols*) - exitting");
+ return;
+ }
+
+ status = U_ZERO_ERROR;
+ SimpleDateFormat cust2(pattern, *symbols, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Could not create SimpleDateFormat (pattern, symbols)");
+ }
+
+ SimpleDateFormat copy(pat);
+
+// ======= Test clone(), assignment, and equality
+
+ logln("Testing clone(), assignment and equality operators");
+
+ if( ! (copy == pat) || copy != pat) {
+ errln("ERROR: Copy constructor (or ==) failed");
+ }
+
+ copy = cust1;
+ if(copy != cust1) {
+ errln("ERROR: Assignment (or !=) failed");
+ }
+
+ Format *clone = def.clone();
+ if( ! (*clone == def) ) {
+ errln("ERROR: Clone() (or ==) failed");
+ }
+ delete clone;
+
+// ======= Test various format() methods
+
+ logln("Testing various format() methods");
+
+ UDate d = 837039928046.0;
+ Formattable fD(d, Formattable::kIsDate);
+
+ UnicodeString res1, res2;
+ FieldPosition pos1(0), pos2(0);
+
+ res1 = def.format(d, res1, pos1);
+ logln( (UnicodeString) "" + d + " formatted to " + res1);
+
+ status = U_ZERO_ERROR;
+ res2 = cust1.format(fD, res2, pos2, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: format(Formattable [Date]) failed");
+ }
+ logln((UnicodeString) "" + fD.getDate() + " formatted to " + res2);
+
+// ======= Test parse()
+
+ logln("Testing parse()");
+
+ UnicodeString text("02/03/76 2:50 AM, CST");
+ UDate result1, result2;
+ ParsePosition pos(0);
+ result1 = def.parse(text, pos);
+ logln(text + " parsed into " + result1);
+
+ status = U_ZERO_ERROR;
+ result2 = def.parse(text, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: parse() failed");
+ }
+ logln(text + " parsed into " + result2);
+
+// ======= Test getters and setters
+
+ logln("Testing getters and setters");
+
+ const DateFormatSymbols *syms = pat.getDateFormatSymbols();
+ if(!syms) {
+ errln("Couldn't obtain DateFormatSymbols. Quitting test!");
+ return;
+ }
+ if(syms->getDynamicClassID() != DateFormatSymbols::getStaticClassID()) {
+ errln("ERROR: format->getDateFormatSymbols()->getDynamicClassID() != DateFormatSymbols::getStaticClassID()");
+ }
+ DateFormatSymbols *newSyms = new DateFormatSymbols(*syms);
+ def.adoptDateFormatSymbols(newSyms);
+ pat_fr.setDateFormatSymbols(*newSyms);
+ if( *(pat.getDateFormatSymbols()) != *(def.getDateFormatSymbols())) {
+ errln("ERROR: adopt or set DateFormatSymbols() failed");
+ }
+
+ status = U_ZERO_ERROR;
+ UDate startDate = pat.get2DigitYearStart(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: getTwoDigitStartDate() failed");
+ }
+
+ status = U_ZERO_ERROR;
+ pat_fr.set2DigitYearStart(startDate, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: setTwoDigitStartDate() failed");
+ }
+
+// ======= Test DateFormatSymbols constructor
+ newSyms =new DateFormatSymbols("gregorian", status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: new DateFormatSymbols() failed");
+ }
+ def.adoptDateFormatSymbols(newSyms);
+
+// ======= Test applyPattern()
+
+ logln("Testing applyPattern()");
+
+ UnicodeString p1("yyyy.MM.dd G 'at' hh:mm:ss z");
+ logln("Applying pattern " + p1);
+ status = U_ZERO_ERROR;
+ pat.applyPattern(p1);
+
+ UnicodeString s2;
+ s2 = pat.toPattern(s2);
+ logln("Extracted pattern is " + s2);
+ if(s2 != p1) {
+ errln("ERROR: toPattern() result did not match pattern applied");
+ }
+
+ logln("Applying pattern " + p1);
+ status = U_ZERO_ERROR;
+ pat.applyLocalizedPattern(p1, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: applyPattern() failed with " + (int32_t) status);
+ }
+ UnicodeString s3;
+ status = U_ZERO_ERROR;
+ s3 = pat.toLocalizedPattern(s3, status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: toLocalizedPattern() failed");
+ }
+ logln("Extracted pattern is " + s3);
+ if(s3 != p1) {
+ errln("ERROR: toLocalizedPattern() result did not match pattern applied");
+ }
+
+// ======= Test getStaticClassID()
+
+ logln("Testing getStaticClassID()");
+
+ status = U_ZERO_ERROR;
+ DateFormat *test = new SimpleDateFormat(status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Couldn't create a SimpleDateFormat");
+ }
+
+ if(test->getDynamicClassID() != SimpleDateFormat::getStaticClassID()) {
+ errln("ERROR: getDynamicClassID() didn't return the expected value");
+ }
+
+ delete test;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/sdtfmtts.h b/Build/source/libs/icu/icu-xetex/test/intltest/sdtfmtts.h
new file mode 100644
index 00000000000..c9ecd374857
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/sdtfmtts.h
@@ -0,0 +1,31 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _INTLTESTSIMPLEDATEFORMATAPI
+#define _INTLTESTSIMPLEDATEFORMATAPI
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+/**
+ * Test basic functionality of various API functions
+ **/
+class IntlTestSimpleDateFormatAPI : public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+private:
+ /**
+ * Performs tests on many API functions, see detailed comments in source code
+ **/
+ void testAPI(/* char* par */);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/sfwdchit.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/sfwdchit.cpp
new file mode 100644
index 00000000000..703a4858e60
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/sfwdchit.cpp
@@ -0,0 +1,120 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/* file name: sfwdchit.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*/
+
+#include "sfwdchit.h"
+#include "unicode/ustring.h"
+#include "unicode/unistr.h"
+#include "uhash.h"
+#include "cmemory.h"
+
+// A hash code of kInvalidHashCode indicates that the has code needs
+// to be computed. A hash code of kEmptyHashCode is used for empty keys
+// and for any key whose computed hash code is kInvalidHashCode.
+const int32_t SimpleFwdCharIterator::kInvalidHashCode = 0;
+const int32_t SimpleFwdCharIterator::kEmptyHashCode = 1;
+
+#if 0 // not used
+SimpleFwdCharIterator::SimpleFwdCharIterator(const UnicodeString& s) {
+
+ fHashCode = kInvalidHashCode;
+ fLen = s.length();
+ fStart = new UChar[fLen];
+ if(fStart == NULL) {
+ fBogus = TRUE;
+ } else {
+ fEnd = fStart+fLen;
+ fCurrent = fStart;
+ fBogus = FALSE;
+ s.extract(0, fLen, fStart);
+ }
+
+}
+#endif
+
+SimpleFwdCharIterator::SimpleFwdCharIterator(UChar *s, int32_t len, UBool adopt) {
+
+ fHashCode = kInvalidHashCode;
+
+ fLen = len==-1 ? u_strlen(s) : len;
+
+ if(adopt == FALSE) {
+ fStart = new UChar[fLen];
+ if(fStart == NULL) {
+ fBogus = TRUE;
+ } else {
+ uprv_memcpy(fStart, s, fLen);
+ fEnd = fStart+fLen;
+ fCurrent = fStart;
+ fBogus = FALSE;
+ }
+ } else { // adopt = TRUE
+ fCurrent = fStart = s;
+ fEnd = fStart + fLen;
+ fBogus = FALSE;
+ }
+
+}
+
+SimpleFwdCharIterator::~SimpleFwdCharIterator() {
+ delete[] fStart;
+}
+
+#if 0 // not used
+UBool SimpleFwdCharIterator::operator==(const ForwardCharacterIterator& that) const {
+ if(this == &that) {
+ return TRUE;
+ }
+/*
+ if(that->fHashCode != kInvalidHashCode && this->fHashCode = that->fHashCode) {
+ return TRUE;
+ }
+
+ if(this->fStart == that->fStart) {
+ return TRUE;
+ }
+
+ if(this->fLen == that->fLen && uprv_memcmp(this->fStart, that->fStart, this->fLen) {
+ return TRUE;
+ }
+*/
+ return FALSE;
+}
+#endif
+
+int32_t SimpleFwdCharIterator::hashCode(void) const {
+ if (fHashCode == kInvalidHashCode)
+ {
+ UHashTok key;
+ key.pointer = fStart;
+ ((SimpleFwdCharIterator *)this)->fHashCode = uhash_hashUChars(key);
+ }
+ return fHashCode;
+}
+
+UClassID SimpleFwdCharIterator::getDynamicClassID(void) const {
+ return NULL;
+}
+
+UChar SimpleFwdCharIterator::nextPostInc(void) {
+ if(fCurrent == fEnd) {
+ return ForwardCharacterIterator::DONE;
+ } else {
+ return *(fCurrent)++;
+ }
+}
+
+UChar32 SimpleFwdCharIterator::next32PostInc(void) {
+ return ForwardCharacterIterator::DONE;
+}
+
+UBool SimpleFwdCharIterator::hasNext() {
+ return fCurrent < fEnd;
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/sfwdchit.h b/Build/source/libs/icu/icu-xetex/test/intltest/sfwdchit.h
new file mode 100644
index 00000000000..71fbd00ce26
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/sfwdchit.h
@@ -0,0 +1,77 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef SFDWCHIT_H
+#define SFDWCHIT_H
+
+#include "unicode/chariter.h"
+#include "intltest.h"
+
+class SimpleFwdCharIterator : public ForwardCharacterIterator {
+public:
+ // not used -- SimpleFwdCharIterator(const UnicodeString& s);
+ SimpleFwdCharIterator(UChar *s, int32_t len, UBool adopt = FALSE);
+
+ virtual ~SimpleFwdCharIterator();
+
+ /**
+ * Returns true when both iterators refer to the same
+ * character in the same character-storage object.
+ */
+ // not used -- virtual UBool operator==(const ForwardCharacterIterator& that) const;
+
+ /**
+ * Generates a hash code for this iterator.
+ */
+ virtual int32_t hashCode(void) const;
+
+ /**
+ * Returns a UClassID for this ForwardCharacterIterator ("poor man's
+ * RTTI").<P> Despite the fact that this function is public,
+ * DO NOT CONSIDER IT PART OF CHARACTERITERATOR'S API!
+ */
+ virtual UClassID getDynamicClassID(void) const;
+
+ /**
+ * Gets the current code unit for returning and advances to the next code unit
+ * in the iteration range
+ * (toward endIndex()). If there are
+ * no more code units to return, returns DONE.
+ */
+ virtual UChar nextPostInc(void);
+
+ /**
+ * Gets the current code point for returning and advances to the next code point
+ * in the iteration range
+ * (toward endIndex()). If there are
+ * no more code points to return, returns DONE.
+ */
+ virtual UChar32 next32PostInc(void);
+
+ /**
+ * Returns FALSE if there are no more code units or code points
+ * at or after the current position in the iteration range.
+ * This is used with nextPostInc() or next32PostInc() in forward
+ * iteration.
+ */
+ virtual UBool hasNext();
+
+protected:
+ SimpleFwdCharIterator() {}
+ SimpleFwdCharIterator(const SimpleFwdCharIterator &other)
+ : ForwardCharacterIterator(other) {}
+ SimpleFwdCharIterator &operator=(const SimpleFwdCharIterator&) { return *this; }
+private:
+ static const int32_t kInvalidHashCode;
+ static const int32_t kEmptyHashCode;
+
+ UChar *fStart, *fEnd, *fCurrent;
+ int32_t fLen;
+ UBool fBogus;
+ int32_t fHashCode;
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/srchtest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/srchtest.cpp
new file mode 100644
index 00000000000..cde9da4bdd3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/srchtest.cpp
@@ -0,0 +1,2350 @@
+/*
+*****************************************************************************
+* Copyright (C) 2001-2006, International Business Machines orporation
+* and others. All Rights Reserved.
+****************************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "srchtest.h"
+#include "../cintltst/usrchdat.c"
+#include "unicode/stsearch.h"
+#include "unicode/ustring.h"
+#include "unicode/schriter.h"
+#include <string.h>
+#include <stdio.h>
+
+// private definitions -----------------------------------------------------
+
+#define CASE(id,test) \
+ case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ if(areBroken) { \
+ errln(__FILE__ " cannot test - failed to create collator."); \
+ } else { \
+ test(); \
+ } \
+ } \
+ break;
+
+// public contructors and destructors --------------------------------------
+
+StringSearchTest::StringSearchTest() :
+ m_en_wordbreaker_(NULL), m_en_characterbreaker_(NULL)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ m_en_us_ = (RuleBasedCollator *)Collator::createInstance("en_US", status);
+ m_fr_fr_ = (RuleBasedCollator *)Collator::createInstance("fr_FR", status);
+ m_de_ = (RuleBasedCollator *)Collator::createInstance("de_DE", status);
+ m_es_ = (RuleBasedCollator *)Collator::createInstance("es_ES", status);
+ if(U_FAILURE(status)) {
+ delete m_en_us_;
+ delete m_fr_fr_;
+ delete m_de_;
+ delete m_es_;
+ m_en_us_ = 0;
+ m_fr_fr_ = 0;
+ m_de_ = 0;
+ m_es_ = 0;
+ errln("Collator creation failed with %s", u_errorName(status));
+ return;
+ }
+
+
+ UnicodeString rules;
+ rules.setTo(((RuleBasedCollator *)m_de_)->getRules());
+ UChar extrarules[128];
+ u_unescape(EXTRACOLLATIONRULE, extrarules, 128);
+ rules.append(extrarules, u_strlen(extrarules));
+ delete m_de_;
+
+ m_de_ = new RuleBasedCollator(rules, status);
+
+ rules.setTo(((RuleBasedCollator *)m_es_)->getRules());
+ rules.append(extrarules, u_strlen(extrarules));
+
+ delete m_es_;
+
+ m_es_ = new RuleBasedCollator(rules, status);
+
+#if !UCONFIG_NO_BREAK_ITERATION
+ m_en_wordbreaker_ = BreakIterator::createWordInstance(
+ Locale::getEnglish(), status);
+ m_en_characterbreaker_ = BreakIterator::createCharacterInstance(
+ Locale::getEnglish(), status);
+#endif
+}
+
+StringSearchTest::~StringSearchTest()
+{
+ delete m_en_us_;
+ delete m_fr_fr_;
+ delete m_de_;
+ delete m_es_;
+#if !UCONFIG_NO_BREAK_ITERATION
+ delete m_en_wordbreaker_;
+ delete m_en_characterbreaker_;
+#endif
+}
+
+// public methods ----------------------------------------------------------
+
+void StringSearchTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* )
+{
+ UBool areBroken = FALSE;
+ if (m_en_us_ == NULL && m_fr_fr_ == NULL && m_de_ == NULL &&
+ m_es_ == NULL && m_en_wordbreaker_ == NULL &&
+ m_en_characterbreaker_ == NULL && exec) {
+ areBroken = TRUE;
+ }
+
+ switch (index) {
+ CASE(0, TestOpenClose)
+ CASE(1, TestInitialization)
+ CASE(2, TestBasic)
+ CASE(3, TestNormExact)
+ CASE(4, TestStrength)
+#if UCONFIG_NO_BREAK_ITERATION
+ case 5:
+ name = "TestBreakIterator";
+ break;
+#else
+ CASE(5, TestBreakIterator)
+#endif
+ CASE(6, TestVariable)
+ CASE(7, TestOverlap)
+ CASE(8, TestCollator)
+ CASE(9, TestPattern)
+ CASE(10, TestText)
+ CASE(11, TestCompositeBoundaries)
+ CASE(12, TestGetSetOffset)
+ CASE(13, TestGetSetAttribute)
+ CASE(14, TestGetMatch)
+ CASE(15, TestSetMatch)
+ CASE(16, TestReset)
+ CASE(17, TestSupplementary)
+ CASE(18, TestContraction)
+ CASE(19, TestIgnorable)
+ CASE(20, TestCanonical)
+ CASE(21, TestNormCanonical)
+ CASE(22, TestStrengthCanonical)
+#if UCONFIG_NO_BREAK_ITERATION
+ case 23:
+ name = "TestBreakIteratorCanonical";
+ break;
+#else
+ CASE(23, TestBreakIteratorCanonical)
+#endif
+ CASE(24, TestVariableCanonical)
+ CASE(25, TestOverlapCanonical)
+ CASE(26, TestCollatorCanonical)
+ CASE(27, TestPatternCanonical)
+ CASE(28, TestTextCanonical)
+ CASE(29, TestCompositeBoundariesCanonical)
+ CASE(30, TestGetSetOffsetCanonical)
+ CASE(31, TestSupplementaryCanonical)
+ CASE(32, TestContractionCanonical)
+ CASE(33, TestUClassID)
+ CASE(34, TestSubclass)
+ CASE(35, TestCoverage)
+ CASE(36, TestDiactricMatch)
+ default: name = ""; break;
+ }
+}
+
+// private methods ------------------------------------------------------
+
+RuleBasedCollator * StringSearchTest::getCollator(const char *collator)
+{
+ if (collator == NULL) {
+ return m_en_us_;
+ }
+ if (strcmp(collator, "fr") == 0) {
+ return m_fr_fr_;
+ }
+ else if (strcmp(collator, "de") == 0) {
+ return m_de_;
+ }
+ else if (strcmp(collator, "es") == 0) {
+ return m_es_;
+ }
+ else {
+ return m_en_us_;
+ }
+}
+
+BreakIterator * StringSearchTest::getBreakIterator(const char *breaker)
+{
+#if UCONFIG_NO_BREAK_ITERATION
+ return NULL;
+#else
+ if (breaker == NULL) {
+ return NULL;
+ }
+ if (strcmp(breaker, "wordbreaker") == 0) {
+ return m_en_wordbreaker_;
+ }
+ else {
+ return m_en_characterbreaker_;
+ }
+#endif
+}
+
+char * StringSearchTest::toCharString(const UnicodeString &text)
+{
+ static char result[1024];
+ int index = 0;
+ int count = 0;
+ int length = text.length();
+
+ for (; count < length; count ++) {
+ UChar ch = text[count];
+ if (ch >= 0x20 && ch <= 0x7e) {
+ result[index ++] = (char)ch;
+ }
+ else {
+ sprintf(result+index, "\\u%04x", ch);
+ index += 6; /* \uxxxx */
+ }
+ }
+ result[index] = 0;
+
+ return result;
+}
+
+Collator::ECollationStrength StringSearchTest::getECollationStrength(
+ const UCollationStrength &strength) const
+{
+ switch (strength)
+ {
+ case UCOL_PRIMARY :
+ return Collator::PRIMARY;
+ case UCOL_SECONDARY :
+ return Collator::SECONDARY;
+ case UCOL_TERTIARY :
+ return Collator::TERTIARY;
+ default :
+ return Collator::IDENTICAL;
+ }
+}
+
+UBool StringSearchTest::assertEqualWithStringSearch(StringSearch *strsrch,
+ const SearchData *search)
+{
+ int count = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t matchindex = search->offset[count];
+ UnicodeString matchtext;
+
+ if (strsrch->getMatchedStart() != USEARCH_DONE ||
+ strsrch->getMatchedLength() != 0) {
+ errln("Error with the initialization of match start and length");
+ }
+ // start of following matches
+ while (U_SUCCESS(status) && matchindex >= 0) {
+ int32_t matchlength = search->size[count];
+ strsrch->next(status);
+ if (matchindex != strsrch->getMatchedStart() ||
+ matchlength != strsrch->getMatchedLength()) {
+ char *str = toCharString(strsrch->getText());
+ errln("Text: %s", str);
+ str = toCharString(strsrch->getPattern());
+ errln("Pattern: %s", str);
+ errln("Error following match found at %d %d",
+ strsrch->getMatchedStart(), strsrch->getMatchedLength());
+ return FALSE;
+ }
+ count ++;
+
+ strsrch->getMatchedText(matchtext);
+
+ if (U_FAILURE(status) ||
+ strsrch->getText().compareBetween(matchindex,
+ matchindex + matchlength,
+ matchtext, 0,
+ matchtext.length())) {
+ errln("Error getting following matched text");
+ }
+
+ matchindex = search->offset[count];
+ }
+ strsrch->next(status);
+ if (strsrch->getMatchedStart() != USEARCH_DONE ||
+ strsrch->getMatchedLength() != 0) {
+ char *str = toCharString(strsrch->getText());
+ errln("Text: %s", str);
+ str = toCharString(strsrch->getPattern());
+ errln("Pattern: %s", str);
+ errln("Error following match found at %d %d",
+ strsrch->getMatchedStart(), strsrch->getMatchedLength());
+ return FALSE;
+ }
+ // start of preceding matches
+ count = count == 0 ? 0 : count - 1;
+ matchindex = search->offset[count];
+ while (U_SUCCESS(status) && matchindex >= 0) {
+ int32_t matchlength = search->size[count];
+ strsrch->previous(status);
+ if (matchindex != strsrch->getMatchedStart() ||
+ matchlength != strsrch->getMatchedLength()) {
+ char *str = toCharString(strsrch->getText());
+ errln("Text: %s", str);
+ str = toCharString(strsrch->getPattern());
+ errln("Pattern: %s", str);
+ errln("Error following match found at %d %d",
+ strsrch->getMatchedStart(), strsrch->getMatchedLength());
+ return FALSE;
+ }
+
+ strsrch->getMatchedText(matchtext);
+
+ if (U_FAILURE(status) ||
+ strsrch->getText().compareBetween(matchindex,
+ matchindex + matchlength,
+ matchtext, 0,
+ matchtext.length())) {
+ errln("Error getting following matched text");
+ }
+
+ matchindex = count > 0 ? search->offset[count - 1] : -1;
+ count --;
+ }
+ strsrch->previous(status);
+ if (strsrch->getMatchedStart() != USEARCH_DONE ||
+ strsrch->getMatchedLength() != 0) {
+ char *str = toCharString(strsrch->getText());
+ errln("Text: %s", str);
+ str = toCharString(strsrch->getPattern());
+ errln("Pattern: %s", str);
+ errln("Error following match found at %d %d",
+ strsrch->getMatchedStart(), strsrch->getMatchedLength());
+ return FALSE;
+ }
+ return TRUE;
+}
+
+UBool StringSearchTest::assertEqual(const SearchData *search)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ Collator *collator = getCollator(search->collator);
+ BreakIterator *breaker = getBreakIterator(search->breaker);
+ StringSearch *strsrch, *strsrch2;
+ UChar temp[128];
+
+#if UCONFIG_NO_BREAK_ITERATION
+ if(search->breaker) {
+ return TRUE; /* skip test */
+ }
+#endif
+ u_unescape(search->text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp);
+ u_unescape(search->pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp);
+
+#if !UCONFIG_NO_BREAK_ITERATION
+ if (breaker != NULL) {
+ breaker->setText(text);
+ }
+#endif
+ collator->setStrength(getECollationStrength(search->strength));
+ strsrch = new StringSearch(pattern, text, (RuleBasedCollator *)collator,
+ breaker, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ return FALSE;
+ }
+
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ collator->setStrength(getECollationStrength(UCOL_TERTIARY));
+ delete strsrch;
+ return FALSE;
+ }
+
+
+ strsrch2 = strsrch->clone();
+ if( strsrch2 == strsrch || *strsrch2 != *strsrch ||
+ !assertEqualWithStringSearch(strsrch2, search)
+ ) {
+ errln("failure with StringSearch.clone()");
+ collator->setStrength(getECollationStrength(UCOL_TERTIARY));
+ delete strsrch;
+ delete strsrch2;
+ return FALSE;
+ }
+ delete strsrch2;
+
+ collator->setStrength(getECollationStrength(UCOL_TERTIARY));
+ delete strsrch;
+ return TRUE;
+}
+
+UBool StringSearchTest::assertCanonicalEqual(const SearchData *search)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *collator = getCollator(search->collator);
+ BreakIterator *breaker = getBreakIterator(search->breaker);
+ StringSearch *strsrch;
+ UChar temp[128];
+
+#if UCONFIG_NO_BREAK_ITERATION
+ if(search->breaker) {
+ return TRUE; /* skip test */
+ }
+#endif
+
+ u_unescape(search->text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp);
+ u_unescape(search->pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp);
+
+#if !UCONFIG_NO_BREAK_ITERATION
+ if (breaker != NULL) {
+ breaker->setText(text);
+ }
+#endif
+ collator->setStrength(getECollationStrength(search->strength));
+ strsrch = new StringSearch(pattern, text, (RuleBasedCollator *)collator,
+ breaker, status);
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ return FALSE;
+ }
+
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ collator->setStrength(getECollationStrength(UCOL_TERTIARY));
+ delete strsrch;
+ return FALSE;
+ }
+ collator->setStrength(getECollationStrength(UCOL_TERTIARY));
+ delete strsrch;
+ return TRUE;
+}
+
+UBool StringSearchTest::assertEqualWithAttribute(const SearchData *search,
+ USearchAttributeValue canonical,
+ USearchAttributeValue overlap)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Collator *collator = getCollator(search->collator);
+ BreakIterator *breaker = getBreakIterator(search->breaker);
+ StringSearch *strsrch;
+ UChar temp[128];
+
+
+#if UCONFIG_NO_BREAK_ITERATION
+ if(search->breaker) {
+ return TRUE; /* skip test */
+ }
+#endif
+
+ u_unescape(search->text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp);
+ u_unescape(search->pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp);
+
+#if !UCONFIG_NO_BREAK_ITERATION
+ if (breaker != NULL) {
+ breaker->setText(text);
+ }
+#endif
+ collator->setStrength(getECollationStrength(search->strength));
+ strsrch = new StringSearch(pattern, text, (RuleBasedCollator *)collator,
+ breaker, status);
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, canonical, status);
+ strsrch->setAttribute(USEARCH_OVERLAP, overlap, status);
+
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ return FALSE;
+ }
+
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ collator->setStrength(getECollationStrength(UCOL_TERTIARY));
+ delete strsrch;
+ return FALSE;
+ }
+ collator->setStrength(getECollationStrength(UCOL_TERTIARY));
+ delete strsrch;
+ return TRUE;
+}
+
+void StringSearchTest::TestOpenClose()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *result;
+ BreakIterator *breakiter = m_en_wordbreaker_;
+ UnicodeString pattern;
+ UnicodeString text;
+ UnicodeString temp("a");
+ StringCharacterIterator chariter(text);
+
+ /* testing null arguments */
+ result = new StringSearch(pattern, text, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ errln("Error: NULL arguments should produce an error");
+ }
+ delete result;
+
+ chariter.setText(text);
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, chariter, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ errln("Error: NULL arguments should produce an error");
+ }
+ delete result;
+
+ text.append(0, 0x1);
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, text, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ errln("Error: Empty pattern should produce an error");
+ }
+ delete result;
+
+ chariter.setText(text);
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, chariter, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ errln("Error: Empty pattern should produce an error");
+ }
+ delete result;
+
+ text.remove();
+ pattern.append(temp);
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, text, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ errln("Error: Empty text should produce an error");
+ }
+ delete result;
+
+ chariter.setText(text);
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, chariter, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ errln("Error: Empty text should produce an error");
+ }
+ delete result;
+
+ text.append(temp);
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, text, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ errln("Error: NULL arguments should produce an error");
+ }
+ delete result;
+
+ chariter.setText(text);
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, chariter, NULL, NULL, status);
+ if (U_SUCCESS(status)) {
+ errln("Error: NULL arguments should produce an error");
+ }
+ delete result;
+
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, text, m_en_us_, NULL, status);
+ if (U_FAILURE(status)) {
+ errln("Error: NULL break iterator is valid for opening search");
+ }
+ delete result;
+
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, chariter, m_en_us_, NULL, status);
+ if (U_FAILURE(status)) {
+ errln("Error: NULL break iterator is valid for opening search");
+ }
+ delete result;
+
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, text, Locale::getEnglish(), NULL, status);
+ if (U_FAILURE(status) || result == NULL) {
+ errln("Error: NULL break iterator is valid for opening search");
+ }
+ delete result;
+
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, chariter, Locale::getEnglish(), NULL, status);
+ if (U_FAILURE(status)) {
+ errln("Error: NULL break iterator is valid for opening search");
+ }
+ delete result;
+
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, text, m_en_us_, breakiter, status);
+ if (U_FAILURE(status)) {
+ errln("Error: Break iterator is valid for opening search");
+ }
+ delete result;
+
+ status = U_ZERO_ERROR;
+ result = new StringSearch(pattern, chariter, m_en_us_, NULL, status);
+ if (U_FAILURE(status)) {
+ errln("Error: Break iterator is valid for opening search");
+ }
+ delete result;
+}
+
+void StringSearchTest::TestInitialization()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern;
+ UnicodeString text;
+ UnicodeString temp("a");
+ StringSearch *result;
+ int count;
+
+ /* simple test on the pattern ce construction */
+ pattern.append(temp);
+ pattern.append(temp);
+ text.append(temp);
+ text.append(temp);
+ text.append(temp);
+ result = new StringSearch(pattern, text, m_en_us_, NULL, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening search %s", u_errorName(status));
+ }
+ StringSearch *copy = new StringSearch(*result);
+ if (*(copy->getCollator()) != *(result->getCollator()) ||
+ copy->getBreakIterator() != result->getBreakIterator() ||
+ copy->getMatchedLength() != result->getMatchedLength() ||
+ copy->getMatchedStart() != result->getMatchedStart() ||
+ copy->getOffset() != result->getOffset() ||
+ copy->getPattern() != result->getPattern() ||
+ copy->getText() != result->getText() ||
+ *(copy) != *(result))
+ {
+ errln("Error copying StringSearch");
+ }
+ delete copy;
+
+ copy = (StringSearch *)result->safeClone();
+ if (*(copy->getCollator()) != *(result->getCollator()) ||
+ copy->getBreakIterator() != result->getBreakIterator() ||
+ copy->getMatchedLength() != result->getMatchedLength() ||
+ copy->getMatchedStart() != result->getMatchedStart() ||
+ copy->getOffset() != result->getOffset() ||
+ copy->getPattern() != result->getPattern() ||
+ copy->getText() != result->getText() ||
+ *(copy) != *(result)) {
+ errln("Error copying StringSearch");
+ }
+ delete result;
+
+ /* testing if an extremely large pattern will fail the initialization */
+ for (count = 0; count < 512; count ++) {
+ pattern.append(temp);
+ }
+ result = new StringSearch(pattern, text, m_en_us_, NULL, status);
+ if (*result != *result) {
+ errln("Error: string search object expected to match itself");
+ }
+ if (*result == *copy) {
+ errln("Error: string search objects are not expected to match");
+ }
+ *copy = *result;
+ if (*(copy->getCollator()) != *(result->getCollator()) ||
+ copy->getBreakIterator() != result->getBreakIterator() ||
+ copy->getMatchedLength() != result->getMatchedLength() ||
+ copy->getMatchedStart() != result->getMatchedStart() ||
+ copy->getOffset() != result->getOffset() ||
+ copy->getPattern() != result->getPattern() ||
+ copy->getText() != result->getText() ||
+ *(copy) != *(result)) {
+ errln("Error copying StringSearch");
+ }
+ if (U_FAILURE(status)) {
+ errln("Error opening search %s", u_errorName(status));
+ }
+ delete result;
+ delete copy;
+}
+
+void StringSearchTest::TestBasic()
+{
+ int count = 0;
+ while (BASIC[count].text != NULL) {
+ //printf("count %d", count);
+ if (!assertEqual(&BASIC[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+void StringSearchTest::TestNormExact()
+{
+ int count = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ m_en_us_->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error setting collation normalization %s",
+ u_errorName(status));
+ }
+ while (BASIC[count].text != NULL) {
+ if (!assertEqual(&BASIC[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+ count = 0;
+ while (NORMEXACT[count].text != NULL) {
+ if (!assertEqual(&NORMEXACT[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+ m_en_us_->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_OFF, status);
+ count = 0;
+ while (NONNORMEXACT[count].text != NULL) {
+ if (!assertEqual(&NONNORMEXACT[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+void StringSearchTest::TestStrength()
+{
+ int count = 0;
+ while (STRENGTH[count].text != NULL) {
+ if (!assertEqual(&STRENGTH[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+void StringSearchTest::TestBreakIterator()
+{
+ UChar temp[128];
+ u_unescape(BREAKITERATOREXACT[0].text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(BREAKITERATOREXACT[0].pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ }
+
+ strsrch->setBreakIterator(NULL, status);
+ if (U_FAILURE(status) || strsrch->getBreakIterator() != NULL) {
+ errln("Error usearch_getBreakIterator returned wrong object");
+ }
+
+ strsrch->setBreakIterator(m_en_characterbreaker_, status);
+ if (U_FAILURE(status) ||
+ strsrch->getBreakIterator() != m_en_characterbreaker_) {
+ errln("Error usearch_getBreakIterator returned wrong object");
+ }
+
+ strsrch->setBreakIterator(m_en_wordbreaker_, status);
+ if (U_FAILURE(status) ||
+ strsrch->getBreakIterator() != m_en_wordbreaker_) {
+ errln("Error usearch_getBreakIterator returned wrong object");
+ }
+
+ delete strsrch;
+
+ int count = 0;
+ while (count < 4) {
+ // special purposes for tests numbers 0-3
+ const SearchData *search = &(BREAKITERATOREXACT[count]);
+ RuleBasedCollator *collator = getCollator(search->collator);
+ BreakIterator *breaker = getBreakIterator(search->breaker);
+ StringSearch *strsrch;
+
+ u_unescape(search->text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(search->pattern, temp, 128);
+ pattern.setTo(temp, u_strlen(temp));
+ if (breaker != NULL) {
+ breaker->setText(text);
+ }
+ collator->setStrength(getECollationStrength(search->strength));
+
+ strsrch = new StringSearch(pattern, text, collator, breaker, status);
+ if (U_FAILURE(status) ||
+ strsrch->getBreakIterator() != breaker) {
+ errln("Error setting break iterator");
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ }
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ collator->setStrength(getECollationStrength(UCOL_TERTIARY));
+ delete strsrch;
+ }
+ search = &(BREAKITERATOREXACT[count + 1]);
+ breaker = getBreakIterator(search->breaker);
+ if (breaker != NULL) {
+ breaker->setText(text);
+ }
+ strsrch->setBreakIterator(breaker, status);
+ if (U_FAILURE(status) ||
+ strsrch->getBreakIterator() != breaker) {
+ errln("Error setting break iterator");
+ delete strsrch;
+ }
+ strsrch->reset();
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ errln("Error at test number %d", count);
+ }
+ delete strsrch;
+ count += 2;
+ }
+ count = 0;
+ while (BREAKITERATOREXACT[count].text != NULL) {
+ if (!assertEqual(&BREAKITERATOREXACT[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+#endif
+
+void StringSearchTest::TestVariable()
+{
+ int count = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ m_en_us_->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status);
+ if (U_FAILURE(status)) {
+ errln("Error setting collation alternate attribute %s",
+ u_errorName(status));
+ }
+ while (VARIABLE[count].text != NULL) {
+ logln("variable %d", count);
+ if (!assertEqual(&VARIABLE[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+ m_en_us_->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE,
+ status);
+}
+
+void StringSearchTest::TestOverlap()
+{
+ int count = 0;
+ while (OVERLAP[count].text != NULL) {
+ if (!assertEqualWithAttribute(&OVERLAP[count], USEARCH_OFF,
+ USEARCH_ON)) {
+ errln("Error at overlap test number %d", count);
+ }
+ count ++;
+ }
+ count = 0;
+ while (NONOVERLAP[count].text != NULL) {
+ if (!assertEqual(&NONOVERLAP[count])) {
+ errln("Error at non overlap test number %d", count);
+ }
+ count ++;
+ }
+
+ count = 0;
+ while (count < 1) {
+ const SearchData *search = &(OVERLAP[count]);
+ UChar temp[128];
+ u_unescape(search->text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(search->pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ RuleBasedCollator *collator = getCollator(search->collator);
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *strsrch = new StringSearch(pattern, text,
+ collator, NULL,
+ status);
+
+ strsrch->setAttribute(USEARCH_OVERLAP, USEARCH_ON, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_OVERLAP) != USEARCH_ON) {
+ errln("Error setting overlap option");
+ }
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ delete strsrch;
+ return;
+ }
+
+ search = &(NONOVERLAP[count]);
+ strsrch->setAttribute(USEARCH_OVERLAP, USEARCH_OFF, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_OVERLAP) != USEARCH_OFF) {
+ errln("Error setting overlap option");
+ }
+ strsrch->reset();
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ delete strsrch;
+ errln("Error at test number %d", count);
+ }
+
+ count ++;
+ delete strsrch;
+ }
+}
+
+void StringSearchTest::TestCollator()
+{
+ // test collator that thinks "o" and "p" are the same thing
+ UChar temp[128];
+ u_unescape(COLLATOR[0].text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(COLLATOR[0].pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ delete strsrch;
+ return;
+ }
+ if (!assertEqualWithStringSearch(strsrch, &COLLATOR[0])) {
+ delete strsrch;
+ return;
+ }
+
+ u_unescape(TESTCOLLATORRULE, temp, 128);
+ UnicodeString rules;
+ rules.setTo(temp, u_strlen(temp));
+ RuleBasedCollator *tailored = new RuleBasedCollator(rules, status);
+ tailored->setStrength(getECollationStrength(COLLATOR[1].strength));
+
+ if (U_FAILURE(status)) {
+ errln("Error opening rule based collator %s", u_errorName(status));
+ delete strsrch;
+ if (tailored != NULL) {
+ delete tailored;
+ }
+ return;
+ }
+
+ strsrch->setCollator(tailored, status);
+ if (U_FAILURE(status) || (*strsrch->getCollator()) != (*tailored)) {
+ errln("Error setting rule based collator");
+ delete strsrch;
+ if (tailored != NULL) {
+ delete tailored;
+ }
+ }
+ strsrch->reset();
+ if (!assertEqualWithStringSearch(strsrch, &COLLATOR[1])) {
+ delete strsrch;
+ if (tailored != NULL) {
+ delete tailored;
+ }
+ return;
+ }
+
+ strsrch->setCollator(m_en_us_, status);
+ strsrch->reset();
+ if (U_FAILURE(status) || (*strsrch->getCollator()) != (*m_en_us_)) {
+ errln("Error setting rule based collator");
+ delete strsrch;
+ if (tailored != NULL) {
+ delete tailored;
+ }
+ }
+ if (!assertEqualWithStringSearch(strsrch, &COLLATOR[0])) {
+ errln("Error searching collator test");
+ }
+ delete strsrch;
+ if (tailored != NULL) {
+ delete tailored;
+ }
+}
+
+void StringSearchTest::TestPattern()
+{
+
+ UChar temp[512];
+ int templength;
+ u_unescape(PATTERN[0].text, temp, 512);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(PATTERN[0].pattern, temp, 512);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ m_en_us_->setStrength(getECollationStrength(PATTERN[0].strength));
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ m_en_us_->setStrength(getECollationStrength(UCOL_TERTIARY));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ return;
+ }
+ if (strsrch->getPattern() != pattern) {
+ errln("Error setting pattern");
+ }
+ if (!assertEqualWithStringSearch(strsrch, &PATTERN[0])) {
+ m_en_us_->setStrength(getECollationStrength(UCOL_TERTIARY));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ return;
+ }
+
+ u_unescape(PATTERN[1].pattern, temp, 512);
+ pattern.setTo(temp, u_strlen(temp));
+ strsrch->setPattern(pattern, status);
+ if (pattern != strsrch->getPattern()) {
+ errln("Error setting pattern");
+ m_en_us_->setStrength(getECollationStrength(UCOL_TERTIARY));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ return;
+ }
+ strsrch->reset();
+ if (U_FAILURE(status)) {
+ errln("Error setting pattern %s", u_errorName(status));
+ }
+ if (!assertEqualWithStringSearch(strsrch, &PATTERN[1])) {
+ m_en_us_->setStrength(getECollationStrength(UCOL_TERTIARY));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ return;
+ }
+
+ u_unescape(PATTERN[0].pattern, temp, 512);
+ pattern.setTo(temp, u_strlen(temp));
+ strsrch->setPattern(pattern, status);
+ if (pattern != strsrch->getPattern()) {
+ errln("Error setting pattern");
+ m_en_us_->setStrength(getECollationStrength(UCOL_TERTIARY));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ return;
+ }
+ strsrch->reset();
+ if (U_FAILURE(status)) {
+ errln("Error setting pattern %s", u_errorName(status));
+ }
+ if (!assertEqualWithStringSearch(strsrch, &PATTERN[0])) {
+ m_en_us_->setStrength(getECollationStrength(UCOL_TERTIARY));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ return;
+ }
+ /* enormous pattern size to see if this crashes */
+ for (templength = 0; templength != 512; templength ++) {
+ temp[templength] = 0x61;
+ }
+ temp[511] = 0;
+ pattern.setTo(temp, 511);
+ strsrch->setPattern(pattern, status);
+ if (U_FAILURE(status)) {
+ errln("Error setting pattern with size 512, %s", u_errorName(status));
+ }
+ m_en_us_->setStrength(getECollationStrength(UCOL_TERTIARY));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+}
+
+void StringSearchTest::TestText()
+{
+ UChar temp[128];
+ u_unescape(TEXT[0].text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(TEXT[0].pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ return;
+ }
+ if (text != strsrch->getText()) {
+ errln("Error setting text");
+ }
+ if (!assertEqualWithStringSearch(strsrch, &TEXT[0])) {
+ delete strsrch;
+ return;
+ }
+
+ u_unescape(TEXT[1].text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ strsrch->setText(text, status);
+ if (text != strsrch->getText()) {
+ errln("Error setting text");
+ delete strsrch;
+ return;
+ }
+ if (U_FAILURE(status)) {
+ errln("Error setting text %s", u_errorName(status));
+ }
+ if (!assertEqualWithStringSearch(strsrch, &TEXT[1])) {
+ delete strsrch;
+ return;
+ }
+
+ u_unescape(TEXT[0].text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ StringCharacterIterator chariter(text);
+ strsrch->setText(chariter, status);
+ if (text != strsrch->getText()) {
+ errln("Error setting text");
+ delete strsrch;
+ return;
+ }
+ if (U_FAILURE(status)) {
+ errln("Error setting pattern %s", u_errorName(status));
+ }
+ if (!assertEqualWithStringSearch(strsrch, &TEXT[0])) {
+ errln("Error searching within set text");
+ }
+ delete strsrch;
+}
+
+void StringSearchTest::TestCompositeBoundaries()
+{
+ int count = 0;
+ while (COMPOSITEBOUNDARIES[count].text != NULL) {
+ logln("composite %d", count);
+ if (!assertEqual(&COMPOSITEBOUNDARIES[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+void StringSearchTest::TestGetSetOffset()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern("1234567890123456");
+ UnicodeString text("12345678901234567890123456789012");
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_,
+ NULL, status);
+ /* testing out of bounds error */
+ strsrch->setOffset(-1, status);
+ if (U_SUCCESS(status)) {
+ errln("Error expecting set offset error");
+ }
+ strsrch->setOffset(128, status);
+ if (U_SUCCESS(status)) {
+ errln("Error expecting set offset error");
+ }
+ int index = 0;
+ while (BASIC[index].text != NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ SearchData search = BASIC[index ++];
+ UChar temp[128];
+
+ u_unescape(search.text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(search.pattern, temp, 128);
+ pattern.setTo(temp, u_strlen(temp));
+ strsrch->setText(text, status);
+ strsrch->setPattern(pattern, status);
+ strsrch->getCollator()->setStrength(getECollationStrength(
+ search.strength));
+ strsrch->reset();
+
+ int count = 0;
+ int32_t matchindex = search.offset[count];
+ while (U_SUCCESS(status) && matchindex >= 0) {
+ int32_t matchlength = search.size[count];
+ strsrch->next(status);
+ if (matchindex != strsrch->getMatchedStart() ||
+ matchlength != strsrch->getMatchedLength()) {
+ char *str = toCharString(strsrch->getText());
+ errln("Text: %s", str);
+ str = toCharString(strsrch->getPattern());
+ errln("Pattern: %s", str);
+ errln("Error match found at %d %d",
+ strsrch->getMatchedStart(),
+ strsrch->getMatchedLength());
+ return;
+ }
+ matchindex = search.offset[count + 1] == -1 ? -1 :
+ search.offset[count + 2];
+ if (search.offset[count + 1] != -1) {
+ strsrch->setOffset(search.offset[count + 1] + 1, status);
+ if (strsrch->getOffset() != search.offset[count + 1] + 1) {
+ errln("Error setting offset\n");
+ return;
+ }
+ }
+
+ count += 2;
+ }
+ strsrch->next(status);
+ if (strsrch->getMatchedStart() != USEARCH_DONE) {
+ char *str = toCharString(strsrch->getText());
+ errln("Text: %s", str);
+ str = toCharString(strsrch->getPattern());
+ errln("Pattern: %s", str);
+ errln("Error match found at %d %d",
+ strsrch->getMatchedStart(),
+ strsrch->getMatchedLength());
+ return;
+ }
+ }
+ strsrch->getCollator()->setStrength(getECollationStrength(
+ UCOL_TERTIARY));
+ delete strsrch;
+}
+
+void StringSearchTest::TestGetSetAttribute()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern("pattern");
+ UnicodeString text("text");
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ if (U_FAILURE(status)) {
+ errln("Error opening search %s", u_errorName(status));
+ return;
+ }
+
+ strsrch->setAttribute(USEARCH_OVERLAP, USEARCH_DEFAULT, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_OVERLAP) != USEARCH_OFF) {
+ errln("Error setting overlap to the default");
+ }
+ strsrch->setAttribute(USEARCH_OVERLAP, USEARCH_ON, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_OVERLAP) != USEARCH_ON) {
+ errln("Error setting overlap true");
+ }
+ strsrch->setAttribute(USEARCH_OVERLAP, USEARCH_OFF, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_OVERLAP) != USEARCH_OFF) {
+ errln("Error setting overlap false");
+ }
+ strsrch->setAttribute(USEARCH_OVERLAP, USEARCH_ATTRIBUTE_VALUE_COUNT,
+ status);
+ if (U_SUCCESS(status)) {
+ errln("Error setting overlap to illegal value");
+ }
+ status = U_ZERO_ERROR;
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_DEFAULT, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_CANONICAL_MATCH) != USEARCH_OFF) {
+ errln("Error setting canonical match to the default");
+ }
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_CANONICAL_MATCH) != USEARCH_ON) {
+ errln("Error setting canonical match true");
+ }
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_OFF, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_CANONICAL_MATCH) != USEARCH_OFF) {
+ errln("Error setting canonical match false");
+ }
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH,
+ USEARCH_ATTRIBUTE_VALUE_COUNT, status);
+ if (U_SUCCESS(status)) {
+ errln("Error setting canonical match to illegal value");
+ }
+ status = U_ZERO_ERROR;
+ strsrch->setAttribute(USEARCH_ATTRIBUTE_COUNT, USEARCH_DEFAULT, status);
+ if (U_SUCCESS(status)) {
+ errln("Error setting illegal attribute success");
+ }
+
+ delete strsrch;
+}
+
+void StringSearchTest::TestGetMatch()
+{
+ UChar temp[128];
+ SearchData search = MATCH[0];
+ u_unescape(search.text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(search.pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ return;
+ }
+
+ int count = 0;
+ int32_t matchindex = search.offset[count];
+ UnicodeString matchtext;
+ while (U_SUCCESS(status) && matchindex >= 0) {
+ int32_t matchlength = search.size[count];
+ strsrch->next(status);
+ if (matchindex != strsrch->getMatchedStart() ||
+ matchlength != strsrch->getMatchedLength()) {
+ char *str = toCharString(strsrch->getText());
+ errln("Text: %s", str);
+ str = toCharString(strsrch->getPattern());
+ errln("Pattern: %s", str);
+ errln("Error match found at %d %d", strsrch->getMatchedStart(),
+ strsrch->getMatchedLength());
+ return;
+ }
+ count ++;
+
+ status = U_ZERO_ERROR;
+ strsrch->getMatchedText(matchtext);
+ if (matchtext.length() != matchlength || U_FAILURE(status)){
+ errln("Error getting match text");
+ }
+ matchindex = search.offset[count];
+ }
+ status = U_ZERO_ERROR;
+ strsrch->next(status);
+ if (strsrch->getMatchedStart() != USEARCH_DONE ||
+ strsrch->getMatchedLength() != 0) {
+ errln("Error end of match not found");
+ }
+ status = U_ZERO_ERROR;
+ strsrch->getMatchedText(matchtext);
+ if (matchtext.length() != 0) {
+ errln("Error getting null matches");
+ }
+ delete strsrch;
+}
+
+void StringSearchTest::TestSetMatch()
+{
+ int count = 0;
+ while (MATCH[count].text != NULL) {
+ SearchData search = MATCH[count];
+ UChar temp[128];
+ UErrorCode status = U_ZERO_ERROR;
+ u_unescape(search.text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(search.pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_,
+ NULL, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ return;
+ }
+
+ int size = 0;
+ while (search.offset[size] != -1) {
+ size ++;
+ }
+
+ if (strsrch->first(status) != search.offset[0] || U_FAILURE(status)) {
+ errln("Error getting first match");
+ }
+ if (strsrch->last(status) != search.offset[size -1] ||
+ U_FAILURE(status)) {
+ errln("Error getting last match");
+ }
+
+ int index = 0;
+ while (index < size) {
+ if (index + 2 < size) {
+ if (strsrch->following(search.offset[index + 2] - 1, status)
+ != search.offset[index + 2] || U_FAILURE(status)) {
+ errln("Error getting following match at index %d",
+ search.offset[index + 2] - 1);
+ }
+ }
+ if (index + 1 < size) {
+ if (strsrch->preceding(search.offset[index + 1] +
+ search.size[index + 1] + 1,
+ status) != search.offset[index + 1] ||
+ U_FAILURE(status)) {
+ errln("Error getting preceeding match at index %d",
+ search.offset[index + 1] + 1);
+ }
+ }
+ index += 2;
+ }
+ status = U_ZERO_ERROR;
+ if (strsrch->following(text.length(), status) != USEARCH_DONE) {
+ errln("Error expecting out of bounds match");
+ }
+ if (strsrch->preceding(0, status) != USEARCH_DONE) {
+ errln("Error expecting out of bounds match");
+ }
+ count ++;
+ delete strsrch;
+ }
+}
+
+void StringSearchTest::TestReset()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString text("fish fish");
+ UnicodeString pattern("s");
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+ return;
+ }
+ strsrch->setAttribute(USEARCH_OVERLAP, USEARCH_ON, status);
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ strsrch->setOffset(9, status);
+ if (U_FAILURE(status)) {
+ errln("Error setting attributes and offsets");
+ }
+ else {
+ strsrch->reset();
+ if (strsrch->getAttribute(USEARCH_OVERLAP) != USEARCH_OFF ||
+ strsrch->getAttribute(USEARCH_CANONICAL_MATCH) != USEARCH_OFF ||
+ strsrch->getOffset() != 0 || strsrch->getMatchedLength() != 0 ||
+ strsrch->getMatchedStart() != USEARCH_DONE) {
+ errln("Error resetting string search");
+ }
+ strsrch->previous(status);
+ if (strsrch->getMatchedStart() != 7 ||
+ strsrch->getMatchedLength() != 1) {
+ errln("Error resetting string search\n");
+ }
+ }
+ delete strsrch;
+}
+
+void StringSearchTest::TestSupplementary()
+{
+ int count = 0;
+ while (SUPPLEMENTARY[count].text != NULL) {
+ if (!assertEqual(&SUPPLEMENTARY[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+void StringSearchTest::TestContraction()
+{
+ UChar temp[128];
+ UErrorCode status = U_ZERO_ERROR;
+
+ u_unescape(CONTRACTIONRULE, temp, 128);
+ UnicodeString rules;
+ rules.setTo(temp, u_strlen(temp));
+ RuleBasedCollator *collator = new RuleBasedCollator(rules,
+ getECollationStrength(UCOL_TERTIARY), UCOL_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening collator %s", u_errorName(status));
+ }
+ UnicodeString text("text");
+ UnicodeString pattern("pattern");
+ StringSearch *strsrch = new StringSearch(pattern, text, collator, NULL,
+ status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ }
+
+ int count = 0;
+ while (CONTRACTION[count].text != NULL) {
+ u_unescape(CONTRACTION[count].text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(CONTRACTION[count].pattern, temp, 128);
+ pattern.setTo(temp, u_strlen(temp));
+ strsrch->setText(text, status);
+ strsrch->setPattern(pattern, status);
+ if (!assertEqualWithStringSearch(strsrch, &CONTRACTION[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+ delete strsrch;
+ delete collator;
+}
+
+void StringSearchTest::TestIgnorable()
+{
+ UChar temp[128];
+ u_unescape(IGNORABLERULE, temp, 128);
+ UnicodeString rules;
+ rules.setTo(temp, u_strlen(temp));
+ UErrorCode status = U_ZERO_ERROR;
+ int count = 0;
+ RuleBasedCollator *collator = new RuleBasedCollator(rules,
+ getECollationStrength(IGNORABLE[count].strength),
+ UCOL_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening collator %s", u_errorName(status));
+ return;
+ }
+ UnicodeString pattern("pattern");
+ UnicodeString text("text");
+ StringSearch *strsrch = new StringSearch(pattern, text, collator, NULL,
+ status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ delete collator;
+ return;
+ }
+
+ while (IGNORABLE[count].text != NULL) {
+ u_unescape(IGNORABLE[count].text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(IGNORABLE[count].pattern, temp, 128);
+ pattern.setTo(temp, u_strlen(temp));
+ strsrch->setText(text, status);
+ strsrch->setPattern(pattern, status);
+ if (!assertEqualWithStringSearch(strsrch, &IGNORABLE[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+ delete strsrch;
+ delete collator;
+}
+
+void StringSearchTest::TestDiactricMatch()
+{
+ UChar temp[128];
+ UErrorCode status = U_ZERO_ERROR;
+ int count = 0;
+ RuleBasedCollator* coll = NULL;
+ StringSearch *strsrch = NULL;
+
+ UnicodeString pattern("pattern");
+ UnicodeString text("text");
+
+ const SearchData *search;
+
+ search = &(DIACTRICMATCH[count]);
+ while (search->text != NULL) {
+ coll = getCollator(search->collator);
+ coll->setStrength(getECollationStrength(search->strength));
+ strsrch = new StringSearch(pattern, text, coll, getBreakIterator(search->breaker), status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ return;
+ }
+ u_unescape(search->text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(search->pattern, temp, 128);
+ pattern.setTo(temp, u_strlen(temp));
+ strsrch->setText(text, status);
+ strsrch->setPattern(pattern, status);
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ errln("Error at test number %d", count);
+ }
+ search = &(DIACTRICMATCH[++count]);
+ delete strsrch;
+ }
+
+}
+
+void StringSearchTest::TestCanonical()
+{
+ int count = 0;
+ while (BASICCANONICAL[count].text != NULL) {
+ if (!assertCanonicalEqual(&BASICCANONICAL[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+void StringSearchTest::TestNormCanonical()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ m_en_us_->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
+ int count = 0;
+ while (NORMCANONICAL[count].text != NULL) {
+ if (!assertCanonicalEqual(&NORMCANONICAL[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+ m_en_us_->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_OFF, status);
+}
+
+void StringSearchTest::TestStrengthCanonical()
+{
+ int count = 0;
+ while (STRENGTHCANONICAL[count].text != NULL) {
+ if (!assertCanonicalEqual(&STRENGTHCANONICAL[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+#if !UCONFIG_NO_BREAK_ITERATION
+
+void StringSearchTest::TestBreakIteratorCanonical()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int count = 0;
+
+ while (count < 4) {
+ // special purposes for tests numbers 0-3
+ UChar temp[128];
+ const SearchData *search = &(BREAKITERATORCANONICAL[count]);
+
+ u_unescape(search->text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(search->pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+ RuleBasedCollator *collator = getCollator(search->collator);
+ collator->setStrength(getECollationStrength(search->strength));
+
+ BreakIterator *breaker = getBreakIterator(search->breaker);
+ StringSearch *strsrch = new StringSearch(pattern, text, collator,
+ breaker, status);
+ if (U_FAILURE(status)) {
+ errln("Error creating string search data");
+ return;
+ }
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (U_FAILURE(status) ||
+ strsrch->getBreakIterator() != breaker) {
+ errln("Error setting break iterator");
+ delete strsrch;
+ return;
+ }
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ collator->setStrength(getECollationStrength(UCOL_TERTIARY));
+ delete strsrch;
+ return;
+ }
+ search = &(BREAKITERATOREXACT[count + 1]);
+ breaker = getBreakIterator(search->breaker);
+ if (breaker == NULL) {
+ errln("Error creating BreakIterator");
+ return;
+ }
+ breaker->setText(strsrch->getText());
+ strsrch->setBreakIterator(breaker, status);
+ if (U_FAILURE(status) || strsrch->getBreakIterator() != breaker) {
+ errln("Error setting break iterator");
+ delete strsrch;
+ return;
+ }
+ strsrch->reset();
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ errln("Error at test number %d", count);
+ return;
+ }
+ delete strsrch;
+ count += 2;
+ }
+ count = 0;
+ while (BREAKITERATORCANONICAL[count].text != NULL) {
+ if (!assertEqual(&BREAKITERATORCANONICAL[count])) {
+ errln("Error at test number %d", count);
+ return;
+ }
+ count ++;
+ }
+}
+
+#endif
+
+void StringSearchTest::TestVariableCanonical()
+{
+ int count = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ m_en_us_->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status);
+ if (U_FAILURE(status)) {
+ errln("Error setting collation alternate attribute %s",
+ u_errorName(status));
+ }
+ while (VARIABLE[count].text != NULL) {
+ logln("variable %d", count);
+ if (!assertCanonicalEqual(&VARIABLE[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+ m_en_us_->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE,
+ status);
+}
+
+void StringSearchTest::TestOverlapCanonical()
+{
+ int count = 0;
+ while (OVERLAPCANONICAL[count].text != NULL) {
+ if (!assertEqualWithAttribute(&OVERLAPCANONICAL[count], USEARCH_ON,
+ USEARCH_ON)) {
+ errln("Error at overlap test number %d", count);
+ }
+ count ++;
+ }
+ count = 0;
+ while (NONOVERLAP[count].text != NULL) {
+ if (!assertCanonicalEqual(&NONOVERLAPCANONICAL[count])) {
+ errln("Error at non overlap test number %d", count);
+ }
+ count ++;
+ }
+
+ count = 0;
+ while (count < 1) {
+ UChar temp[128];
+ const SearchData *search = &(OVERLAPCANONICAL[count]);
+ UErrorCode status = U_ZERO_ERROR;
+
+ u_unescape(search->text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(search->pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+ RuleBasedCollator *collator = getCollator(search->collator);
+ StringSearch *strsrch = new StringSearch(pattern, text, collator,
+ NULL, status);
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ strsrch->setAttribute(USEARCH_OVERLAP, USEARCH_ON, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_OVERLAP) != USEARCH_ON) {
+ errln("Error setting overlap option");
+ }
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ delete strsrch;
+ return;
+ }
+ search = &(NONOVERLAPCANONICAL[count]);
+ strsrch->setAttribute(USEARCH_OVERLAP, USEARCH_OFF, status);
+ if (U_FAILURE(status) ||
+ strsrch->getAttribute(USEARCH_OVERLAP) != USEARCH_OFF) {
+ errln("Error setting overlap option");
+ }
+ strsrch->reset();
+ if (!assertEqualWithStringSearch(strsrch, search)) {
+ delete strsrch;
+ errln("Error at test number %d", count);
+ }
+
+ count ++;
+ delete strsrch;
+ }
+}
+
+void StringSearchTest::TestCollatorCanonical()
+{
+ /* test collator that thinks "o" and "p" are the same thing */
+ UChar temp[128];
+ u_unescape(COLLATORCANONICAL[0].text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(COLLATORCANONICAL[0].pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_,
+ NULL, status);
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ }
+ if (!assertEqualWithStringSearch(strsrch, &COLLATORCANONICAL[0])) {
+ delete strsrch;
+ return;
+ }
+
+ u_unescape(TESTCOLLATORRULE, temp, 128);
+ UnicodeString rules;
+ rules.setTo(temp, u_strlen(temp));
+ RuleBasedCollator *tailored = new RuleBasedCollator(rules,
+ getECollationStrength(COLLATORCANONICAL[1].strength),
+ UCOL_ON, status);
+
+ if (U_FAILURE(status)) {
+ errln("Error opening rule based collator %s", u_errorName(status));
+ }
+
+ strsrch->setCollator(tailored, status);
+ if (U_FAILURE(status) || *(strsrch->getCollator()) != *tailored) {
+ errln("Error setting rule based collator");
+ }
+ strsrch->reset();
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (!assertEqualWithStringSearch(strsrch, &COLLATORCANONICAL[1])) {
+ delete strsrch;
+ if (tailored != NULL) {
+ delete tailored;
+ }
+ }
+
+ strsrch->setCollator(m_en_us_, status);
+ strsrch->reset();
+ if (U_FAILURE(status) || *(strsrch->getCollator()) != *m_en_us_) {
+ errln("Error setting rule based collator");
+ }
+ if (!assertEqualWithStringSearch(strsrch, &COLLATORCANONICAL[0])) {
+ }
+ delete strsrch;
+ if (tailored != NULL) {
+ delete tailored;
+ }
+}
+
+void StringSearchTest::TestPatternCanonical()
+{
+
+ UChar temp[128];
+
+ u_unescape(PATTERNCANONICAL[0].text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(PATTERNCANONICAL[0].pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ m_en_us_->setStrength(
+ getECollationStrength(PATTERNCANONICAL[0].strength));
+
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ goto ENDTESTPATTERN;
+ }
+ if (pattern != strsrch->getPattern()) {
+ errln("Error setting pattern");
+ }
+ if (!assertEqualWithStringSearch(strsrch, &PATTERNCANONICAL[0])) {
+ goto ENDTESTPATTERN;
+ }
+
+ u_unescape(PATTERNCANONICAL[1].pattern, temp, 128);
+ pattern.setTo(temp, u_strlen(temp));
+ strsrch->setPattern(pattern, status);
+ if (pattern != strsrch->getPattern()) {
+ errln("Error setting pattern");
+ goto ENDTESTPATTERN;
+ }
+ strsrch->reset();
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error setting pattern %s", u_errorName(status));
+ }
+ if (!assertEqualWithStringSearch(strsrch, &PATTERNCANONICAL[1])) {
+ goto ENDTESTPATTERN;
+ }
+
+ u_unescape(PATTERNCANONICAL[0].pattern, temp, 128);
+ pattern.setTo(temp, u_strlen(temp));
+ strsrch->setPattern(pattern, status);
+ if (pattern != strsrch->getPattern()) {
+ errln("Error setting pattern");
+ goto ENDTESTPATTERN;
+ }
+ strsrch->reset();
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error setting pattern %s", u_errorName(status));
+ }
+ if (!assertEqualWithStringSearch(strsrch, &PATTERNCANONICAL[0])) {
+ goto ENDTESTPATTERN;
+ }
+ENDTESTPATTERN:
+ m_en_us_->setStrength(getECollationStrength(UCOL_TERTIARY));
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+}
+
+void StringSearchTest::TestTextCanonical()
+{
+ UChar temp[128];
+ u_unescape(TEXTCANONICAL[0].text, temp, 128);
+ UnicodeString text;
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(TEXTCANONICAL[0].pattern, temp, 128);
+ UnicodeString pattern;
+ pattern.setTo(temp, u_strlen(temp));
+
+ UErrorCode status = U_ZERO_ERROR;
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ goto ENDTESTPATTERN;
+ }
+ if (text != strsrch->getText()) {
+ errln("Error setting text");
+ }
+ if (!assertEqualWithStringSearch(strsrch, &TEXTCANONICAL[0])) {
+ goto ENDTESTPATTERN;
+ }
+
+ u_unescape(TEXTCANONICAL[1].text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ strsrch->setText(text, status);
+ if (text != strsrch->getText()) {
+ errln("Error setting text");
+ goto ENDTESTPATTERN;
+ }
+ if (U_FAILURE(status)) {
+ errln("Error setting text %s", u_errorName(status));
+ }
+ if (!assertEqualWithStringSearch(strsrch, &TEXTCANONICAL[1])) {
+ goto ENDTESTPATTERN;
+ }
+
+ u_unescape(TEXTCANONICAL[0].text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ strsrch->setText(text, status);
+ if (text != strsrch->getText()) {
+ errln("Error setting text");
+ goto ENDTESTPATTERN;
+ }
+ if (U_FAILURE(status)) {
+ errln("Error setting pattern %s", u_errorName(status));
+ }
+ if (!assertEqualWithStringSearch(strsrch, &TEXTCANONICAL[0])) {
+ goto ENDTESTPATTERN;
+ }
+ENDTESTPATTERN:
+ if (strsrch != NULL) {
+ delete strsrch;
+ }
+}
+
+void StringSearchTest::TestCompositeBoundariesCanonical()
+{
+ int count = 0;
+ while (COMPOSITEBOUNDARIESCANONICAL[count].text != NULL) {
+ logln("composite %d", count);
+ if (!assertCanonicalEqual(&COMPOSITEBOUNDARIESCANONICAL[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+void StringSearchTest::TestGetSetOffsetCanonical()
+{
+
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString text("text");
+ UnicodeString pattern("pattern");
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ /* testing out of bounds error */
+ strsrch->setOffset(-1, status);
+ if (U_SUCCESS(status)) {
+ errln("Error expecting set offset error");
+ }
+ strsrch->setOffset(128, status);
+ if (U_SUCCESS(status)) {
+ errln("Error expecting set offset error");
+ }
+ int index = 0;
+ UChar temp[128];
+ while (BASICCANONICAL[index].text != NULL) {
+ SearchData search = BASICCANONICAL[index ++];
+ if (BASICCANONICAL[index].text == NULL) {
+ /* skip the last one */
+ break;
+ }
+
+ u_unescape(search.text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(search.pattern, temp, 128);
+ pattern.setTo(temp, u_strlen(temp));
+
+ UErrorCode status = U_ZERO_ERROR;
+ strsrch->setText(text, status);
+
+ strsrch->setPattern(pattern, status);
+
+ int count = 0;
+ int32_t matchindex = search.offset[count];
+ while (U_SUCCESS(status) && matchindex >= 0) {
+ int32_t matchlength = search.size[count];
+ strsrch->next(status);
+ if (matchindex != strsrch->getMatchedStart() ||
+ matchlength != strsrch->getMatchedLength()) {
+ char *str = toCharString(strsrch->getText());
+ errln("Text: %s", str);
+ str = toCharString(strsrch->getPattern());
+ errln("Pattern: %s", str);
+ errln("Error match found at %d %d",
+ strsrch->getMatchedStart(),
+ strsrch->getMatchedLength());
+ return;
+ }
+ matchindex = search.offset[count + 1] == -1 ? -1 :
+ search.offset[count + 2];
+ if (search.offset[count + 1] != -1) {
+ strsrch->setOffset(search.offset[count + 1] + 1, status);
+ if (strsrch->getOffset() != search.offset[count + 1] + 1) {
+ errln("Error setting offset");
+ return;
+ }
+ }
+
+ count += 2;
+ }
+ strsrch->next(status);
+ if (strsrch->getMatchedStart() != USEARCH_DONE) {
+ char *str = toCharString(strsrch->getText());
+ errln("Text: %s", str);
+ str = toCharString(strsrch->getPattern());
+ errln("Pattern: %s", str);
+ errln("Error match found at %d %d", strsrch->getMatchedStart(),
+ strsrch->getMatchedLength());
+ return;
+ }
+ }
+ delete strsrch;
+}
+
+void StringSearchTest::TestSupplementaryCanonical()
+{
+ int count = 0;
+ while (SUPPLEMENTARYCANONICAL[count].text != NULL) {
+ if (!assertCanonicalEqual(&SUPPLEMENTARYCANONICAL[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+}
+
+void StringSearchTest::TestContractionCanonical()
+{
+ UChar temp[128];
+
+ u_unescape(CONTRACTIONRULE, temp, 128);
+ UnicodeString rules;
+ rules.setTo(temp, u_strlen(temp));
+
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedCollator *collator = new RuleBasedCollator(rules,
+ getECollationStrength(UCOL_TERTIARY), UCOL_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening collator %s", u_errorName(status));
+ }
+ UnicodeString text("text");
+ UnicodeString pattern("pattern");
+ StringSearch *strsrch = new StringSearch(pattern, text, collator, NULL,
+ status);
+ strsrch->setAttribute(USEARCH_CANONICAL_MATCH, USEARCH_ON, status);
+ if (U_FAILURE(status)) {
+ errln("Error opening string search %s", u_errorName(status));
+ }
+
+ int count = 0;
+ while (CONTRACTIONCANONICAL[count].text != NULL) {
+ u_unescape(CONTRACTIONCANONICAL[count].text, temp, 128);
+ text.setTo(temp, u_strlen(temp));
+ u_unescape(CONTRACTIONCANONICAL[count].pattern, temp, 128);
+ pattern.setTo(temp, u_strlen(temp));
+ strsrch->setText(text, status);
+ strsrch->setPattern(pattern, status);
+ if (!assertEqualWithStringSearch(strsrch,
+ &CONTRACTIONCANONICAL[count])) {
+ errln("Error at test number %d", count);
+ }
+ count ++;
+ }
+ delete strsrch;
+ delete collator;
+}
+
+void StringSearchTest::TestUClassID()
+{
+ char id = *((char *)StringSearch::getStaticClassID());
+ if (id != 0) {
+ errln("Static class id for StringSearch should be 0");
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString text("text");
+ UnicodeString pattern("pattern");
+ StringSearch *strsrch = new StringSearch(pattern, text, m_en_us_, NULL,
+ status);
+ id = *((char *)strsrch->getDynamicClassID());
+ if (id != 0) {
+ errln("Dynamic class id for StringSearch should be 0");
+ }
+ delete strsrch;
+}
+
+class TestSearch : public SearchIterator
+{
+public:
+ TestSearch(const TestSearch &obj);
+ TestSearch(const UnicodeString &text,
+ BreakIterator *breakiter,
+ const UnicodeString &pattern);
+ ~TestSearch();
+
+ void setOffset(int32_t position, UErrorCode &status);
+ int32_t getOffset() const;
+ SearchIterator* safeClone() const;
+
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @draft ICU 2.2
+ */
+ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @draft ICU 2.2
+ */
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+ UBool operator!=(const TestSearch &that) const;
+
+ UnicodeString m_pattern_;
+
+protected:
+ int32_t handleNext(int32_t position, UErrorCode &status);
+ int32_t handlePrev(int32_t position, UErrorCode &status);
+ TestSearch & operator=(const TestSearch &that);
+
+private:
+
+ /**
+ * The address of this static class variable serves as this class's ID
+ * for ICU "poor man's RTTI".
+ */
+ static const char fgClassID;
+ uint32_t m_offset_;
+};
+
+const char TestSearch::fgClassID=0;
+
+TestSearch::TestSearch(const TestSearch &obj) : SearchIterator(obj)
+{
+ m_offset_ = obj.m_offset_;
+ m_pattern_ = obj.m_pattern_;
+}
+
+TestSearch::TestSearch(const UnicodeString &text,
+ BreakIterator *breakiter,
+ const UnicodeString &pattern) : SearchIterator()
+{
+ m_breakiterator_ = breakiter;
+ m_pattern_ = pattern;
+ m_text_ = text;
+ m_offset_ = 0;
+ m_pattern_ = pattern;
+}
+
+TestSearch::~TestSearch()
+{
+}
+
+
+void TestSearch::setOffset(int32_t position, UErrorCode &status)
+{
+ if (position >= 0 && position <= m_text_.length()) {
+ m_offset_ = position;
+ }
+ else {
+ status = U_INDEX_OUTOFBOUNDS_ERROR;
+ }
+}
+
+int32_t TestSearch::getOffset() const
+{
+ return m_offset_;
+}
+
+SearchIterator * TestSearch::safeClone() const
+{
+ return new TestSearch(m_text_, m_breakiterator_, m_pattern_);
+}
+
+UBool TestSearch::operator!=(const TestSearch &that) const
+{
+ if (SearchIterator::operator !=(that)) {
+ return FALSE;
+ }
+ return m_offset_ != that.m_offset_ || m_pattern_ != that.m_pattern_;
+}
+
+int32_t TestSearch::handleNext(int32_t start, UErrorCode &status)
+{
+ if(U_SUCCESS(status)) {
+ int match = m_text_.indexOf(m_pattern_, start);
+ if (match < 0) {
+ m_offset_ = m_text_.length();
+ setMatchStart(m_offset_);
+ setMatchLength(0);
+ return USEARCH_DONE;
+ }
+ setMatchStart(match);
+ m_offset_ = match;
+ setMatchLength(m_pattern_.length());
+ return match;
+ } else {
+ return USEARCH_DONE;
+ }
+}
+
+int32_t TestSearch::handlePrev(int32_t start, UErrorCode &status)
+{
+ if(U_SUCCESS(status)) {
+ int match = m_text_.lastIndexOf(m_pattern_, 0, start);
+ if (match < 0) {
+ m_offset_ = 0;
+ setMatchStart(m_offset_);
+ setMatchLength(0);
+ return USEARCH_DONE;
+ }
+ setMatchStart(match);
+ m_offset_ = match;
+ setMatchLength(m_pattern_.length());
+ return match;
+ } else {
+ return USEARCH_DONE;
+ }
+}
+
+TestSearch & TestSearch::operator=(const TestSearch &that)
+{
+ SearchIterator::operator=(that);
+ m_offset_ = that.m_offset_;
+ m_pattern_ = that.m_pattern_;
+ return *this;
+}
+
+void StringSearchTest::TestSubclass()
+{
+ UnicodeString text("abc abcd abc");
+ UnicodeString pattern("abc");
+ TestSearch search(text, NULL, pattern);
+ TestSearch search2(search);
+ int expected[] = {0, 4, 9};
+ UErrorCode status = U_ZERO_ERROR;
+ int i;
+ StringCharacterIterator chariter(text);
+
+ search.setText(text, status);
+ if (search.getText() != search2.getText()) {
+ errln("Error setting text");
+ }
+
+ search.setText(chariter, status);
+ if (search.getText() != search2.getText()) {
+ errln("Error setting text");
+ }
+
+ search.reset();
+ // comparing constructors
+
+ for (i = 0; i < (int)(sizeof(expected) / sizeof(expected[0])); i ++) {
+ if (search.next(status) != expected[i]) {
+ errln("Error getting next match");
+ }
+ if (search.getMatchedLength() != search.m_pattern_.length()) {
+ errln("Error getting next match length");
+ }
+ }
+ if (search.next(status) != USEARCH_DONE) {
+ errln("Error should have reached the end of the iteration");
+ }
+ for (i = sizeof(expected) / sizeof(expected[0]) - 1; i >= 0; i --) {
+ if (search.previous(status) != expected[i]) {
+ errln("Error getting previous match");
+ }
+ if (search.getMatchedLength() != search.m_pattern_.length()) {
+ errln("Error getting previous match length");
+ }
+ }
+ if (search.previous(status) != USEARCH_DONE) {
+ errln("Error should have reached the start of the iteration");
+ }
+}
+
+class StubSearchIterator:public SearchIterator{
+public:
+ StubSearchIterator(){}
+ virtual void setOffset(int32_t , UErrorCode &) {};
+ virtual int32_t getOffset(void) const {return 0;};
+ virtual SearchIterator* safeClone(void) const {return NULL;};
+ virtual int32_t handleNext(int32_t , UErrorCode &){return 0;};
+ virtual int32_t handlePrev(int32_t , UErrorCode &) {return 0;};
+ virtual UClassID getDynamicClassID() const {
+ static char classID = 0;
+ return (UClassID)&classID;
+ }
+};
+
+void StringSearchTest::TestCoverage(){
+ StubSearchIterator stub1, stub2;
+ UErrorCode status = U_ZERO_ERROR;
+
+ if (stub1 != stub2){
+ errln("new StubSearchIterator should be equal");
+ }
+
+ stub2.setText(UnicodeString("ABC"), status);
+ if (U_FAILURE(status)) {
+ errln("Error: SearchIterator::SetText");
+ }
+
+ stub1 = stub2;
+ if (stub1 != stub2){
+ errln("SearchIterator::operator = assigned object should be equal");
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/srchtest.h b/Build/source/libs/icu/icu-xetex/test/intltest/srchtest.h
new file mode 100644
index 00000000000..e27ec620bb0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/srchtest.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2001-2005, International Business Machines Corporation and others
+ * All Rights Reserved.
+ ***************************************************************************/
+
+#ifndef _STRSRCH_H
+#define _STRSRCH_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/tblcoll.h"
+#include "unicode/brkiter.h"
+#include "intltest.h"
+#include "unicode/usearch.h"
+
+struct SearchData;
+typedef struct SearchData SearchData;
+
+class StringSearchTest: public IntlTest
+{
+public:
+ StringSearchTest();
+ virtual ~StringSearchTest();
+
+ void runIndexedTest(int32_t index, UBool exec, const char* &name,
+ char* par = NULL);
+
+private:
+ RuleBasedCollator *m_en_us_;
+ RuleBasedCollator *m_fr_fr_;
+ RuleBasedCollator *m_de_;
+ RuleBasedCollator *m_es_;
+ BreakIterator *m_en_wordbreaker_;
+ BreakIterator *m_en_characterbreaker_;
+
+ RuleBasedCollator * getCollator(const char *collator);
+ BreakIterator * getBreakIterator(const char *breaker);
+ char * toCharString(const UnicodeString &text);
+ Collator::ECollationStrength getECollationStrength(
+ const UCollationStrength &strength) const;
+ UBool assertEqualWithStringSearch( StringSearch *strsrch,
+ const SearchData *search);
+ UBool assertEqual(const SearchData *search);
+ UBool assertCanonicalEqual(const SearchData *search);
+ UBool assertEqualWithAttribute(const SearchData *search,
+ USearchAttributeValue canonical,
+ USearchAttributeValue overlap);
+ void TestOpenClose();
+ void TestInitialization();
+ void TestBasic();
+ void TestNormExact();
+ void TestStrength();
+#if !UCONFIG_NO_BREAK_ITERATION
+ void TestBreakIterator();
+#endif
+ void TestVariable();
+ void TestOverlap();
+ void TestCollator();
+ void TestPattern();
+ void TestText();
+ void TestCompositeBoundaries();
+ void TestGetSetOffset();
+ void TestGetSetAttribute();
+ void TestGetMatch();
+ void TestSetMatch();
+ void TestReset();
+ void TestSupplementary();
+ void TestContraction();
+ void TestIgnorable();
+ void TestCanonical();
+ void TestNormCanonical();
+ void TestStrengthCanonical();
+#if !UCONFIG_NO_BREAK_ITERATION
+ void TestBreakIteratorCanonical();
+#endif
+ void TestVariableCanonical();
+ void TestOverlapCanonical();
+ void TestCollatorCanonical();
+ void TestPatternCanonical();
+ void TestTextCanonical();
+ void TestCompositeBoundariesCanonical();
+ void TestGetSetOffsetCanonical();
+ void TestSupplementaryCanonical();
+ void TestContractionCanonical();
+ void TestUClassID();
+ void TestSubclass();
+ void TestCoverage();
+ void TestDiactricMatch();
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/strcase.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/strcase.cpp
new file mode 100644
index 00000000000..0645f1269ce
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/strcase.cpp
@@ -0,0 +1,542 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2002-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: strcase.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2002mar12
+* created by: Markus W. Scherer
+*
+* Test file for string casing C++ API functions.
+*/
+
+#include "unicode/uchar.h"
+#include "unicode/ures.h"
+#include "unicode/uloc.h"
+#include "unicode/locid.h"
+#include "unicode/ubrk.h"
+#include "unicode/unistr.h"
+#include "unicode/ucasemap.h"
+#include "ustrtest.h"
+#include "unicode/tstdtmod.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+StringCaseTest::~StringCaseTest() {}
+
+void
+StringCaseTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) {
+ if (exec) logln("TestSuite StringCaseTest: ");
+ switch (index) {
+ case 0: name = "TestCaseConversion"; if (exec) TestCaseConversion(); break;
+ case 1:
+ name = "TestCasing";
+#if !UCONFIG_NO_BREAK_ITERATION
+ if(exec) TestCasing();
+#endif
+ break;
+
+ default: name = ""; break; //needed to end loop
+ }
+}
+
+void
+StringCaseTest::TestCaseConversion()
+{
+ static const UChar uppercaseGreek[] =
+ { 0x399, 0x395, 0x3a3, 0x3a5, 0x3a3, 0x20, 0x03a7, 0x3a1, 0x399, 0x3a3, 0x3a4,
+ 0x39f, 0x3a3, 0 };
+ // "IESUS CHRISTOS"
+
+ static const UChar lowercaseGreek[] =
+ { 0x3b9, 0x3b5, 0x3c3, 0x3c5, 0x3c2, 0x20, 0x03c7, 0x3c1, 0x3b9, 0x3c3, 0x3c4,
+ 0x3bf, 0x3c2, 0 };
+ // "iesus christos"
+
+ static const UChar lowercaseTurkish[] =
+ { 0x69, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x2c, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x63, 0x6f,
+ 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x74, 0x0131, 0x6e, 0x6f, 0x70, 0x6c, 0x65, 0x21, 0 };
+
+ static const UChar uppercaseTurkish[] =
+ { 0x54, 0x4f, 0x50, 0x4b, 0x41, 0x50, 0x49, 0x20, 0x50, 0x41, 0x4c, 0x41, 0x43, 0x45, 0x2c, 0x20,
+ 0x0130, 0x53, 0x54, 0x41, 0x4e, 0x42, 0x55, 0x4c, 0 };
+
+ UnicodeString expectedResult;
+ UnicodeString test3;
+
+ test3 += (UChar32)0x0130;
+ test3 += "STANBUL, NOT CONSTANTINOPLE!";
+
+ UnicodeString test4(test3);
+ test4.toLower(Locale(""));
+ expectedResult = UnicodeString("i\\u0307stanbul, not constantinople!", "").unescape();
+ if (test4 != expectedResult)
+ errln("1. toLower failed: expected \"" + expectedResult + "\", got \"" + test4 + "\".");
+
+ test4 = test3;
+ test4.toLower(Locale("tr", "TR"));
+ expectedResult = lowercaseTurkish;
+ if (test4 != expectedResult)
+ errln("2. toLower failed: expected \"" + expectedResult + "\", got \"" + test4 + "\".");
+
+ test3 = "topkap";
+ test3 += (UChar32)0x0131;
+ test3 += " palace, istanbul";
+ test4 = test3;
+
+ test4.toUpper(Locale(""));
+ expectedResult = "TOPKAPI PALACE, ISTANBUL";
+ if (test4 != expectedResult)
+ errln("toUpper failed: expected \"" + expectedResult + "\", got \"" + test4 + "\".");
+
+ test4 = test3;
+ test4.toUpper(Locale("tr", "TR"));
+ expectedResult = uppercaseTurkish;
+ if (test4 != expectedResult)
+ errln("toUpper failed: expected \"" + expectedResult + "\", got \"" + test4 + "\".");
+
+ test3 = CharsToUnicodeString("S\\u00FC\\u00DFmayrstra\\u00DFe");
+
+ test3.toUpper(Locale("de", "DE"));
+ expectedResult = CharsToUnicodeString("S\\u00DCSSMAYRSTRASSE");
+ if (test3 != expectedResult)
+ errln("toUpper failed: expected \"" + expectedResult + "\", got \"" + test3 + "\".");
+
+ test4.replace(0, test4.length(), uppercaseGreek);
+
+ test4.toLower(Locale("el", "GR"));
+ expectedResult = lowercaseGreek;
+ if (test4 != expectedResult)
+ errln("toLower failed: expected \"" + expectedResult + "\", got \"" + test4 + "\".");
+
+ test4.replace(0, test4.length(), lowercaseGreek);
+
+ test4.toUpper();
+ expectedResult = uppercaseGreek;
+ if (test4 != expectedResult)
+ errln("toUpper failed: expected \"" + expectedResult + "\", got \"" + test4 + "\".");
+
+ // more string case mapping tests with the new implementation
+ {
+ static const UChar
+
+ beforeLower[]= { 0x61, 0x42, 0x49, 0x3a3, 0xdf, 0x3a3, 0x2f, 0xd93f, 0xdfff },
+ lowerRoot[]= { 0x61, 0x62, 0x69, 0x3c3, 0xdf, 0x3c2, 0x2f, 0xd93f, 0xdfff },
+ lowerTurkish[]={ 0x61, 0x62, 0x131, 0x3c3, 0xdf, 0x3c2, 0x2f, 0xd93f, 0xdfff },
+
+ beforeUpper[]= { 0x61, 0x42, 0x69, 0x3c2, 0xdf, 0x3c3, 0x2f, 0xfb03, 0xfb03, 0xfb03, 0xd93f, 0xdfff },
+ upperRoot[]= { 0x41, 0x42, 0x49, 0x3a3, 0x53, 0x53, 0x3a3, 0x2f, 0x46, 0x46, 0x49, 0x46, 0x46, 0x49, 0x46, 0x46, 0x49, 0xd93f, 0xdfff },
+ upperTurkish[]={ 0x41, 0x42, 0x130, 0x3a3, 0x53, 0x53, 0x3a3, 0x2f, 0x46, 0x46, 0x49, 0x46, 0x46, 0x49, 0x46, 0x46, 0x49, 0xd93f, 0xdfff },
+
+ beforeMiniUpper[]= { 0xdf, 0x61 },
+ miniUpper[]= { 0x53, 0x53, 0x41 };
+
+ UnicodeString s;
+
+ /* lowercase with root locale */
+ s=UnicodeString(FALSE, beforeLower, (int32_t)(sizeof(beforeLower)/U_SIZEOF_UCHAR));
+ s.toLower("");
+ if( s.length()!=(sizeof(lowerRoot)/U_SIZEOF_UCHAR) ||
+ s!=UnicodeString(FALSE, lowerRoot, s.length())
+ ) {
+ errln("error in toLower(root locale)=\"" + s + "\" expected \"" + UnicodeString(FALSE, lowerRoot, (int32_t)(sizeof(lowerRoot)/U_SIZEOF_UCHAR)) + "\"");
+ }
+
+ /* lowercase with turkish locale */
+ s=UnicodeString(FALSE, beforeLower, (int32_t)(sizeof(beforeLower)/U_SIZEOF_UCHAR));
+ s.setCharAt(0, beforeLower[0]).toLower(Locale("tr"));
+ if( s.length()!=(sizeof(lowerTurkish)/U_SIZEOF_UCHAR) ||
+ s!=UnicodeString(FALSE, lowerTurkish, s.length())
+ ) {
+ errln("error in toLower(turkish locale)=\"" + s + "\" expected \"" + UnicodeString(FALSE, lowerTurkish, (int32_t)(sizeof(lowerTurkish)/U_SIZEOF_UCHAR)) + "\"");
+ }
+
+ /* uppercase with root locale */
+ s=UnicodeString(FALSE, beforeUpper, (int32_t)(sizeof(beforeUpper)/U_SIZEOF_UCHAR));
+ s.setCharAt(0, beforeUpper[0]).toUpper(Locale(""));
+ if( s.length()!=(sizeof(upperRoot)/U_SIZEOF_UCHAR) ||
+ s!=UnicodeString(FALSE, upperRoot, s.length())
+ ) {
+ errln("error in toUpper(root locale)=\"" + s + "\" expected \"" + UnicodeString(FALSE, upperRoot, (int32_t)(sizeof(upperRoot)/U_SIZEOF_UCHAR)) + "\"");
+ }
+
+ /* uppercase with turkish locale */
+ s=UnicodeString(FALSE, beforeUpper, (int32_t)(sizeof(beforeUpper)/U_SIZEOF_UCHAR));
+ s.toUpper(Locale("tr"));
+ if( s.length()!=(sizeof(upperTurkish)/U_SIZEOF_UCHAR) ||
+ s!=UnicodeString(FALSE, upperTurkish, s.length())
+ ) {
+ errln("error in toUpper(turkish locale)=\"" + s + "\" expected \"" + UnicodeString(FALSE, upperTurkish, (int32_t)(sizeof(upperTurkish)/U_SIZEOF_UCHAR)) + "\"");
+ }
+
+ /* uppercase a short string with root locale */
+ s=UnicodeString(FALSE, beforeMiniUpper, (int32_t)(sizeof(beforeMiniUpper)/U_SIZEOF_UCHAR));
+ s.setCharAt(0, beforeMiniUpper[0]).toUpper("");
+ if( s.length()!=(sizeof(miniUpper)/U_SIZEOF_UCHAR) ||
+ s!=UnicodeString(FALSE, miniUpper, s.length())
+ ) {
+ errln("error in toUpper(root locale)=\"" + s + "\" expected \"" + UnicodeString(FALSE, miniUpper, (int32_t)(sizeof(miniUpper)/U_SIZEOF_UCHAR)) + "\"");
+ }
+ }
+
+ // test some supplementary characters (>= Unicode 3.1)
+ {
+ UnicodeString t;
+
+ UnicodeString
+ deseretInput=UnicodeString("\\U0001043C\\U00010414", "").unescape(),
+ deseretLower=UnicodeString("\\U0001043C\\U0001043C", "").unescape(),
+ deseretUpper=UnicodeString("\\U00010414\\U00010414", "").unescape();
+ (t=deseretInput).toLower();
+ if(t!=deseretLower) {
+ errln("error lowercasing Deseret (plane 1) characters");
+ }
+ (t=deseretInput).toUpper();
+ if(t!=deseretUpper) {
+ errln("error uppercasing Deseret (plane 1) characters");
+ }
+ }
+
+ // test some more cases that looked like problems
+ {
+ UnicodeString t;
+
+ UnicodeString
+ ljInput=UnicodeString("ab'cD \\uFB00i\\u0131I\\u0130 \\u01C7\\u01C8\\u01C9 \\U0001043C\\U00010414", "").unescape(),
+ ljLower=UnicodeString("ab'cd \\uFB00i\\u0131ii\\u0307 \\u01C9\\u01C9\\u01C9 \\U0001043C\\U0001043C", "").unescape(),
+ ljUpper=UnicodeString("AB'CD FFIII\\u0130 \\u01C7\\u01C7\\u01C7 \\U00010414\\U00010414", "").unescape();
+ (t=ljInput).toLower("en");
+ if(t!=ljLower) {
+ errln("error lowercasing LJ characters");
+ }
+ (t=ljInput).toUpper("en");
+ if(t!=ljUpper) {
+ errln("error uppercasing LJ characters");
+ }
+ }
+
+#if !UCONFIG_NO_NORMALIZATION
+ // some context-sensitive casing depends on normalization data being present
+
+ // Unicode 3.1.1 SpecialCasing tests
+ {
+ UnicodeString t;
+
+ // sigmas preceded and/or followed by cased letters
+ UnicodeString
+ sigmas=UnicodeString("i\\u0307\\u03a3\\u0308j \\u0307\\u03a3\\u0308j i\\u00ad\\u03a3\\u0308 \\u0307\\u03a3\\u0308 ", "").unescape(),
+ sigmasLower=UnicodeString("i\\u0307\\u03c3\\u0308j \\u0307\\u03c3\\u0308j i\\u00ad\\u03c2\\u0308 \\u0307\\u03c3\\u0308 ", "").unescape(),
+ sigmasUpper=UnicodeString("I\\u0307\\u03a3\\u0308J \\u0307\\u03a3\\u0308J I\\u00ad\\u03a3\\u0308 \\u0307\\u03a3\\u0308 ", "").unescape();
+
+ (t=sigmas).toLower();
+ if(t!=sigmasLower) {
+ errln("error in sigmas.toLower()=\"" + t + "\" expected \"" + sigmasLower + "\"");
+ }
+
+ (t=sigmas).toUpper(Locale(""));
+ if(t!=sigmasUpper) {
+ errln("error in sigmas.toUpper()=\"" + t + "\" expected \"" + sigmasUpper + "\"");
+ }
+
+ // turkish & azerbaijani dotless i & dotted I
+ // remove dot above if there was a capital I before and there are no more accents above
+ UnicodeString
+ dots=UnicodeString("I \\u0130 I\\u0307 I\\u0327\\u0307 I\\u0301\\u0307 I\\u0327\\u0307\\u0301", "").unescape(),
+ dotsTurkish=UnicodeString("\\u0131 i i i\\u0327 \\u0131\\u0301\\u0307 i\\u0327\\u0301", "").unescape(),
+ dotsDefault=UnicodeString("i i\\u0307 i\\u0307 i\\u0327\\u0307 i\\u0301\\u0307 i\\u0327\\u0307\\u0301", "").unescape();
+
+ (t=dots).toLower("tr");
+ if(t!=dotsTurkish) {
+ errln("error in dots.toLower(tr)=\"" + t + "\" expected \"" + dotsTurkish + "\"");
+ }
+
+ (t=dots).toLower("de");
+ if(t!=dotsDefault) {
+ errln("error in dots.toLower(de)=\"" + t + "\" expected \"" + dotsDefault + "\"");
+ }
+ }
+
+ // more Unicode 3.1.1 tests
+ {
+ UnicodeString t;
+
+ // lithuanian dot above in uppercasing
+ UnicodeString
+ dots=UnicodeString("a\\u0307 \\u0307 i\\u0307 j\\u0327\\u0307 j\\u0301\\u0307", "").unescape(),
+ dotsLithuanian=UnicodeString("A\\u0307 \\u0307 I J\\u0327 J\\u0301\\u0307", "").unescape(),
+ dotsDefault=UnicodeString("A\\u0307 \\u0307 I\\u0307 J\\u0327\\u0307 J\\u0301\\u0307", "").unescape();
+
+ (t=dots).toUpper("lt");
+ if(t!=dotsLithuanian) {
+ errln("error in dots.toUpper(lt)=\"" + t + "\" expected \"" + dotsLithuanian + "\"");
+ }
+
+ (t=dots).toUpper("de");
+ if(t!=dotsDefault) {
+ errln("error in dots.toUpper(de)=\"" + t + "\" expected \"" + dotsDefault + "\"");
+ }
+
+ // lithuanian adds dot above to i in lowercasing if there are more above accents
+ UnicodeString
+ i=UnicodeString("I I\\u0301 J J\\u0301 \\u012e \\u012e\\u0301 \\u00cc\\u00cd\\u0128", "").unescape(),
+ iLithuanian=UnicodeString("i i\\u0307\\u0301 j j\\u0307\\u0301 \\u012f \\u012f\\u0307\\u0301 i\\u0307\\u0300i\\u0307\\u0301i\\u0307\\u0303", "").unescape(),
+ iDefault=UnicodeString("i i\\u0301 j j\\u0301 \\u012f \\u012f\\u0301 \\u00ec\\u00ed\\u0129", "").unescape();
+
+ (t=i).toLower("lt");
+ if(t!=iLithuanian) {
+ errln("error in i.toLower(lt)=\"" + t + "\" expected \"" + iLithuanian + "\"");
+ }
+
+ (t=i).toLower("de");
+ if(t!=iDefault) {
+ errln("error in i.toLower(de)=\"" + t + "\" expected \"" + iDefault + "\"");
+ }
+ }
+
+#endif
+
+ // test case folding
+ {
+ UnicodeString
+ s=UnicodeString("A\\u00df\\u00b5\\ufb03\\U0001040c\\u0130\\u0131", "").unescape(),
+ f=UnicodeString("ass\\u03bcffi\\U00010434i\\u0307\\u0131", "").unescape(),
+ g=UnicodeString("ass\\u03bcffi\\U00010434i\\u0131", "").unescape(),
+ t;
+
+ (t=s).foldCase();
+ if(f!=t) {
+ errln("error in foldCase(\"" + s + "\", default)=\"" + t + "\" but expected \"" + f + "\"");
+ }
+
+ // alternate handling for dotted I/dotless i (U+0130, U+0131)
+ (t=s).foldCase(U_FOLD_CASE_EXCLUDE_SPECIAL_I);
+ if(g!=t) {
+ errln("error in foldCase(\"" + s + "\", U_FOLD_CASE_EXCLUDE_SPECIAL_I)=\"" + t + "\" but expected \"" + g + "\"");
+ }
+ }
+}
+
+// data-driven case mapping tests ------------------------------------------ ***
+
+enum {
+ TEST_LOWER,
+ TEST_UPPER,
+ TEST_TITLE,
+ TEST_FOLD,
+ TEST_COUNT
+};
+
+// names of TestData children in casing.txt
+static const char *const dataNames[TEST_COUNT+1]={
+ "lowercasing",
+ "uppercasing",
+ "titlecasing",
+ "casefolding",
+ ""
+};
+
+void
+StringCaseTest::TestCasingImpl(const UnicodeString &input,
+ const UnicodeString &output,
+ int32_t whichCase,
+ void *iter, const char *localeID, uint32_t options) {
+ // UnicodeString
+ UnicodeString result;
+ const char *name;
+ Locale locale(localeID);
+
+ result=input;
+ switch(whichCase) {
+ case TEST_LOWER:
+ name="toLower";
+ result.toLower(locale);
+ break;
+ case TEST_UPPER:
+ name="toUpper";
+ result.toUpper(locale);
+ break;
+#if !UCONFIG_NO_BREAK_ITERATION
+ case TEST_TITLE:
+ name="toTitle";
+ result.toTitle((BreakIterator *)iter, locale, options);
+ break;
+#endif
+ case TEST_FOLD:
+ name="foldCase";
+ result.foldCase(options);
+ break;
+ default:
+ name="";
+ break; // won't happen
+ }
+ if(result!=output) {
+ errln("error: UnicodeString.%s() got a wrong result for a test case from casing.res", name);
+ }
+#if !UCONFIG_NO_BREAK_ITERATION
+ if(whichCase==TEST_TITLE && options==0) {
+ result=input;
+ result.toTitle((BreakIterator *)iter, locale);
+ if(result!=output) {
+ errln("error: UnicodeString.toTitle(options=0) got a wrong result for a test case from casing.res");
+ }
+ }
+#endif
+
+ // UTF-8
+ char utf8In[100], utf8Out[100];
+ int32_t utf8InLength, utf8OutLength, resultLength;
+ UChar *buffer;
+
+ UCaseMap *csm;
+ UErrorCode errorCode;
+
+ errorCode=U_ZERO_ERROR;
+ csm=ucasemap_open(localeID, options, &errorCode);
+#if !UCONFIG_NO_BREAK_ITERATION
+ if(iter!=NULL) {
+ // Clone the break iterator so that the UCaseMap can safely adopt it.
+ int32_t size=1; // Not 0 because that only gives preflighting.
+ UBreakIterator *clone=ubrk_safeClone((UBreakIterator *)iter, NULL, &size, &errorCode);
+ ucasemap_setBreakIterator(csm, clone, &errorCode);
+ }
+#endif
+
+ u_strToUTF8(utf8In, (int32_t)sizeof(utf8In), &utf8InLength, input.getBuffer(), input.length(), &errorCode);
+ switch(whichCase) {
+ case TEST_LOWER:
+ name="ucasemap_utf8ToLower";
+ utf8OutLength=ucasemap_utf8ToLower(csm,
+ utf8Out, (int32_t)sizeof(utf8Out),
+ utf8In, utf8InLength, &errorCode);
+ break;
+ case TEST_UPPER:
+ name="ucasemap_utf8ToUpper";
+ utf8OutLength=ucasemap_utf8ToUpper(csm,
+ utf8Out, (int32_t)sizeof(utf8Out),
+ utf8In, utf8InLength, &errorCode);
+ break;
+#if !UCONFIG_NO_BREAK_ITERATION
+ case TEST_TITLE:
+ name="ucasemap_utf8ToTitle";
+ utf8OutLength=ucasemap_utf8ToTitle(csm,
+ utf8Out, (int32_t)sizeof(utf8Out),
+ utf8In, utf8InLength, &errorCode);
+ break;
+#endif
+ case TEST_FOLD:
+ name="ucasemap_utf8FoldCase";
+ utf8OutLength=ucasemap_utf8FoldCase(csm,
+ utf8Out, (int32_t)sizeof(utf8Out),
+ utf8In, utf8InLength, &errorCode);
+ break;
+ default:
+ name="";
+ utf8OutLength=0;
+ break; // won't happen
+ }
+ buffer=result.getBuffer(utf8OutLength);
+ u_strFromUTF8(buffer, result.getCapacity(), &resultLength, utf8Out, utf8OutLength, &errorCode);
+ result.releaseBuffer(U_SUCCESS(errorCode) ? resultLength : 0);
+
+ if(U_FAILURE(errorCode)) {
+ errln("error: %s() got an error for a test case from casing.res - %s", name, u_errorName(errorCode));
+ } else if(result!=output) {
+ errln("error: %s() got a wrong result for a test case from casing.res", name);
+ }
+ ucasemap_close(csm);
+}
+
+void
+StringCaseTest::TestCasing() {
+ UErrorCode status = U_ZERO_ERROR;
+ void *iter;
+ char cLocaleID[100];
+ UnicodeString locale, input, output, optionsString, result;
+ uint32_t options;
+ int32_t whichCase, type;
+ TestDataModule *driver = TestDataModule::getTestDataModule("casing", *this, status);
+ if(U_SUCCESS(status)) {
+ for(whichCase=0; whichCase<TEST_COUNT; ++whichCase) {
+#if UCONFIG_NO_BREAK_ITERATION
+ if(whichCase==TEST_TITLE) {
+ continue;
+ }
+#endif
+ TestData *casingTest = driver->createTestData(dataNames[whichCase], status);
+ if(U_FAILURE(status)) {
+ errln("TestCasing failed to createTestData(%s) - %s", dataNames[whichCase], u_errorName(status));
+ break;
+ }
+ const DataMap *myCase = NULL;
+ while(casingTest->nextCase(myCase, status)) {
+ input = myCase->getString("Input", status);
+ output = myCase->getString("Output", status);
+
+ if(whichCase!=TEST_FOLD) {
+ locale = myCase->getString("Locale", status);
+ }
+ locale.extract(0, 0x7fffffff, cLocaleID, sizeof(cLocaleID), "");
+
+ iter=NULL;
+#if !UCONFIG_NO_BREAK_ITERATION
+ if(whichCase==TEST_TITLE) {
+ type = myCase->getInt("Type", status);
+ if(type>=0) {
+ iter=ubrk_open((UBreakIteratorType)type, cLocaleID, NULL, 0, &status);
+ } else if(type==-2) {
+ // Open a trivial break iterator that only delivers { 0, length }
+ // or even just { 0 } as boundaries.
+ static const UChar rules[] = { 0x2e, 0x2a, 0x3b }; // ".*;"
+ UParseError parseError;
+ iter=ubrk_openRules(rules, LENGTHOF(rules), NULL, 0, &parseError, &status);
+ }
+ }
+#endif
+ options = 0;
+ if(whichCase==TEST_TITLE || whichCase==TEST_FOLD) {
+ optionsString = myCase->getString("Options", status);
+ if(optionsString.indexOf((UChar)0x54)>=0) { // T
+ options|=U_FOLD_CASE_EXCLUDE_SPECIAL_I;
+ }
+ if(optionsString.indexOf((UChar)0x4c)>=0) { // L
+ options|=U_TITLECASE_NO_LOWERCASE;
+ }
+ if(optionsString.indexOf((UChar)0x41)>=0) { // A
+ options|=U_TITLECASE_NO_BREAK_ADJUSTMENT;
+ }
+ }
+
+ if(U_FAILURE(status)) {
+ errln("error: TestCasing() setup failed for %s test case from casing.res: %s", dataNames[whichCase], u_errorName(status));
+ status = U_ZERO_ERROR;
+ } else {
+ TestCasingImpl(input, output, whichCase, iter, cLocaleID, options);
+ }
+
+#if !UCONFIG_NO_BREAK_ITERATION
+ if(iter!=NULL) {
+ ubrk_close(iter);
+ }
+#endif
+ }
+ delete casingTest;
+ }
+ }
+ delete driver;
+
+#if !UCONFIG_NO_BREAK_ITERATION
+ // more tests for API coverage
+ status=U_ZERO_ERROR;
+ input=UNICODE_STRING_SIMPLE("sTrA\\u00dfE").unescape();
+ (result=input).toTitle(NULL);
+ if(result!=UNICODE_STRING_SIMPLE("Stra\\u00dfe").unescape()) {
+ errln("UnicodeString::toTitle(NULL) failed");
+ }
+#endif
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/strtest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/strtest.cpp
new file mode 100644
index 00000000000..97620c921ff
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/strtest.cpp
@@ -0,0 +1,192 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/* file name: strtest.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 1999nov22
+* created by: Markus W. Scherer
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/putil.h"
+#include "intltest.h"
+#include "strtest.h"
+#include "unicode/ustring.h"
+
+#if defined(U_WINDOWS) && defined(_MSC_VER)
+#include <vector>
+using namespace std;
+#endif
+
+StringTest::~StringTest() {}
+
+void StringTest::TestEndian(void) {
+ union {
+ uint8_t byte;
+ uint16_t word;
+ } u;
+ u.word=0x0100;
+ if(U_IS_BIG_ENDIAN!=u.byte) {
+ errln("TestEndian: U_IS_BIG_ENDIAN needs to be fixed in platform.h");
+ }
+}
+
+void StringTest::TestSizeofTypes(void) {
+ if(U_SIZEOF_WCHAR_T!=sizeof(wchar_t)) {
+ errln("TestSizeofWCharT: U_SIZEOF_WCHAR_T!=sizeof(wchar_t) - U_SIZEOF_WCHAR_T needs to be fixed in platform.h");
+ }
+#ifdef U_INT64_T_UNAVAILABLE
+ errln("int64_t and uint64_t are undefined.");
+#else
+ if(8!=sizeof(int64_t)) {
+ errln("TestSizeofTypes: 8!=sizeof(int64_t) - int64_t needs to be fixed in platform.h");
+ }
+ if(8!=sizeof(uint64_t)) {
+ errln("TestSizeofTypes: 8!=sizeof(uint64_t) - uint64_t needs to be fixed in platform.h");
+ }
+#endif
+ if(8!=sizeof(double)) {
+ errln("8!=sizeof(double) - putil.c code may not work");
+ }
+ if(4!=sizeof(int32_t)) {
+ errln("4!=sizeof(int32_t)");
+ }
+ if(4!=sizeof(uint32_t)) {
+ errln("4!=sizeof(uint32_t)");
+ }
+ if(2!=sizeof(int16_t)) {
+ errln("2!=sizeof(int16_t)");
+ }
+ if(2!=sizeof(uint16_t)) {
+ errln("2!=sizeof(uint16_t)");
+ }
+ if(2!=sizeof(UChar)) {
+ errln("2!=sizeof(UChar)");
+ }
+ if(1!=sizeof(int8_t)) {
+ errln("1!=sizeof(int8_t)");
+ }
+ if(1!=sizeof(uint8_t)) {
+ errln("1!=sizeof(uint8_t)");
+ }
+ if(1!=sizeof(UBool)) {
+ errln("1!=sizeof(UBool)");
+ }
+}
+
+void StringTest::TestCharsetFamily(void) {
+ unsigned char c='A';
+ if( U_CHARSET_FAMILY==U_ASCII_FAMILY && c!=0x41 ||
+ U_CHARSET_FAMILY==U_EBCDIC_FAMILY && c!=0xc1
+ ) {
+ errln("TestCharsetFamily: U_CHARSET_FAMILY needs to be fixed in platform.h");
+ }
+}
+
+U_STRING_DECL(ustringVar, "aZ0 -", 5);
+
+void StringTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) {
+ if(exec) {
+ logln("TestSuite Character and String Test: ");
+ }
+ switch(index) {
+ case 0:
+ name="TestEndian";
+ if(exec) {
+ TestEndian();
+ }
+ break;
+ case 1:
+ name="TestSizeofTypes";
+ if(exec) {
+ TestSizeofTypes();
+ }
+ break;
+ case 2:
+ name="TestCharsetFamily";
+ if(exec) {
+ TestCharsetFamily();
+ }
+ break;
+ case 3:
+ name="Test_U_STRING";
+ if(exec) {
+ U_STRING_INIT(ustringVar, "aZ0 -", 5);
+ if( sizeof(ustringVar)/sizeof(*ustringVar)!=6 ||
+ ustringVar[0]!=0x61 ||
+ ustringVar[1]!=0x5a ||
+ ustringVar[2]!=0x30 ||
+ ustringVar[3]!=0x20 ||
+ ustringVar[4]!=0x2d ||
+ ustringVar[5]!=0
+ ) {
+ errln("Test_U_STRING: U_STRING_DECL with U_STRING_INIT does not work right! "
+ "See putil.h and utypes.h with platform.h.");
+ }
+ }
+ break;
+ case 4:
+ name="Test_UNICODE_STRING";
+ if(exec) {
+ UnicodeString ustringVar=UNICODE_STRING("aZ0 -", 5);
+ if( ustringVar.length()!=5 ||
+ ustringVar[0]!=0x61 ||
+ ustringVar[1]!=0x5a ||
+ ustringVar[2]!=0x30 ||
+ ustringVar[3]!=0x20 ||
+ ustringVar[4]!=0x2d
+ ) {
+ errln("Test_UNICODE_STRING: UNICODE_STRING does not work right! "
+ "See unistr.h and utypes.h with platform.h.");
+ }
+ }
+ break;
+ case 5:
+ name="Test_UNICODE_STRING_SIMPLE";
+ if(exec) {
+ UnicodeString ustringVar=UNICODE_STRING_SIMPLE("aZ0 -");
+ if( ustringVar.length()!=5 ||
+ ustringVar[0]!=0x61 ||
+ ustringVar[1]!=0x5a ||
+ ustringVar[2]!=0x30 ||
+ ustringVar[3]!=0x20 ||
+ ustringVar[4]!=0x2d
+ ) {
+ errln("Test_UNICODE_STRING_SIMPLE: UNICODE_STRING_SIMPLE does not work right! "
+ "See unistr.h and utypes.h with platform.h.");
+ }
+ }
+ break;
+ case 6:
+ name="Test_UTF8_COUNT_TRAIL_BYTES";
+ if(exec) {
+ if(UTF8_COUNT_TRAIL_BYTES(0x7F) != 0
+ || UTF8_COUNT_TRAIL_BYTES(0xC0) != 1
+ || UTF8_COUNT_TRAIL_BYTES(0xE0) != 2
+ || UTF8_COUNT_TRAIL_BYTES(0xF0) != 3)
+ {
+ errln("Test_UTF8_COUNT_TRAIL_BYTES: UTF8_COUNT_TRAIL_BYTES does not work right! "
+ "See utf8.h.");
+ }
+ }
+ break;
+ case 7:
+ name="TestSTLCompatibility";
+ if(exec) {
+#if defined(U_WINDOWS) && defined(_MSC_VER)
+ /* Just make sure that it compiles with STL's placement new usage. */
+ vector<UnicodeString> myvect;
+ myvect.push_back(UnicodeString("blah"));
+#endif
+ }
+ break;
+ default:
+ name="";
+ break;
+ }
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/strtest.h b/Build/source/libs/icu/icu-xetex/test/intltest/strtest.h
new file mode 100644
index 00000000000..5f342e10980
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/strtest.h
@@ -0,0 +1,38 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2004, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/* file name: strtest.h
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 1999nov22
+* created by: Markus W. Scherer
+*/
+
+/*
+ * Test character- and string- related settings in utypes.h,
+ * macros in putil.h, and constructors in unistr.h .
+ */
+
+#ifndef __STRTEST_H__
+#define __STRTEST_H__
+
+#include "intltest.h"
+
+class StringTest : public IntlTest {
+public:
+ StringTest() {}
+ virtual ~StringTest();
+
+ void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=NULL);
+
+private:
+ void TestEndian(void);
+ void TestSizeofTypes(void);
+ void TestCharsetFamily(void);
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/svccoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/svccoll.cpp
new file mode 100644
index 00000000000..4c1db47406b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/svccoll.cpp
@@ -0,0 +1,586 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2003-2006, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ *******************************************************************************
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "svccoll.h"
+#include "unicode/coll.h"
+#include "unicode/strenum.h"
+#include "hash.h"
+#include "uassert.h"
+
+#include "ucol_imp.h" // internal api needed to test ucollator equality
+#include "cstring.h" // internal api used to compare locale strings
+
+void CollationServiceTest::runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par */)
+{
+ if (exec) logln("TestSuite CollationServiceTest: ");
+ switch (index) {
+ TESTCASE(0, TestRegister);
+ TESTCASE(1, TestRegisterFactory);
+ TESTCASE(2, TestSeparateTree);
+ default: name = ""; break;
+ }
+}
+
+void CollationServiceTest::TestRegister()
+{
+#if !UCONFIG_NO_SERVICE
+ // register a singleton
+ const Locale& FR = Locale::getFrance();
+ const Locale& US = Locale::getUS();
+ const Locale US_FOO("en", "US", "FOO");
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ Collator* frcol = Collator::createInstance(FR, status);
+ Collator* uscol = Collator::createInstance(US, status);
+ if(U_FAILURE(status)) {
+ errln("Failed to create collators with %s", u_errorName(status));
+ delete frcol;
+ delete uscol;
+ return;
+ }
+
+ { // try override en_US collator
+ URegistryKey key = Collator::registerInstance(frcol, US, status);
+
+ Collator* ncol = Collator::createInstance(US_FOO, status);
+ if (*frcol != *ncol) {
+ errln("register of french collator for en_US failed on request for en_US_FOO");
+ }
+ // ensure original collator's params not touched
+ Locale loc = frcol->getLocale(ULOC_REQUESTED_LOCALE, status);
+ if (loc != FR) {
+ errln(UnicodeString("fr collator's requested locale changed to ") + loc.getName());
+ }
+ loc = frcol->getLocale(ULOC_VALID_LOCALE, status);
+ if (loc != FR) {
+ errln(UnicodeString("fr collator's valid locale changed to ") + loc.getName());
+ }
+
+ loc = ncol->getLocale(ULOC_REQUESTED_LOCALE, status);
+ if (loc != US_FOO) {
+ errln(UnicodeString("requested locale for en_US_FOO is not en_US_FOO but ") + loc.getName());
+ }
+ loc = ncol->getLocale(ULOC_VALID_LOCALE, status);
+ if (loc != US) {
+ errln(UnicodeString("valid locale for en_US_FOO is not en_US but ") + loc.getName());
+ }
+ loc = ncol->getLocale(ULOC_ACTUAL_LOCALE, status);
+ if (loc != US) {
+ errln(UnicodeString("actual locale for en_US_FOO is not en_US but ") + loc.getName());
+ }
+ delete ncol; ncol = NULL;
+
+ if (!Collator::unregister(key, status)) {
+ errln("failed to unregister french collator");
+ }
+ // !!! frcol pointer is now invalid !!!
+
+ ncol = Collator::createInstance(US, status);
+ if (*uscol != *ncol) {
+ errln("collator after unregister does not match original");
+ }
+ delete ncol; ncol = NULL;
+ }
+
+ // recreate frcol
+ frcol = Collator::createInstance(FR, status);
+
+ UCollator* frFR = ucol_open("fr_FR", &status);
+
+ { // try create collator for new locale
+ Locale fu_FU_FOO("fu", "FU", "FOO");
+ Locale fu_FU("fu", "FU", "");
+
+ Collator* fucol = Collator::createInstance(fu_FU, status);
+ URegistryKey key = Collator::registerInstance(frcol, fu_FU, status);
+ Collator* ncol = Collator::createInstance(fu_FU_FOO, status);
+ if (*frcol != *ncol) {
+ errln("register of fr collator for fu_FU failed");
+ }
+
+ UnicodeString locName = fu_FU.getName();
+ StringEnumeration* localeEnum = Collator::getAvailableLocales();
+ UBool found = FALSE;
+ const UnicodeString* locStr, *ls2;
+ for (locStr = localeEnum->snext(status);
+ !found && locStr != NULL;
+ locStr = localeEnum->snext(status)) {
+ //
+ if (locName == *locStr) {
+ found = TRUE;
+ }
+ }
+
+ StringEnumeration *le2 = NULL;
+ localeEnum->reset(status);
+ int32_t i, count;
+ count = localeEnum->count(status);
+ for(i = 0; i < count; ++i) {
+ if(i == count / 2) {
+ le2 = localeEnum->clone();
+ if(le2 == NULL || count != le2->count(status)) {
+ errln("ServiceEnumeration.clone() failed");
+ break;
+ }
+ }
+ if(i >= count / 2) {
+ locStr = localeEnum->snext(status);
+ ls2 = le2->snext(status);
+ if(*locStr != *ls2) {
+ errln("ServiceEnumeration.clone() failed for item %d", i);
+ }
+ } else {
+ localeEnum->snext(status);
+ }
+ }
+
+ delete localeEnum;
+ delete le2;
+
+ if (!found) {
+ errln("new locale fu_FU not reported as supported locale");
+ }
+
+ UnicodeString displayName;
+ Collator::getDisplayName(fu_FU, displayName);
+ if (displayName != "fu (FU)") {
+ errln(UnicodeString("found ") + displayName + " for fu_FU");
+ }
+
+ Collator::getDisplayName(fu_FU, fu_FU, displayName);
+ if (displayName != "fu (FU)") {
+ errln(UnicodeString("found ") + displayName + " for fu_FU");
+ }
+
+ // test ucol_open
+ UCollator* fufu = ucol_open("fu_FU_FOO", &status);
+ if (!fufu) {
+ errln("could not open fu_FU_FOO with ucol_open");
+ } else {
+ if (!ucol_equals(fufu, frFR)) {
+ errln("collator fufu != collator frFR");
+ }
+ }
+
+ if (!Collator::unregister(key, status)) {
+ errln("failed to unregister french collator");
+ }
+ // !!! note frcoll invalid again, but we're no longer using it
+
+ // other collators should still work ok
+ Locale nloc = ncol->getLocale(ULOC_VALID_LOCALE, status);
+ if (nloc != fu_FU) {
+ errln(UnicodeString("asked for nloc valid locale after close and got") + nloc.getName());
+ }
+ delete ncol; ncol = NULL;
+
+ if (fufu) {
+ const char* nlocstr = ucol_getLocale(fufu, ULOC_VALID_LOCALE, &status);
+ if (uprv_strcmp(nlocstr, "fu_FU") != 0) {
+ errln(UnicodeString("asked for uloc valid locale after close and got ") + nlocstr);
+ }
+ ucol_close(fufu);
+ }
+ ucol_close(frFR);
+
+ ncol = Collator::createInstance(fu_FU, status);
+ if (*fucol != *ncol) {
+ errln("collator after unregister does not match original fu_FU");
+ }
+ delete uscol; uscol = NULL;
+ delete ncol; ncol = NULL;
+ delete fucol; fucol = NULL;
+ }
+#endif
+}
+
+// ------------------
+
+#if !UCONFIG_NO_SERVICE
+struct CollatorInfo {
+ Locale locale;
+ Collator* collator;
+ Hashtable* displayNames; // locale name -> string
+
+ CollatorInfo(const Locale& locale, Collator* collatorToAdopt, Hashtable* displayNamesToAdopt);
+ ~CollatorInfo();
+ UnicodeString& getDisplayName(const Locale& displayLocale, UnicodeString& name) const;
+};
+
+CollatorInfo::CollatorInfo(const Locale& _locale, Collator* _collator, Hashtable* _displayNames)
+ : locale(_locale)
+ , collator(_collator)
+ , displayNames(_displayNames)
+{
+}
+
+CollatorInfo::~CollatorInfo() {
+ delete collator;
+ delete displayNames;
+}
+
+UnicodeString&
+CollatorInfo::getDisplayName(const Locale& displayLocale, UnicodeString& name) const {
+ if (displayNames) {
+ UnicodeString* val = (UnicodeString*)displayNames->get(displayLocale.getName());
+ if (val) {
+ name = *val;
+ return name;
+ }
+ }
+
+ return locale.getDisplayName(displayLocale, name);
+}
+
+// ---------------
+
+class TestFactory : public CollatorFactory {
+ CollatorInfo** info;
+ int32_t count;
+ UnicodeString* ids;
+
+ const CollatorInfo* getInfo(const Locale& loc) const {
+ for (CollatorInfo** p = info; *p; ++p) {
+ if (loc == (**p).locale) {
+ return *p;
+ }
+ }
+ return NULL;
+ }
+
+public:
+ TestFactory(CollatorInfo** _info)
+ : info(_info)
+ , count(0)
+ , ids(NULL)
+ {
+ CollatorInfo** p;
+ for (p = info; *p; ++p) {}
+ count = (int32_t)(p - info);
+ }
+
+ ~TestFactory() {
+ for (CollatorInfo** p = info; *p; ++p) {
+ delete *p;
+ }
+ delete[] info;
+ delete[] ids;
+ }
+
+ virtual Collator* createCollator(const Locale& loc) {
+ const CollatorInfo* ci = getInfo(loc);
+ if (ci) {
+ return ci->collator->clone();
+ }
+ return NULL;
+ }
+
+ virtual UnicodeString& getDisplayName(const Locale& objectLocale,
+ const Locale& displayLocale,
+ UnicodeString& result)
+ {
+ const CollatorInfo* ci = getInfo(objectLocale);
+ if (ci) {
+ ci->getDisplayName(displayLocale, result);
+ } else {
+ result.setToBogus();
+ }
+ return result;
+ }
+
+ const UnicodeString* getSupportedIDs(int32_t& _count, UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ if (!ids) {
+ ids = new UnicodeString[count];
+ if (!ids) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ _count = 0;
+ return NULL;
+ }
+
+ for (int i = 0; i < count; ++i) {
+ ids[i] = info[i]->locale.getName();
+ }
+ }
+
+ _count = count;
+ return ids;
+ }
+ return NULL;
+ }
+
+ virtual inline UClassID getDynamicClassID() const {
+ return (UClassID)&gClassID;
+ }
+
+ static UClassID getStaticClassID() {
+ return (UClassID)&gClassID;
+ }
+
+private:
+ static char gClassID;
+};
+
+char TestFactory::gClassID = 0;
+#endif
+
+void CollationServiceTest::TestRegisterFactory(void)
+{
+#if !UCONFIG_NO_SERVICE
+ int32_t n1, n2, n3;
+ Locale fu_FU("fu", "FU", "");
+ Locale fu_FU_FOO("fu", "FU", "FOO");
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ Hashtable* fuFUNames = new Hashtable(FALSE, status);
+ if (!fuFUNames) {
+ errln("memory allocation error");
+ return;
+ }
+ fuFUNames->setValueDeleter(uhash_deleteUnicodeString);
+
+ fuFUNames->put(fu_FU.getName(), new UnicodeString("ze leetle bunny Fu-Fu"), status);
+ fuFUNames->put(fu_FU_FOO.getName(), new UnicodeString("zee leetel bunny Foo-Foo"), status);
+ fuFUNames->put(Locale::getDefault().getName(), new UnicodeString("little bunny Foo Foo"), status);
+
+ Collator* frcol = Collator::createInstance(Locale::getFrance(), status);
+ Collator* gecol = Collator::createInstance(Locale::getGermany(), status);
+ Collator* jpcol = Collator::createInstance(Locale::getJapan(), status);
+ if(U_FAILURE(status)) {
+ errln("Failed to create collators with %s", u_errorName(status));
+ delete frcol;
+ delete gecol;
+ delete jpcol;
+ delete fuFUNames;
+ return;
+ }
+
+ CollatorInfo** info = new CollatorInfo*[4];
+ if (!info) {
+ errln("memory allocation error");
+ return;
+ }
+
+ info[0] = new CollatorInfo(Locale::getUS(), frcol, NULL);
+ info[1] = new CollatorInfo(Locale::getFrance(), gecol, NULL);
+ info[2] = new CollatorInfo(fu_FU, jpcol, fuFUNames);
+ info[3] = NULL;
+
+ TestFactory* factory = new TestFactory(info);
+ if (!factory) {
+ errln("memory allocation error");
+ return;
+ }
+
+ Collator* uscol = Collator::createInstance(Locale::getUS(), status);
+ Collator* fucol = Collator::createInstance(fu_FU, status);
+
+ {
+ n1 = checkAvailable("before registerFactory");
+
+ URegistryKey key = Collator::registerFactory(factory, status);
+
+ n2 = checkAvailable("after registerFactory");
+ assertTrue("count after > count before", n2 > n1);
+
+ Collator* ncol = Collator::createInstance(Locale::getUS(), status);
+ if (*frcol != *ncol) {
+ errln("frcoll for en_US failed");
+ }
+ delete ncol; ncol = NULL;
+
+ ncol = Collator::createInstance(fu_FU_FOO, status);
+ if (*jpcol != *ncol) {
+ errln("jpcol for fu_FU_FOO failed");
+ }
+
+ Locale loc = ncol->getLocale(ULOC_REQUESTED_LOCALE, status);
+ if (loc != fu_FU_FOO) {
+ errln(UnicodeString("requested locale for fu_FU_FOO is not fu_FU_FOO but ") + loc.getName());
+ }
+ loc = ncol->getLocale(ULOC_VALID_LOCALE, status);
+ if (loc != fu_FU) {
+ errln(UnicodeString("valid locale for fu_FU_FOO is not fu_FU but ") + loc.getName());
+ }
+ delete ncol; ncol = NULL;
+
+ UnicodeString locName = fu_FU.getName();
+ StringEnumeration* localeEnum = Collator::getAvailableLocales();
+ UBool found = FALSE;
+ const UnicodeString* locStr;
+ for (locStr = localeEnum->snext(status);
+ !found && locStr != NULL;
+ locStr = localeEnum->snext(status))
+ {
+ if (locName == *locStr) {
+ found = TRUE;
+ }
+ }
+ delete localeEnum;
+
+ if (!found) {
+ errln("new locale fu_FU not reported as supported locale");
+ }
+
+ UnicodeString name;
+ Collator::getDisplayName(fu_FU, name);
+ if (name != "little bunny Foo Foo") {
+ errln(UnicodeString("found ") + name + " for fu_FU");
+ }
+
+ Collator::getDisplayName(fu_FU, fu_FU_FOO, name);
+ if (name != "zee leetel bunny Foo-Foo") {
+ errln(UnicodeString("found ") + name + " for fu_FU in fu_FU_FOO");
+ }
+
+ if (!Collator::unregister(key, status)) {
+ errln("failed to unregister factory");
+ }
+ // ja, fr, ge collators no longer valid
+
+ ncol = Collator::createInstance(fu_FU, status);
+ if (*fucol != *ncol) {
+ errln("collator after unregister does not match original fu_FU");
+ }
+ delete ncol;
+
+ n3 = checkAvailable("after unregister");
+ assertTrue("count after unregister == count before register", n3 == n1);
+ }
+
+ delete fucol;
+ delete uscol;
+#endif
+}
+
+/**
+ * Iterate through the given iterator, checking to see that all the strings
+ * in the expected array are present.
+ * @param expected array of strings we expect to see, or NULL
+ * @param expectedCount number of elements of expected, or 0
+ */
+int32_t CollationServiceTest::checkStringEnumeration(const char* msg,
+ StringEnumeration& iter,
+ const char** expected,
+ int32_t expectedCount) {
+ UErrorCode ec = U_ZERO_ERROR;
+ U_ASSERT(expectedCount >= 0 && expectedCount < 31); // [sic] 31 not 32
+ int32_t i = 0, idxAfterReset = 0, n = iter.count(ec);
+ assertSuccess("count", ec);
+ UnicodeString buf, buffAfterReset;
+ int32_t seenMask = 0;
+ for (;; ++i) {
+ const UnicodeString* s = iter.snext(ec);
+ if (!assertSuccess("snext", ec) || s == NULL)
+ break;
+ if (i != 0)
+ buf.append(UNICODE_STRING_SIMPLE(", "));
+ buf.append(*s);
+ // check expected list
+ for (int32_t j=0, bit=1; j<expectedCount; ++j, bit<<=1) {
+ if ((seenMask&bit)==0) {
+ UnicodeString exp(expected[j], (char*)NULL);
+ if (*s == exp) {
+ seenMask |= bit;
+ logln((UnicodeString)"Ok: \"" + exp + "\" seen");
+ }
+ }
+ }
+ }
+ // can't get pesky operator+(const US&, foo) to cooperate; use toString
+#if !UCONFIG_NO_FORMATTING
+ logln(UnicodeString() + msg + " = [" + buf + "] (" + toString(i) + ")");
+#else
+ logln(UnicodeString() + msg + " = [" + buf + "] (??? NO_FORMATTING)");
+#endif
+ assertTrue("count verified", i==n);
+ iter.reset(ec);
+ for (;; ++idxAfterReset) {
+ const UChar *s = iter.unext(NULL, ec);
+ if (!assertSuccess("unext", ec) || s == NULL)
+ break;
+ if (idxAfterReset != 0)
+ buffAfterReset.append(UNICODE_STRING_SIMPLE(", "));
+ buffAfterReset.append(s);
+ }
+ assertTrue("idxAfterReset verified", idxAfterReset==n);
+ assertTrue("buffAfterReset verified", buffAfterReset==buf);
+ // did we see all expected strings?
+ if (((1<<expectedCount)-1) != seenMask) {
+ for (int32_t j=0, bit=1; j<expectedCount; ++j, bit<<=1) {
+ if ((seenMask&bit)==0) {
+ errln((UnicodeString)"FAIL: \"" + expected[j] + "\" not seen");
+ }
+ }
+ }
+ return n;
+}
+
+/**
+ * Check the integrity of the results of Collator::getAvailableLocales().
+ * Return the number of items returned.
+ */
+#if !UCONFIG_NO_SERVICE
+int32_t CollationServiceTest::checkAvailable(const char* msg) {
+ StringEnumeration *iter = Collator::getAvailableLocales();
+ if (!assertTrue("getAvailableLocales != NULL", iter!=NULL)) return -1;
+ int32_t n = checkStringEnumeration(msg, *iter, NULL, 0);
+ delete iter;
+ return n;
+}
+#endif
+
+static const char* KW[] = {
+ "collation"
+};
+static const int32_t KW_COUNT = sizeof(KW)/sizeof(KW[0]);
+
+static const char* KWVAL[] = {
+ "phonebook",
+ "stroke"
+};
+static const int32_t KWVAL_COUNT = sizeof(KWVAL)/sizeof(KWVAL[0]);
+
+void CollationServiceTest::TestSeparateTree() {
+ UErrorCode ec = U_ZERO_ERROR;
+ StringEnumeration *iter = Collator::getKeywords(ec);
+ if (!assertTrue("getKeywords != NULL", iter!=NULL)) return;
+ if (!assertSuccess("getKeywords", ec)) return;
+ checkStringEnumeration("getKeywords", *iter, KW, KW_COUNT);
+ delete iter;
+
+ iter = Collator::getKeywordValues(KW[0], ec);
+ if (!assertTrue("getKeywordValues != NULL", iter!=NULL)) return;
+ if (!assertSuccess("getKeywordValues", ec)) return;
+ checkStringEnumeration("getKeywordValues", *iter, KWVAL, KWVAL_COUNT);
+ delete iter;
+
+ UBool isAvailable;
+ Locale equiv = Collator::getFunctionalEquivalent("collation",
+ Locale::createFromName("fr"),
+ isAvailable, ec);
+ assertSuccess("getFunctionalEquivalent", ec);
+ assertEquals("getFunctionalEquivalent(fr)", "fr", equiv.getName());
+ assertTrue("getFunctionalEquivalent(fr).isAvailable==TRUE",
+ isAvailable == TRUE);
+
+ equiv = Collator::getFunctionalEquivalent("collation",
+ Locale::createFromName("fr_FR"),
+ isAvailable, ec);
+ assertSuccess("getFunctionalEquivalent", ec);
+ assertEquals("getFunctionalEquivalent(fr_FR)", "fr", equiv.getName());
+ assertTrue("getFunctionalEquivalent(fr_FR).isAvailable==TRUE",
+ isAvailable == TRUE);
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/svccoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/svccoll.h
new file mode 100644
index 00000000000..3967f104ce8
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/svccoll.h
@@ -0,0 +1,46 @@
+/********************************************************************
+ * Copyright (c) 2004, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * CollationServiceTest tests registration of collators.
+ */
+
+#ifndef _SVCCOLL
+#define _SVCCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "intltest.h"
+
+U_NAMESPACE_BEGIN
+
+class StringEnumeration;
+
+class CollationServiceTest: public IntlTest {
+public:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* /*par = NULL */);
+
+ void TestRegister(void);
+ void TestRegisterFactory(void);
+ void TestSeparateTree();
+
+ private:
+ int32_t checkStringEnumeration(const char* msg,
+ StringEnumeration& iter,
+ const char** expected,
+ int32_t expectedCount);
+
+ int32_t checkAvailable(const char* msg);
+};
+
+U_NAMESPACE_END
+
+/* #if !UCONFIG_NO_COLLATION */
+#endif
+
+/* #ifndef _SVCCOLL */
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tchcfmt.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tchcfmt.cpp
new file mode 100644
index 00000000000..82d237d5102
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tchcfmt.cpp
@@ -0,0 +1,652 @@
+
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+#include "tchcfmt.h"
+#include "cmemory.h"
+#include "unicode/msgfmt.h"
+#include "unicode/choicfmt.h"
+
+#include <float.h>
+
+// tests have obvious memory leaks!
+
+void TestChoiceFormat::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ TESTCASE(0,TestSimpleExample);
+ TESTCASE(1,TestComplexExample);
+ TESTCASE(2,TestClosures);
+ TESTCASE(3,TestPatterns);
+ default: name = ""; break;
+ }
+}
+
+static UBool chkstatus( UErrorCode &status, const char* msg = NULL )
+{
+ UBool ok = U_SUCCESS(status);
+ if (!ok) it_errln( msg );
+ return ok;
+}
+
+void
+TestChoiceFormat::TestSimpleExample( void )
+{
+ double limits[] = {1,2,3,4,5,6,7};
+ UnicodeString monthNames[] = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
+ ChoiceFormat* form = new ChoiceFormat(limits, monthNames, 7);
+ ParsePosition parse_pos;
+ // TODO Fix this ParsePosition stuff...
+ UnicodeString str;
+ UnicodeString res1, res2;
+ UErrorCode status;
+ FieldPosition fpos(0);
+ Formattable f;
+ int32_t ix;
+ //for (double i = 0.0; i <= 8.0; ++i) {
+ for (ix = 0; ix <= 8; ++ix) {
+ double i = ix; //nos
+ status = U_ZERO_ERROR;
+ fpos = 0;
+ str = "";
+ res1 = form->format(i, str, fpos, status );
+ if (!chkstatus( status, "*** test_simple_example format" )) {
+ delete form;
+ return;
+ }
+ //form->parse(res1, f, parse_pos);
+ res2 = " ??? ";
+ it_logln(UnicodeString("") + ix + UnicodeString(" -> ") + res1 + UnicodeString(" -> ") + res2);
+ }
+ //Testing ==operator
+ const double filelimits[] = {0,1,2};
+ const UnicodeString filepart[] = {"are no files","is one file","are {2} files"};
+ ChoiceFormat* formnew=new ChoiceFormat(filelimits, filepart, 3);
+ ChoiceFormat* formequal=new ChoiceFormat(limits, monthNames, 7);
+ if(*formnew == *form){
+ errln("ERROR: ==operator failed\n");
+ }
+ if(!(*form == *formequal)){
+ errln("ERROR: ==operator failed\n");
+ }
+ delete formequal;
+
+#ifdef U_USE_CHOICE_FORMAT_DEPRECATES
+ //Testing adoptChoices()
+ double *limitsToAdopt = (double *)uprv_malloc(7 * sizeof(double));
+ UnicodeString *monthNamesToAdopt = new UnicodeString[7];
+
+ uprv_arrayCopy(monthNames, monthNamesToAdopt, 7);
+ uprv_memcpy(limitsToAdopt, limits, (size_t)(7 * sizeof(limits[0])));
+
+ formnew->adoptChoices(limitsToAdopt, monthNamesToAdopt, 7);
+ if(!(*formnew == *form)){
+ errln("ERROR: ==Operator or adoptChoices failed\n");
+ }
+#endif
+
+ delete formnew;
+
+ //Testing getLimits()
+ double *gotLimits=0;
+ int32_t count=0;
+ gotLimits=(double*)form->getLimits(count);
+ if(count != 7){
+ errln("getLimits didn't update the count correctly\n");
+ }
+ for(ix=0; ix<count; ix++){
+ if(gotLimits[ix] != limits[ix]){
+ errln((UnicodeString)"getLimits didn't get the limits correctly. Expected " + limits[ix] + " Got " + gotLimits[ix]);
+ }
+ }
+ //Testing getFormat()
+ count=0;
+ UnicodeString *gotFormats=0;
+ gotFormats=(UnicodeString*)form->getFormats(count);
+ if(count != 7){
+ errln("getFormats didn't update the count correctly\n");
+ }
+ for(ix=0; ix<count; ix++){
+ if(gotFormats[ix] != monthNames[ix]){
+ errln((UnicodeString)"getFormats didn't get the Formats correctly. Expected " + monthNames[ix] + " Got " + gotFormats[ix]);
+ }
+ }
+
+
+ delete form;
+
+}
+
+void
+TestChoiceFormat::TestComplexExample( void )
+{
+ UErrorCode status = U_ZERO_ERROR;
+ const double filelimits[] = {-1, 0,1,2};
+ const UnicodeString filepart[] = {"are corrupted files", "are no files","is one file","are {2} files"};
+
+ ChoiceFormat* fileform = new ChoiceFormat( filelimits, filepart, 4);
+
+ if (!fileform) {
+ it_errln("*** test_complex_example fileform");
+ return;
+ }
+
+ Format* filenumform = NumberFormat::createInstance( status );
+ if (!filenumform) {
+ it_errln("*** test_complex_example filenumform");
+ delete fileform;
+ return;
+ }
+ if (!chkstatus( status, "*** test_simple_example filenumform" )) {
+ delete fileform;
+ delete filenumform;
+ return;
+ }
+
+ //const Format* testFormats[] = { fileform, NULL, filenumform };
+ //pattform->setFormats( testFormats, 3 );
+
+ MessageFormat* pattform = new MessageFormat("There {0} on {1}", status );
+ if (!pattform) {
+ it_errln("*** test_complex_example pattform");
+ delete fileform;
+ delete filenumform;
+ return;
+ }
+ if (!chkstatus( status, "*** test_complex_example pattform" )) {
+ delete fileform;
+ delete filenumform;
+ delete pattform;
+ return;
+ }
+
+ pattform->setFormat( 0, *fileform );
+ pattform->setFormat( 2, *filenumform );
+
+
+ Formattable testArgs[] = {(int32_t)0, "Disk_A", (int32_t)0};
+ UnicodeString str;
+ UnicodeString res1, res2;
+ pattform->toPattern( res1 );
+ it_logln("MessageFormat toPattern: " + res1);
+ fileform->toPattern( res1 );
+ it_logln("ChoiceFormat toPattern: " + res1);
+ if (res1 == "-1.0#are corrupted files|0.0#are no files|1.0#is one file|2.0#are {2} files") {
+ it_logln("toPattern tested!");
+ }else{
+ it_errln("*** ChoiceFormat to Pattern result!");
+ }
+
+ FieldPosition fpos(0);
+
+ UnicodeString checkstr[] = {
+ "There are corrupted files on Disk_A",
+ "There are no files on Disk_A",
+ "There is one file on Disk_A",
+ "There are 2 files on Disk_A",
+ "There are 3 files on Disk_A"
+ };
+
+ // if (status != U_ZERO_ERROR) return; // TODO: analyze why we have such a bad bail out here!
+
+ if (U_FAILURE(status)) {
+ delete fileform;
+ delete filenumform;
+ delete pattform;
+ return;
+ }
+
+
+ int32_t i;
+ int32_t start = -1;
+ for (i = start; i < 4; ++i) {
+ str = "";
+ status = U_ZERO_ERROR;
+ testArgs[0] = Formattable((int32_t)i);
+ testArgs[2] = testArgs[0];
+ res2 = pattform->format(testArgs, 3, str, fpos, status );
+ if (!chkstatus( status, "*** test_complex_example format" )) {
+ delete fileform;
+ delete filenumform;
+ delete pattform;
+ return;
+ }
+ it_logln(i + UnicodeString(" -> ") + res2);
+ if (res2 != checkstr[i - start]) {
+ it_errln("*** test_complex_example res string");
+ it_errln(UnicodeString("*** ") + i + UnicodeString(" -> '") + res2 + UnicodeString("' unlike '") + checkstr[i] + UnicodeString("' ! "));
+ }
+ }
+ it_logln();
+
+ it_logln("------ additional testing in complex test ------");
+ it_logln();
+ //
+ int32_t retCount;
+ const double* retLimits = fileform->getLimits( retCount );
+ if ((retCount == 4) && (retLimits)
+ && (retLimits[0] == -1.0)
+ && (retLimits[1] == 0.0)
+ && (retLimits[2] == 1.0)
+ && (retLimits[3] == 2.0)) {
+ it_logln("getLimits tested!");
+ }else{
+ it_errln("*** getLimits unexpected result!");
+ }
+
+ const UnicodeString* retFormats = fileform->getFormats( retCount );
+ if ((retCount == 4) && (retFormats)
+ && (retFormats[0] == "are corrupted files")
+ && (retFormats[1] == "are no files")
+ && (retFormats[2] == "is one file")
+ && (retFormats[3] == "are {2} files")) {
+ it_logln("getFormats tested!");
+ }else{
+ it_errln("*** getFormats unexpected result!");
+ }
+
+ UnicodeString checkstr2[] = {
+ "There is no folder on Disk_A",
+ "There is one folder on Disk_A",
+ "There are many folders on Disk_A",
+ "There are many folders on Disk_A"
+ };
+
+ fileform->applyPattern("0#is no folder|1#is one folder|2#are many folders", status );
+ if (status == U_ZERO_ERROR)
+ it_logln("status applyPattern OK!");
+ if (!chkstatus( status, "*** test_complex_example pattform" )) {
+ delete fileform;
+ delete filenumform;
+ delete pattform;
+ return;
+ }
+ pattform->setFormat( 0, *fileform );
+ fpos = 0;
+ for (i = 0; i < 4; ++i) {
+ str = "";
+ status = U_ZERO_ERROR;
+ testArgs[0] = Formattable((int32_t)i);
+ testArgs[2] = testArgs[0];
+ res2 = pattform->format(testArgs, 3, str, fpos, status );
+ if (!chkstatus( status, "*** test_complex_example format 2" )) {
+ delete fileform;
+ delete filenumform;
+ delete pattform;
+ return;
+ }
+ it_logln(UnicodeString() + i + UnicodeString(" -> ") + res2);
+ if (res2 != checkstr2[i]) {
+ it_errln("*** test_complex_example res string");
+ it_errln(UnicodeString("*** ") + i + UnicodeString(" -> '") + res2 + UnicodeString("' unlike '") + checkstr2[i] + UnicodeString("' ! "));
+ }
+ }
+
+ const double limits_A[] = {1,2,3,4,5,6,7};
+ const UnicodeString monthNames_A[] = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
+ ChoiceFormat* form_A = new ChoiceFormat(limits_A, monthNames_A, 7);
+ ChoiceFormat* form_A2 = new ChoiceFormat(limits_A, monthNames_A, 7);
+ const double limits_B[] = {1,2,3,4,5,6,7};
+ const UnicodeString monthNames_B[] = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat_BBB"};
+ ChoiceFormat* form_B = new ChoiceFormat(limits_B, monthNames_B, 7);
+ if (!form_A || !form_B || !form_A2) {
+ it_errln("*** test-choiceFormat not allocatable!");
+ }else{
+ if (*form_A == *form_A2) {
+ it_logln("operator== tested.");
+ }else{
+ it_errln("*** operator==");
+ }
+
+ if (*form_A != *form_B) {
+ it_logln("operator!= tested.");
+ }else{
+ it_errln("*** operator!=");
+ }
+
+ ChoiceFormat* form_A3 = (ChoiceFormat*) form_A->clone();
+ if (!form_A3) {
+ it_errln("*** ChoiceFormat->clone is nil.");
+ }else{
+ if ((*form_A3 == *form_A) && (*form_A3 != *form_B)) {
+ it_logln("method clone tested.");
+ }else{
+ it_errln("*** ChoiceFormat clone or operator==, or operator!= .");
+ }
+ }
+
+ ChoiceFormat form_Assigned( *form_A );
+ UBool ok = (form_Assigned == *form_A) && (form_Assigned != *form_B);
+ form_Assigned = *form_B;
+ ok = ok && (form_Assigned != *form_A) && (form_Assigned == *form_B);
+ if (ok) {
+ it_logln("copy constructor and operator= tested.");
+ }else{
+ it_errln("*** copy constructor or operator= or operator == or operator != .");
+ }
+ delete form_A3;
+ }
+
+
+ delete form_A; delete form_A2; delete form_B;
+
+ const char* testPattern = "0#none|1#one|2#many";
+ ChoiceFormat form_pat( testPattern, status );
+ if (!chkstatus( status, "*** ChoiceFormat contructor( newPattern, status)" )) {
+ delete fileform;
+ delete filenumform;
+ delete pattform;
+ return;
+ }
+
+ form_pat.toPattern( res1 );
+ if (res1 == "0.0#none|1.0#one|2.0#many") {
+ it_logln("ChoiceFormat contructor( newPattern, status) tested");
+ }else{
+ it_errln("*** ChoiceFormat contructor( newPattern, status) or toPattern result!");
+ }
+
+#ifdef U_USE_CHOICE_FORMAT_DEPRECATES
+ double* d_a = (double *)uprv_malloc(2 * sizeof(double));
+ if (!d_a) { it_errln("*** allocation error."); return; }
+ d_a[0] = 1.0; d_a[1] = 2.0;
+
+ UnicodeString* s_a = new UnicodeString[2];
+ if (!s_a) { it_errln("*** allocation error."); return; }
+ s_a[0] = "first"; s_a[1] = "second";
+
+ form_pat.adoptChoices( d_a, s_a, 2 );
+ form_pat.toPattern( res1 );
+ it_out << "ChoiceFormat adoptChoices toPattern: " << res1 << endl;
+ if (res1 == "1.0#first|2.0#second") {
+ it_logln("ChoiceFormat adoptChoices tested");
+ }else{
+ it_errln("*** ChoiceFormat adoptChoices result!");
+ }
+#endif
+
+ double d_a2[] = { 3.0, 4.0 };
+ UnicodeString s_a2[] = { "third", "forth" };
+
+ form_pat.setChoices( d_a2, s_a2, 2 );
+ form_pat.toPattern( res1 );
+ it_logln(UnicodeString("ChoiceFormat adoptChoices toPattern: ") + res1);
+ if (res1 == "3.0#third|4.0#forth") {
+ it_logln("ChoiceFormat adoptChoices tested");
+ }else{
+ it_errln("*** ChoiceFormat adoptChoices result!");
+ }
+
+ str = "";
+ fpos = 0;
+ status = U_ZERO_ERROR;
+ double arg_double = 3.0;
+ res1 = form_pat.format( arg_double, str, fpos );
+ it_logln(UnicodeString("ChoiceFormat format:") + res1);
+ if (res1 != "third") it_errln("*** ChoiceFormat format (double, ...) result!");
+
+ str = "";
+ fpos = 0;
+ status = U_ZERO_ERROR;
+ int64_t arg_64 = 3;
+ res1 = form_pat.format( arg_64, str, fpos );
+ it_logln(UnicodeString("ChoiceFormat format:") + res1);
+ if (res1 != "third") it_errln("*** ChoiceFormat format (int64_t, ...) result!");
+
+ str = "";
+ fpos = 0;
+ status = U_ZERO_ERROR;
+ int32_t arg_long = 3;
+ res1 = form_pat.format( arg_long, str, fpos );
+ it_logln(UnicodeString("ChoiceFormat format:") + res1);
+ if (res1 != "third") it_errln("*** ChoiceFormat format (int32_t, ...) result!");
+
+ Formattable ft( (int32_t)3 );
+ str = "";
+ fpos = 0;
+ status = U_ZERO_ERROR;
+ res1 = form_pat.format( ft, str, fpos, status );
+ if (!chkstatus( status, "*** test_complex_example format (int32_t, ...)" )) {
+ delete fileform;
+ delete filenumform;
+ delete pattform;
+ return;
+ }
+ it_logln(UnicodeString("ChoiceFormat format:") + res1);
+ if (res1 != "third") it_errln("*** ChoiceFormat format (Formattable, ...) result!");
+
+ Formattable fta[] = { (int32_t)3 };
+ str = "";
+ fpos = 0;
+ status = U_ZERO_ERROR;
+ res1 = form_pat.format( fta, 1, str, fpos, status );
+ if (!chkstatus( status, "*** test_complex_example format (int32_t, ...)" )) {
+ delete fileform;
+ delete filenumform;
+ delete pattform;
+ return;
+ }
+ it_logln(UnicodeString("ChoiceFormat format:") + res1);
+ if (res1 != "third") it_errln("*** ChoiceFormat format (Formattable[], cnt, ...) result!");
+
+ ParsePosition parse_pos = 0;
+ Formattable result;
+ UnicodeString parsetext("third");
+ form_pat.parse( parsetext, result, parse_pos );
+ double rd = (result.getType() == Formattable::kLong) ? result.getLong() : result.getDouble();
+ if (rd == 3.0) {
+ it_logln("parse( ..., ParsePos ) tested.");
+ }else{
+ it_errln("*** ChoiceFormat parse( ..., ParsePos )!");
+ }
+
+ form_pat.parse( parsetext, result, status );
+ rd = (result.getType() == Formattable::kLong) ? result.getLong() : result.getDouble();
+ if (rd == 3.0) {
+ it_logln("parse( ..., UErrorCode ) tested.");
+ }else{
+ it_errln("*** ChoiceFormat parse( ..., UErrorCode )!");
+ }
+
+ /*
+ UClassID classID = ChoiceFormat::getStaticClassID();
+ if (classID == form_pat.getDynamicClassID()) {
+ it_out << "getStaticClassID and getDynamicClassID tested." << endl;
+ }else{
+ it_errln("*** getStaticClassID and getDynamicClassID!");
+ }
+ */
+
+ it_logln();
+
+ delete fileform;
+ delete filenumform;
+ delete pattform;
+}
+
+
+/**
+ * Test new closure API
+ */
+void TestChoiceFormat::TestClosures(void) {
+ // Construct open, half-open, half-open (the other way), and closed
+ // intervals. Do this both using arrays and using a pattern.
+
+ // 'fmt1' is created using arrays
+ UBool T = TRUE, F = FALSE;
+ // 0: ,1)
+ // 1: [1,2]
+ // 2: (2,3]
+ // 3: (3,4)
+ // 4: [4,5)
+ // 5: [5,
+ double limits[] = { 0, 1, 2, 3, 4, 5 };
+ UBool closures[] = { F, F, T, T, F, F };
+ UnicodeString fmts[] = {
+ ",1)", "[1,2]", "(2,3]", "(3,4)", "[4,5)", "[5,"
+ };
+ ChoiceFormat fmt1(limits, closures, fmts, 6);
+
+ // 'fmt2' is created using a pattern; it should be equivalent
+ UErrorCode status = U_ZERO_ERROR;
+ const char* PAT = "0.0#,1)|1.0#[1,2]|2.0<(2,3]|3.0<(3,4)|4.0#[4,5)|5.0#[5,";
+ ChoiceFormat fmt2(PAT, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: ChoiceFormat constructor failed");
+ return;
+ }
+
+ // Check the patterns
+ UnicodeString str;
+ fmt1.toPattern(str);
+ if (str == PAT) {
+ logln("Ok: " + str);
+ } else {
+ errln("FAIL: " + str + ", expected " + PAT);
+ }
+ str.truncate(0);
+
+ // Check equality
+ if (fmt1 != fmt2) {
+ errln("FAIL: fmt1 != fmt2");
+ }
+
+ int32_t i;
+ int32_t count2 = 0;
+ const double *limits2 = fmt2.getLimits(count2);
+ const UBool *closures2 = fmt2.getClosures(count2);
+
+ if((count2 != 6) || !limits2 || !closures2) {
+ errln("FAIL: couldn't get limits or closures");
+ } else {
+ for(i=0;i<count2;i++) {
+ logln("#%d/%d: limit %g closed %s\n",
+ i, count2,
+ limits2[i],
+ closures2[i] ?"T":"F");
+ if(limits2[i] != limits[i]) {
+ errln("FAIL: limit #%d = %g, should be %g\n", i, limits2[i], limits[i]);
+ }
+ if((closures2[i]!=0) != (closures[i]!=0)) {
+ errln("FAIL: closure #%d = %s, should be %s\n", i, closures2[i]?"T":"F", closures[i]?"T":"F");
+ }
+ }
+ }
+
+ // Now test both format objects
+ UnicodeString exp[] = {
+ /*-0.5 => */ ",1)",
+ /* 0.0 => */ ",1)",
+ /* 0.5 => */ ",1)",
+ /* 1.0 => */ "[1,2]",
+ /* 1.5 => */ "[1,2]",
+ /* 2.0 => */ "[1,2]",
+ /* 2.5 => */ "(2,3]",
+ /* 3.0 => */ "(2,3]",
+ /* 3.5 => */ "(3,4)",
+ /* 4.0 => */ "[4,5)",
+ /* 4.5 => */ "[4,5)",
+ /* 5.0 => */ "[5,",
+ /* 5.5 => */ "[5,"
+ };
+
+ // Each format object should behave exactly the same
+ ChoiceFormat* FMT[] = { &fmt1, &fmt2 };
+ for (int32_t pass=0; pass<2; ++pass) {
+ int32_t j=0;
+ for (int32_t ix=-5; ix<=55; ix+=5) {
+ double x = ix / 10.0; // -0.5 to 5.5 step +0.5
+ FMT[pass]->format(x, str);
+ if (str == exp[j]) {
+ logln((UnicodeString)"Ok: " + x + " => " + str);
+ } else {
+ errln((UnicodeString)"FAIL: " + x + " => " + str +
+ ", expected " + exp[j]);
+ }
+ str.truncate(0);
+ ++j;
+ }
+ }
+}
+
+/**
+ * Helper for TestPatterns()
+ */
+void TestChoiceFormat::_testPattern(const char* pattern,
+ UBool isValid,
+ double v1, const char* str1,
+ double v2, const char* str2,
+ double v3, const char* str3) {
+ UErrorCode ec = U_ZERO_ERROR;
+ ChoiceFormat fmt(pattern, ec);
+ if (!isValid) {
+ if (U_FAILURE(ec)) {
+ logln((UnicodeString)"Ok: " + pattern + " failed");
+ } else {
+ logln((UnicodeString)"FAIL: " + pattern + " accepted");
+ }
+ return;
+ }
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: ChoiceFormat(" + pattern + ") failed");
+ return;
+ } else {
+ logln((UnicodeString)"Ok: Pattern: " + pattern);
+ }
+ UnicodeString out;
+ logln((UnicodeString)" toPattern: " + fmt.toPattern(out));
+
+ double v[] = {v1, v2, v3};
+ const char* str[] = {str1, str2, str3};
+ for (int32_t i=0; i<3; ++i) {
+ out.truncate(0);
+ fmt.format(v[i], out);
+ if (out == str[i]) {
+ logln((UnicodeString)"Ok: " + v[i] + " => " + out);
+ } else {
+ errln((UnicodeString)"FAIL: " + v[i] + " => " + out +
+ ", expected " + str[i]);
+ }
+ }
+}
+
+/**
+ * Test applyPattern
+ */
+void TestChoiceFormat::TestPatterns(void) {
+ // Try a pattern that isolates a single value. Create
+ // three ranges: [-Inf,1.0) [1.0,1.0] (1.0,+Inf]
+ _testPattern("0.0#a|1.0#b|1.0<c", TRUE,
+ 1.0 - 1e-9, "a",
+ 1.0, "b",
+ 1.0 + 1e-9, "c");
+
+ // Try an invalid pattern that isolates a single value.
+ // [-Inf,1.0) [1.0,1.0) [1.0,+Inf]
+ _testPattern("0.0#a|1.0#b|1.0#c", FALSE,
+ 0, 0, 0, 0, 0, 0);
+
+ // Another
+ // [-Inf,1.0] (1.0,1.0) [1.0,+Inf]
+ _testPattern("0.0#a|1.0<b|1.0#c", FALSE,
+ 0, 0, 0, 0, 0, 0);
+ // Another
+ // [-Inf,1.0] (1.0,1.0] (1.0,+Inf]
+ _testPattern("0.0#a|1.0<b|1.0<c", FALSE,
+ 0, 0, 0, 0, 0, 0);
+
+ // Try a grossly invalid pattern.
+ // [-Inf,2.0) [2.0,1.0) [1.0,+Inf]
+ _testPattern("0.0#a|2.0#b|1.0#c", FALSE,
+ 0, 0, 0, 0, 0, 0);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tchcfmt.h b/Build/source/libs/icu/icu-xetex/test/intltest/tchcfmt.h
new file mode 100644
index 00000000000..ade2027a52f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tchcfmt.h
@@ -0,0 +1,55 @@
+
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * TestChoiceFormat is a third level test class
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+
+/**
+ * tests Choice Format, functionality of examples, as well as API functionality
+ **/
+class TestChoiceFormat: public IntlTest {
+ /**
+ * tests basic functionality in a simple example
+ **/
+ void TestSimpleExample(void);
+ /**
+ * tests functionality in a more complex example,
+ * and extensive API functionality.
+ * See verbose message output statements for specifically tested API
+ **/
+ void TestComplexExample(void);
+
+ /**
+ * Test new closure API
+ */
+ void TestClosures(void);
+
+ /**
+ * Test applyPattern
+ */
+ void TestPatterns(void);
+
+ void _testPattern(const char* pattern,
+ UBool isValid,
+ double v1, const char* str1,
+ double v2, const char* str2,
+ double v3, const char* str3);
+ /**
+ * runs tests in local funtions:
+ **/
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/testidn.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/testidn.cpp
new file mode 100644
index 00000000000..e1f627735db
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/testidn.cpp
@@ -0,0 +1,450 @@
+/*
+*******************************************************************************
+*
+* Copyright (C) 2003-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: testidn.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2003-02-06
+* created by: Ram Viswanadha
+*
+* This program reads the rfc3454_*.txt files,
+* parses them, and extracts the data for Nameprep conformance.
+* It then preprocesses it and writes a binary file for efficient use
+* in various IDNA conversion processes.
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA && !UCONFIG_NO_TRANSLITERATION
+
+#define USPREP_TYPE_NAMES_ARRAY
+
+#include "unicode/uchar.h"
+#include "unicode/putil.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "unicode/udata.h"
+#include "unewdata.h"
+#include "uoptions.h"
+#include "uparse.h"
+#include "utrie.h"
+#include "umutex.h"
+#include "sprpimpl.h"
+#include "testidna.h"
+#include "punyref.h"
+#include <stdlib.h>
+
+UBool beVerbose=FALSE, haveCopyright=TRUE;
+
+/* prototypes --------------------------------------------------------------- */
+
+
+static void
+parseMappings(const char *filename, UBool reportError,TestIDNA& test, UErrorCode *pErrorCode);
+
+static void
+compareMapping(uint32_t codepoint, uint32_t* mapping, int32_t mapLength,
+ UStringPrepType option);
+
+static void
+compareFlagsForRange(uint32_t start, uint32_t end,UStringPrepType option);
+
+static void
+testAllCodepoints(TestIDNA& test);
+
+static TestIDNA* pTestIDNA =NULL;
+
+static const char* fileNames[] = {
+ "NamePrepProfile.txt"
+ };
+static UStringPrepProfile *profile = NULL;
+static const UTrie *idnTrie = NULL;
+static const int32_t *indexes = NULL;
+static const uint16_t *mappingData = NULL;
+/* -------------------------------------------------------------------------- */
+
+/* file definitions */
+#define DATA_NAME "uidna"
+#define DATA_TYPE "icu"
+
+#define MISC_DIR "misc"
+
+extern int
+testData(TestIDNA& test) {
+ char *basename=NULL;
+ UErrorCode errorCode=U_ZERO_ERROR;
+ char *saveBasename =NULL;
+
+ profile = usprep_open(NULL, DATA_NAME, &errorCode);
+ if(U_FAILURE(errorCode)){
+ test.errln("Failed to load IDNA data file. " + UnicodeString(u_errorName(errorCode)));
+ return errorCode;
+ }
+
+ char* filename = (char*) malloc(strlen(IntlTest::pathToDataDirectory())*1024);
+ //TODO get the srcDir dynamically
+ const char *srcDir=IntlTest::pathToDataDirectory();
+
+ idnTrie = &profile->sprepTrie;
+ indexes = profile->indexes;
+ mappingData = profile->mappingData;
+
+ //initialize
+ pTestIDNA = &test;
+
+ /* prepare the filename beginning with the source dir */
+ if(uprv_strchr(srcDir,U_FILE_SEP_CHAR) == NULL){
+ filename[0] = 0x2E;
+ filename[1] = U_FILE_SEP_CHAR;
+ uprv_strcpy(filename+2,srcDir);
+ }else{
+ uprv_strcpy(filename, srcDir);
+ }
+ basename=filename+uprv_strlen(filename);
+ if(basename>filename && *(basename-1)!=U_FILE_SEP_CHAR) {
+ *basename++=U_FILE_SEP_CHAR;
+ }
+
+ /* process unassigned */
+ basename=filename+uprv_strlen(filename);
+ if(basename>filename && *(basename-1)!=U_FILE_SEP_CHAR) {
+ *basename++=U_FILE_SEP_CHAR;
+ }
+
+ /* first copy misc directory */
+ saveBasename = basename;
+ uprv_strcpy(basename,MISC_DIR);
+ basename = basename + uprv_strlen(MISC_DIR);
+ *basename++=U_FILE_SEP_CHAR;
+
+ /* process unassigned */
+ uprv_strcpy(basename,fileNames[0]);
+ parseMappings(filename,TRUE, test,&errorCode);
+ if(U_FAILURE(errorCode)) {
+ test.errln( "Could not open file %s for reading \n", filename);
+ return errorCode;
+ }
+
+ testAllCodepoints(test);
+
+ usprep_close(profile);
+ pTestIDNA = NULL;
+ free(filename);
+ return errorCode;
+}
+U_CDECL_BEGIN
+
+static void U_CALLCONV
+strprepProfileLineFn(void * /*context*/,
+ char *fields[][2], int32_t fieldCount,
+ UErrorCode *pErrorCode) {
+ uint32_t mapping[40];
+ char *end, *map;
+ uint32_t code;
+ int32_t length;
+ /*UBool* mapWithNorm = (UBool*) context;*/
+ const char* typeName;
+ uint32_t rangeStart=0,rangeEnd =0;
+
+ if(fieldCount != 3){
+ *pErrorCode = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+
+ typeName = fields[2][0];
+ map = fields[1][0];
+
+ if(uprv_strstr(typeName, usprepTypeNames[USPREP_UNASSIGNED])!=NULL){
+
+ u_parseCodePointRange(fields[0][0], &rangeStart,&rangeEnd, pErrorCode);
+
+ /* store the range */
+ compareFlagsForRange(rangeStart,rangeEnd,USPREP_UNASSIGNED);
+
+ }else if(uprv_strstr(typeName, usprepTypeNames[USPREP_PROHIBITED])!=NULL){
+
+ u_parseCodePointRange(fields[0][0], &rangeStart,&rangeEnd, pErrorCode);
+
+ /* store the range */
+ compareFlagsForRange(rangeStart,rangeEnd,USPREP_PROHIBITED);
+
+ }else if(uprv_strstr(typeName, usprepTypeNames[USPREP_MAP])!=NULL){
+ /* get the character code, field 0 */
+ code=(uint32_t)uprv_strtoul(fields[0][0], &end, 16);
+
+ /* parse the mapping string */
+ length=u_parseCodePoints(map, mapping, sizeof(mapping)/4, pErrorCode);
+
+ /* store the mapping */
+ compareMapping(code,mapping, length,USPREP_MAP);
+
+ }else{
+ *pErrorCode = U_INVALID_FORMAT_ERROR;
+ }
+
+}
+
+U_CDECL_END
+
+static void
+parseMappings(const char *filename,UBool reportError, TestIDNA& test, UErrorCode *pErrorCode) {
+ char *fields[3][2];
+
+ if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
+ return;
+ }
+
+ u_parseDelimitedFile(filename, ';', fields, 3, strprepProfileLineFn, (void*)filename, pErrorCode);
+
+ //fprintf(stdout,"Number of code points that have mappings with length >1 : %i\n",len);
+
+ if(U_FAILURE(*pErrorCode) && (reportError || *pErrorCode!=U_FILE_ACCESS_ERROR)) {
+ test.errln( "testidn error: u_parseDelimitedFile(\"%s\") failed - %s\n", filename, u_errorName(*pErrorCode));
+ }
+}
+
+
+static inline UStringPrepType
+getValues(uint32_t result, int32_t& value, UBool& isIndex){
+
+ UStringPrepType type;
+
+ if(result == 0){
+ /*
+ * Initial value stored in the mapping table
+ * just return USPREP_TYPE_LIMIT .. so that
+ * the source codepoint is copied to the destination
+ */
+ type = USPREP_TYPE_LIMIT;
+ isIndex =FALSE;
+ value = 0;
+ }else if(result >= _SPREP_TYPE_THRESHOLD){
+ type = (UStringPrepType) (result - _SPREP_TYPE_THRESHOLD);
+ isIndex =FALSE;
+ value = 0;
+ }else{
+ /* get the state */
+ type = USPREP_MAP;
+ /* ascertain if the value is index or delta */
+ if(result & 0x02){
+ isIndex = TRUE;
+ value = result >> 2; //mask off the lower 2 bits and shift
+
+ }else{
+ isIndex = FALSE;
+ value = (int16_t)result;
+ value = (value >> 2);
+
+ }
+ if((result>>2) == _SPREP_MAX_INDEX_VALUE){
+ type = USPREP_DELETE;
+ isIndex =FALSE;
+ value = 0;
+ }
+ }
+ return type;
+}
+
+
+
+static void
+testAllCodepoints(TestIDNA& test){
+ /*
+ {
+ UChar str[19] = {
+ 0xC138, 0xACC4, 0xC758, 0xBAA8, 0xB4E0, 0xC0AC, 0xB78C, 0xB4E4, 0xC774,
+ 0x070F,//prohibited
+ 0xD55C, 0xAD6D, 0xC5B4, 0xB97C, 0xC774, 0xD574, 0xD55C, 0xB2E4, 0xBA74
+ };
+ uint32_t in[19] = {0};
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t inLength=0, outLength=100;
+ char output[100] = {0};
+ punycode_status error;
+ u_strToUTF32((UChar32*)in,19,&inLength,str,19,&status);
+
+ error= punycode_encode(inLength, in, NULL, (uint32_t*)&outLength, output);
+ printf(output);
+
+ }
+ */
+
+ uint32_t i = 0;
+ int32_t unassigned = 0;
+ int32_t prohibited = 0;
+ int32_t mappedWithNorm = 0;
+ int32_t mapped = 0;
+ int32_t noValueInTrie = 0;
+
+ UStringPrepType type;
+ int32_t value;
+ UBool isIndex = FALSE;
+
+ for(i=0;i<=0x10FFFF;i++){
+ uint32_t result = 0;
+ UTRIE_GET16(idnTrie,i, result);
+ type = getValues(result,value, isIndex);
+ if(type != USPREP_TYPE_LIMIT ){
+ if(type == USPREP_UNASSIGNED){
+ unassigned++;
+ }
+ if(type == USPREP_PROHIBITED){
+ prohibited++;
+ }
+ if(type == USPREP_MAP){
+ mapped++;
+ }
+ }else{
+ noValueInTrie++;
+ if(result > 0){
+ test.errln("The return value for 0x%06X is wrong. %i\n",i,result);
+ }
+ }
+ }
+
+ test.logln("Number of Unassinged code points : %i \n",unassigned);
+ test.logln("Number of Prohibited code points : %i \n",prohibited);
+ test.logln("Number of Mapped code points : %i \n",mapped);
+ test.logln("Number of Mapped with NFKC code points : %i \n",mappedWithNorm);
+ test.logln("Number of code points that have no value in Trie: %i \n",noValueInTrie);
+
+
+}
+
+static void
+compareMapping(uint32_t codepoint, uint32_t* mapping,int32_t mapLength,
+ UStringPrepType type){
+ uint32_t result = 0;
+ UTRIE_GET16(idnTrie,codepoint, result);
+
+ int32_t length=0;
+ UBool isIndex;
+ UStringPrepType retType;
+ int32_t value, index=0, delta=0;
+
+ retType = getValues(result,value,isIndex);
+
+
+ if(type != retType && retType != USPREP_DELETE){
+
+ pTestIDNA->errln( "Did not get the assigned type for codepoint 0x%08X. Expected: %i Got: %i\n",codepoint, USPREP_MAP, type);
+
+ }
+
+ if(isIndex){
+ index = value;
+ if(index >= indexes[_SPREP_ONE_UCHAR_MAPPING_INDEX_START] &&
+ index < indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START]){
+ length = 1;
+ }else if(index >= indexes[_SPREP_TWO_UCHARS_MAPPING_INDEX_START] &&
+ index < indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START]){
+ length = 2;
+ }else if(index >= indexes[_SPREP_THREE_UCHARS_MAPPING_INDEX_START] &&
+ index < indexes[_SPREP_FOUR_UCHARS_MAPPING_INDEX_START]){
+ length = 3;
+ }else{
+ length = mappingData[index++];
+ }
+ }else{
+ delta = value;
+ length = (retType == USPREP_DELETE)? 0 : 1;
+ }
+
+ int32_t realLength =0;
+ /* figure out the real length */
+ for(int32_t j=0; j<mapLength; j++){
+ if(mapping[j] > 0xFFFF){
+ realLength +=2;
+ }else{
+ realLength++;
+ }
+ }
+
+ if(realLength != length){
+ pTestIDNA->errln( "Did not get the expected length. Expected: %i Got: %i\n", mapLength, length);
+ }
+
+ if(isIndex){
+ for(int8_t i =0; i< mapLength; i++){
+ if(mapping[i] <= 0xFFFF){
+ if(mappingData[index+i] != (uint16_t)mapping[i]){
+ pTestIDNA->errln("Did not get the expected result. Expected: 0x%04X Got: 0x%04X \n", mapping[i], mappingData[index+i]);
+ }
+ }else{
+ UChar lead = UTF16_LEAD(mapping[i]);
+ UChar trail = UTF16_TRAIL(mapping[i]);
+ if(mappingData[index+i] != lead ||
+ mappingData[index+i+1] != trail){
+ pTestIDNA->errln( "Did not get the expected result. Expected: 0x%04X 0x%04X Got: 0x%04X 0x%04X", lead, trail, mappingData[index+i], mappingData[index+i+1]);
+ }
+ }
+ }
+ }else{
+ if(retType!=USPREP_DELETE && (codepoint-delta) != (uint16_t)mapping[0]){
+ pTestIDNA->errln("Did not get the expected result. Expected: 0x%04X Got: 0x%04X \n", mapping[0],(codepoint-delta));
+ }
+ }
+
+}
+
+static void
+compareFlagsForRange(uint32_t start, uint32_t end,
+ UStringPrepType type){
+
+ uint32_t result =0 ;
+ UStringPrepType retType;
+ UBool isIndex=FALSE;
+ int32_t value=0;
+/*
+ // supplementary code point
+ UChar __lead16=UTF16_LEAD(0x2323E);
+ int32_t __offset;
+
+ // get data for lead surrogate
+ (result)=_UTRIE_GET_RAW((&idnTrie), index, 0, (__lead16));
+ __offset=(&idnTrie)->getFoldingOffset(result);
+
+ // get the real data from the folded lead/trail units
+ if(__offset>0) {
+ (result)=_UTRIE_GET_RAW((&idnTrie), index, __offset, (0x2323E)&0x3ff);
+ } else {
+ (result)=(uint32_t)((&idnTrie)->initialValue);
+ }
+
+ UTRIE_GET16(&idnTrie,0x2323E, result);
+*/
+ while(start < end+1){
+ UTRIE_GET16(idnTrie,start, result);
+ retType = getValues(result,value,isIndex);
+ if(result > _SPREP_TYPE_THRESHOLD){
+ if(retType != type){
+ pTestIDNA->errln( "FAIL: Did not get the expected type for 0x%06X. Expected: %s Got: %s\n",start,usprepTypeNames[type], usprepTypeNames[retType]);
+ }
+ }else{
+ if(type == USPREP_PROHIBITED && ((result & 0x01) != 0x01)){
+ pTestIDNA->errln( "FAIL: Did not get the expected type for 0x%06X. Expected: %s Got: %s\n",start,usprepTypeNames[type], usprepTypeNames[retType]);
+ }
+ }
+
+ start++;
+ }
+
+}
+
+
+#endif /* #if !UCONFIG_NO_IDNA */
+
+/*
+ * Hey, Emacs, please set the following:
+ *
+ * Local Variables:
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/testidna.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/testidna.cpp
new file mode 100644
index 00000000000..d4d7a8d2a24
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/testidna.cpp
@@ -0,0 +1,1583 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2003-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: testidna.cpp
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2003feb1
+ * created by: Ram Viswanadha
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA && !UCONFIG_NO_TRANSLITERATION
+
+#include <time.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include "unicode/ustring.h"
+#include "unicode/usprep.h"
+#include "unicode/uniset.h"
+#include "testidna.h"
+#include "idnaref.h"
+#include "nptrans.h"
+#include "unicode/putil.h"
+#include "idnaconf.h"
+
+static const UChar unicodeIn[][41] ={
+ {
+ 0x0644, 0x064A, 0x0647, 0x0645, 0x0627, 0x0628, 0x062A, 0x0643, 0x0644,
+ 0x0645, 0x0648, 0x0634, 0x0639, 0x0631, 0x0628, 0x064A, 0x061F, 0x0000
+ },
+ {
+ 0x4ED6, 0x4EEC, 0x4E3A, 0x4EC0, 0x4E48, 0x4E0D, 0x8BF4, 0x4E2D, 0x6587,
+ 0x0000
+ },
+ {
+ 0x0050, 0x0072, 0x006F, 0x010D, 0x0070, 0x0072, 0x006F, 0x0073, 0x0074,
+ 0x011B, 0x006E, 0x0065, 0x006D, 0x006C, 0x0075, 0x0076, 0x00ED, 0x010D,
+ 0x0065, 0x0073, 0x006B, 0x0079, 0x0000
+ },
+ {
+ 0x05DC, 0x05DE, 0x05D4, 0x05D4, 0x05DD, 0x05E4, 0x05E9, 0x05D5, 0x05D8,
+ 0x05DC, 0x05D0, 0x05DE, 0x05D3, 0x05D1, 0x05E8, 0x05D9, 0x05DD, 0x05E2,
+ 0x05D1, 0x05E8, 0x05D9, 0x05EA, 0x0000
+ },
+ {
+ 0x092F, 0x0939, 0x0932, 0x094B, 0x0917, 0x0939, 0x093F, 0x0928, 0x094D,
+ 0x0926, 0x0940, 0x0915, 0x094D, 0x092F, 0x094B, 0x0902, 0x0928, 0x0939,
+ 0x0940, 0x0902, 0x092C, 0x094B, 0x0932, 0x0938, 0x0915, 0x0924, 0x0947,
+ 0x0939, 0x0948, 0x0902, 0x0000
+ },
+ {
+ 0x306A, 0x305C, 0x307F, 0x3093, 0x306A, 0x65E5, 0x672C, 0x8A9E, 0x3092,
+ 0x8A71, 0x3057, 0x3066, 0x304F, 0x308C, 0x306A, 0x3044, 0x306E, 0x304B,
+ 0x0000
+ },
+/*
+ {
+ 0xC138, 0xACC4, 0xC758, 0xBAA8, 0xB4E0, 0xC0AC, 0xB78C, 0xB4E4, 0xC774,
+ 0xD55C, 0xAD6D, 0xC5B4, 0xB97C, 0xC774, 0xD574, 0xD55C, 0xB2E4, 0xBA74,
+ 0xC5BC, 0xB9C8, 0xB098, 0xC88B, 0xC744, 0xAE4C, 0x0000
+ },
+*/
+ {
+ 0x043F, 0x043E, 0x0447, 0x0435, 0x043C, 0x0443, 0x0436, 0x0435, 0x043E,
+ 0x043D, 0x0438, 0x043D, 0x0435, 0x0433, 0x043E, 0x0432, 0x043E, 0x0440,
+ 0x044F, 0x0442, 0x043F, 0x043E, 0x0440, 0x0443, 0x0441, 0x0441, 0x043A,
+ 0x0438, 0x0000
+ },
+ {
+ 0x0050, 0x006F, 0x0072, 0x0071, 0x0075, 0x00E9, 0x006E, 0x006F, 0x0070,
+ 0x0075, 0x0065, 0x0064, 0x0065, 0x006E, 0x0073, 0x0069, 0x006D, 0x0070,
+ 0x006C, 0x0065, 0x006D, 0x0065, 0x006E, 0x0074, 0x0065, 0x0068, 0x0061,
+ 0x0062, 0x006C, 0x0061, 0x0072, 0x0065, 0x006E, 0x0045, 0x0073, 0x0070,
+ 0x0061, 0x00F1, 0x006F, 0x006C, 0x0000
+ },
+ {
+ 0x4ED6, 0x5011, 0x7232, 0x4EC0, 0x9EBD, 0x4E0D, 0x8AAA, 0x4E2D, 0x6587,
+ 0x0000
+ },
+ {
+ 0x0054, 0x1EA1, 0x0069, 0x0073, 0x0061, 0x006F, 0x0068, 0x1ECD, 0x006B,
+ 0x0068, 0x00F4, 0x006E, 0x0067, 0x0074, 0x0068, 0x1EC3, 0x0063, 0x0068,
+ 0x1EC9, 0x006E, 0x00F3, 0x0069, 0x0074, 0x0069, 0x1EBF, 0x006E, 0x0067,
+ 0x0056, 0x0069, 0x1EC7, 0x0074, 0x0000
+ },
+ {
+ 0x0033, 0x5E74, 0x0042, 0x7D44, 0x91D1, 0x516B, 0x5148, 0x751F, 0x0000
+ },
+ {
+ 0x5B89, 0x5BA4, 0x5948, 0x7F8E, 0x6075, 0x002D, 0x0077, 0x0069, 0x0074,
+ 0x0068, 0x002D, 0x0053, 0x0055, 0x0050, 0x0045, 0x0052, 0x002D, 0x004D,
+ 0x004F, 0x004E, 0x004B, 0x0045, 0x0059, 0x0053, 0x0000
+ },
+ {
+ 0x0048, 0x0065, 0x006C, 0x006C, 0x006F, 0x002D, 0x0041, 0x006E, 0x006F,
+ 0x0074, 0x0068, 0x0065, 0x0072, 0x002D, 0x0057, 0x0061, 0x0079, 0x002D,
+ 0x305D, 0x308C, 0x305E, 0x308C, 0x306E, 0x5834, 0x6240, 0x0000
+ },
+ {
+ 0x3072, 0x3068, 0x3064, 0x5C4B, 0x6839, 0x306E, 0x4E0B, 0x0032, 0x0000
+ },
+ {
+ 0x004D, 0x0061, 0x006A, 0x0069, 0x3067, 0x004B, 0x006F, 0x0069, 0x3059,
+ 0x308B, 0x0035, 0x79D2, 0x524D, 0x0000
+ },
+ {
+ 0x30D1, 0x30D5, 0x30A3, 0x30FC, 0x0064, 0x0065, 0x30EB, 0x30F3, 0x30D0,
+ 0x0000
+ },
+ {
+ 0x305D, 0x306E, 0x30B9, 0x30D4, 0x30FC, 0x30C9, 0x3067, 0x0000
+ },
+ // test non-BMP code points
+ {
+ 0xD800, 0xDF00, 0xD800, 0xDF01, 0xD800, 0xDF02, 0xD800, 0xDF03, 0xD800, 0xDF05,
+ 0xD800, 0xDF06, 0xD800, 0xDF07, 0xD800, 0xDF09, 0xD800, 0xDF0A, 0xD800, 0xDF0B,
+ 0x0000
+ },
+ {
+ 0xD800, 0xDF0D, 0xD800, 0xDF0C, 0xD800, 0xDF1E, 0xD800, 0xDF0F, 0xD800, 0xDF16,
+ 0xD800, 0xDF15, 0xD800, 0xDF14, 0xD800, 0xDF12, 0xD800, 0xDF10, 0xD800, 0xDF20,
+ 0xD800, 0xDF21,
+ 0x0000
+ },
+ // Greek
+ {
+ 0x03b5, 0x03bb, 0x03bb, 0x03b7, 0x03bd, 0x03b9, 0x03ba, 0x03ac
+ },
+ // Maltese
+ {
+ 0x0062, 0x006f, 0x006e, 0x0121, 0x0075, 0x0073, 0x0061, 0x0127,
+ 0x0127, 0x0061
+ },
+ // Russian
+ {
+ 0x043f, 0x043e, 0x0447, 0x0435, 0x043c, 0x0443, 0x0436, 0x0435,
+ 0x043e, 0x043d, 0x0438, 0x043d, 0x0435, 0x0433, 0x043e, 0x0432,
+ 0x043e, 0x0440, 0x044f, 0x0442, 0x043f, 0x043e, 0x0440, 0x0443,
+ 0x0441, 0x0441, 0x043a, 0x0438
+ },
+ {
+ 0xFB00, 0xFB01
+ }
+
+};
+
+static const char *asciiIn[] = {
+ "xn--egbpdaj6bu4bxfgehfvwxn",
+ "xn--ihqwcrb4cv8a8dqg056pqjye",
+ "xn--Proprostnemluvesky-uyb24dma41a",
+ "xn--4dbcagdahymbxekheh6e0a7fei0b",
+ "xn--i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd",
+ "xn--n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa",
+/* "xn--989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5jpsd879ccm6fea98c",*/
+ "xn--b1abfaaepdrnnbgefbaDotcwatmq2g4l",
+ "xn--PorqunopuedensimplementehablarenEspaol-fmd56a",
+ "xn--ihqwctvzc91f659drss3x8bo0yb",
+ "xn--TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g",
+ "xn--3B-ww4c5e180e575a65lsy2b",
+ "xn---with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n",
+ "xn--Hello-Another-Way--fc4qua05auwb3674vfr0b",
+ "xn--2-u9tlzr9756bt3uc0v",
+ "xn--MajiKoi5-783gue6qz075azm5e",
+ "xn--de-jg4avhby1noc0d",
+ "xn--d9juau41awczczp",
+ "XN--097CCDEKGHQJK",
+ "XN--db8CBHEJLGH4E0AL",
+ "xn--hxargifdar", // Greek
+ "xn--bonusaa-5bb1da", // Maltese
+ "xn--b1abfaaepdrnnbgefbadotcwatmq2g4l", // Russian (Cyrillic)
+ "fffi"
+};
+
+static const char *domainNames[] = {
+ "slip129-37-118-146.nc.us.ibm.net",
+ "saratoga.pe.utexas.edu",
+ "dial-120-45.ots.utexas.edu",
+ "woo-085.dorms.waller.net",
+ "hd30-049.hil.compuserve.com",
+ "pem203-31.pe.ttu.edu",
+ "56K-227.MaxTNT3.pdq.net",
+ "dial-36-2.ots.utexas.edu",
+ "slip129-37-23-152.ga.us.ibm.net",
+ "ts45ip119.cadvision.com",
+ "sdn-ts-004txaustP05.dialsprint.net",
+ "bar-tnt1s66.erols.com",
+ "101.st-louis-15.mo.dial-access.att.net",
+ "h92-245.Arco.COM",
+ "dial-13-2.ots.utexas.edu",
+ "net-redynet29.datamarkets.com.ar",
+ "ccs-shiva28.reacciun.net.ve",
+ "7.houston-11.tx.dial-access.att.net",
+ "ingw129-37-120-26.mo.us.ibm.net",
+ "dialup6.austintx.com",
+ "dns2.tpao.gov.tr",
+ "slip129-37-119-194.nc.us.ibm.net",
+ "cs7.dillons.co.uk.203.119.193.in-addr.arpa",
+ "swprd1.innovplace.saskatoon.sk.ca",
+ "bikini.bologna.maraut.it",
+ "node91.subnet159-198-79.baxter.com",
+ "cust19.max5.new-york.ny.ms.uu.net",
+ "balexander.slip.andrew.cmu.edu",
+ "pool029.max2.denver.co.dynip.alter.net",
+ "cust49.max9.new-york.ny.ms.uu.net",
+ "s61.abq-dialin2.hollyberry.com",
+ "\\u0917\\u0928\\u0947\\u0936.sanjose.ibm.com", //':'(0x003a) produces U_IDNA_STD3_ASCII_RULES_ERROR
+ "www.xn--vea.com",
+ // "www.\\u00E0\\u00B3\\u00AF.com",//' ' (0x0020) produces U_IDNA_STD3_ASCII_RULES_ERROR
+ "www.\\u00C2\\u00A4.com",
+ "www.\\u00C2\\u00A3.com",
+ // "\\u0025", //'%' (0x0025) produces U_IDNA_STD3_ASCII_RULES_ERROR
+ // "\\u005C\\u005C", //'\' (0x005C) produces U_IDNA_STD3_ASCII_RULES_ERROR
+ //"@",
+ //"\\u002F",
+ //"www.\\u0021.com",
+ //"www.\\u0024.com",
+ //"\\u003f",
+ // These yeild U_IDNA_PROHIBITED_ERROR
+ //"\\u00CF\\u0082.com",
+ //"\\u00CE\\u00B2\\u00C3\\u009Fss.com",
+ //"\\u00E2\\u0098\\u00BA.com",
+ "\\u00C3\\u00BC.com",
+
+};
+
+typedef struct ErrorCases ErrorCases;
+
+static const struct ErrorCases{
+
+ UChar unicode[100];
+ const char *ascii;
+ UErrorCode expected;
+ UBool useSTD3ASCIIRules;
+ UBool testToUnicode;
+ UBool testLabel;
+} errorCases[] = {
+ {
+
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, /* www. */
+ 0xC138, 0xACC4, 0xC758, 0xBAA8, 0xB4E0, 0xC0AC, 0xB78C, 0xB4E4, 0xC774,
+ 0x070F,/*prohibited*/
+ 0xD55C, 0xAD6D, 0xC5B4, 0xB97C, 0xC774, 0xD574, 0xD55C, 0xB2E4, 0xBA74,
+ 0x002e, 0x0063, 0x006f, 0x006d, /* com. */
+ 0x0000
+ },
+ "www.XN--8mb5595fsoa28orucya378bqre2tcwop06c5qbw82a1rffmae0361dea96b.com",
+ U_IDNA_PROHIBITED_ERROR,
+ FALSE, FALSE, TRUE
+ },
+
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, /* www. */
+ 0xC138, 0xACC4, 0xC758, 0xBAA8, 0xB4E0, 0xC0AC, 0xB78C, 0xB4E4, 0xC774,
+ 0x0221, 0x0234/*Unassigned code points*/,
+ 0x002e, 0x0063, 0x006f, 0x006d, /* com. */
+ 0x0000
+ },
+ "www.XN--6lA2Bz548Fj1GuA391Bf1Gb1N59Ab29A7iA.com",
+
+ U_IDNA_UNASSIGNED_ERROR,
+ FALSE, FALSE, TRUE
+ },
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, /* www. */
+ 0xC138, 0xACC4, 0xC758, 0xBAA8, 0xB4E0, 0xC0AC, 0xB78C, 0xB4E4, 0xC774,
+ 0x0644, 0x064A, 0x0647,/*Arabic code points. Cannot mix RTL with LTR*/
+ 0xD55C, 0xAD6D, 0xC5B4, 0xB97C, 0xC774, 0xD574, 0xD55C, 0xB2E4, 0xBA74,
+ 0x002e, 0x0063, 0x006f, 0x006d, /* com. */
+ 0x0000
+ },
+ "www.xn--ghBGI4851OiyA33VqrD6Az86C4qF83CtRv93D5xBk15AzfG0nAgA0578DeA71C.com",
+ U_IDNA_CHECK_BIDI_ERROR,
+ FALSE, FALSE, TRUE
+ },
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, /* www. */
+ /* labels cannot begin with an HYPHEN */
+ 0x002D, 0xACC4, 0xC758, 0xBAA8, 0xB4E0, 0xC0AC, 0xB78C, 0xB4E4, 0xC774,
+ 0x002E,
+ 0xD55C, 0xAD6D, 0xC5B4, 0xB97C, 0xC774, 0xD574, 0xD55C, 0xB2E4, 0xBA74,
+ 0x002e, 0x0063, 0x006f, 0x006d, /* com. */
+ 0x0000
+
+ },
+ "www.xn----b95Ew8SqA315Ao5FbuMlnNmhA.com",
+ U_IDNA_STD3_ASCII_RULES_ERROR,
+ TRUE, FALSE, FALSE
+ },
+ {
+ {
+ /* correct ACE-prefix followed by unicode */
+ 0x0077, 0x0077, 0x0077, 0x002e, /* www. */
+ 0x0078, 0x006e, 0x002d,0x002d, /* ACE Prefix */
+ 0x002D, 0xACC4, 0xC758, 0xBAA8, 0xB4E0, 0xC0AC, 0xB78C, 0xB4E4, 0xC774,
+ 0x002D,
+ 0xD55C, 0xAD6D, 0xC5B4, 0xB97C, 0xC774, 0xD574, 0xD55C, 0xB2E4, 0xBA74,
+ 0x002e, 0x0063, 0x006f, 0x006d, /* com. */
+ 0x0000
+
+ },
+ /* wrong ACE-prefix followed by valid ACE-encoded ASCII */
+ "www.XY-----b91I0V65S96C2A355Cw1E5yCeQr19CsnP1mFfmAE0361DeA96B.com",
+ U_IDNA_ACE_PREFIX_ERROR,
+ FALSE, FALSE, FALSE
+ },
+ /* cannot verify U_IDNA_VERIFICATION_ERROR */
+
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, /* www. */
+ 0xC138, 0xACC4, 0xC758, 0xBAA8, 0xB4E0, 0xC0AC, 0xB78C, 0xB4E4, 0xC774,
+ 0xD55C, 0xAD6D, 0xC5B4, 0xB97C, 0xC774, 0xD574, 0xD55C, 0xB2E4, 0xBA74,
+ 0xC5BC, 0xB9C8, 0xB098, 0xC88B, 0xC744, 0xAE4C,
+ 0x002e, 0x0063, 0x006f, 0x006d, /* com. */
+ 0x0000
+ },
+ "www.xn--989AoMsVi5E83Db1D2A355Cv1E0vAk1DwRv93D5xBh15A0Dt30A5JpSD879Ccm6FeA98C.com",
+ U_IDNA_LABEL_TOO_LONG_ERROR,
+ FALSE, FALSE, TRUE
+ },
+
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, /* www. */
+ 0x0030, 0x0644, 0x064A, 0x0647, 0x0031, /* Arabic code points squashed between EN codepoints */
+ 0x002e, 0x0063, 0x006f, 0x006d, /* com. */
+ 0x0000
+ },
+ "www.xn--01-tvdmo.com",
+ U_IDNA_CHECK_BIDI_ERROR,
+ FALSE, FALSE, TRUE
+ },
+
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, // www.
+ 0x206C, 0x0644, 0x064A, 0x0647, 0x206D, // Arabic code points squashed between BN codepoints
+ 0x002e, 0x0063, 0x006f, 0x006d, // com.
+ 0x0000
+ },
+ "www.XN--ghbgi278xia.com",
+ U_IDNA_PROHIBITED_ERROR,
+ FALSE, FALSE, TRUE
+ },
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, // www.
+ 0x002D, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, // HYPHEN at the start of label
+ 0x002e, 0x0063, 0x006f, 0x006d, // com.
+ 0x0000
+ },
+ "www.-abcde.com",
+ U_IDNA_STD3_ASCII_RULES_ERROR,
+ TRUE, FALSE, FALSE
+ },
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, // www.
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045,0x002D, // HYPHEN at the end of the label
+ 0x002e, 0x0063, 0x006f, 0x006d, // com.
+ 0x0000
+ },
+ "www.abcde-.com",
+ U_IDNA_STD3_ASCII_RULES_ERROR,
+ TRUE, FALSE, FALSE
+ },
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, // www.
+ 0x0041, 0x0042, 0x0043, 0x0044, 0x0045,0x0040, // Containing non LDH code point
+ 0x002e, 0x0063, 0x006f, 0x006d, // com.
+ 0x0000
+ },
+ "www.abcde@.com",
+ U_IDNA_STD3_ASCII_RULES_ERROR,
+ TRUE, FALSE, FALSE
+ },
+ {
+ {
+ 0x0077, 0x0077, 0x0077, 0x002e, // www.
+ // zero length label
+ 0x002e, 0x0063, 0x006f, 0x006d, // com.
+ 0x0000
+ },
+ "www..com",
+ U_IDNA_ZERO_LENGTH_LABEL_ERROR,
+ TRUE, FALSE, FALSE
+ },
+ {
+ {0},
+ NULL,
+ U_ILLEGAL_ARGUMENT_ERROR,
+ TRUE, TRUE, FALSE
+ }
+};
+
+
+
+
+#define MAX_DEST_SIZE 300
+
+void TestIDNA::debug(const UChar* src, int32_t srcLength, int32_t options){
+ UParseError parseError;
+ UErrorCode transStatus = U_ZERO_ERROR;
+ UErrorCode prepStatus = U_ZERO_ERROR;
+ NamePrepTransform* trans = NamePrepTransform::createInstance(parseError,transStatus);
+ int32_t prepOptions = (((options & UIDNA_ALLOW_UNASSIGNED) != 0) ? USPREP_ALLOW_UNASSIGNED: 0);
+ UStringPrepProfile* prep = usprep_open(NULL,"uidna",&prepStatus);
+ UChar *transOut=NULL, *prepOut=NULL;
+ int32_t transOutLength=0, prepOutLength=0;
+
+
+ transOutLength = trans->process(src,srcLength,transOut, 0, prepOptions>0, &parseError, transStatus);
+ if( transStatus == U_BUFFER_OVERFLOW_ERROR){
+ transStatus = U_ZERO_ERROR;
+ transOut = (UChar*) malloc(U_SIZEOF_UCHAR * transOutLength);
+ transOutLength = trans->process(src,srcLength,transOut, transOutLength, prepOptions>0, &parseError, transStatus);
+ }
+
+ prepOutLength = usprep_prepare(prep, src, srcLength, prepOut, 0, prepOptions, &parseError, &prepStatus);
+
+ if( prepStatus == U_BUFFER_OVERFLOW_ERROR){
+ prepStatus = U_ZERO_ERROR;
+ prepOut = (UChar*) malloc(U_SIZEOF_UCHAR * prepOutLength);
+ prepOutLength = usprep_prepare(prep, src, srcLength, prepOut, prepOutLength, prepOptions, &parseError, &prepStatus);
+ }
+
+ if(UnicodeString(transOut,transOutLength)!= UnicodeString(prepOut, prepOutLength)){
+ errln("Failed. Expected: " + prettify(UnicodeString(transOut, transOutLength))
+ + " Got: " + prettify(UnicodeString(prepOut,prepOutLength)));
+ }
+ free(transOut);
+ free(prepOut);
+ delete trans;
+
+}
+
+void TestIDNA::testAPI(const UChar* src, const UChar* expected, const char* testName,
+ UBool useSTD3ASCIIRules,UErrorCode expectedStatus,
+ UBool doCompare, UBool testUnassigned, TestFunc func, UBool testSTD3ASCIIRules){
+
+ UErrorCode status = U_ZERO_ERROR;
+ UChar destStack[MAX_DEST_SIZE];
+ int32_t destLen = 0;
+ UChar* dest = NULL;
+ int32_t expectedLen = (expected != NULL) ? u_strlen(expected) : 0;
+ int32_t options = (useSTD3ASCIIRules == TRUE) ? UIDNA_USE_STD3_RULES : UIDNA_DEFAULT;
+ UParseError parseError;
+ int32_t tSrcLen = 0;
+ UChar* tSrc = NULL;
+
+ if(src != NULL){
+ tSrcLen = u_strlen(src);
+ tSrc =(UChar*) malloc( U_SIZEOF_UCHAR * tSrcLen );
+ memcpy(tSrc,src,tSrcLen * U_SIZEOF_UCHAR);
+ }
+
+ // test null-terminated source and return value of number of UChars required
+ destLen = func(src,-1,NULL,0,options, &parseError , &status);
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ status = U_ZERO_ERROR; // reset error code
+ if(destLen+1 < MAX_DEST_SIZE){
+ dest = destStack;
+ destLen = func(src,-1,dest,destLen+1,options, &parseError, &status);
+ // TODO : compare output with expected
+ if(U_SUCCESS(status) && expectedStatus != U_IDNA_STD3_ASCII_RULES_ERROR&& (doCompare==TRUE) && u_strCaseCompare(dest,destLen, expected,expectedLen,0,&status)!=0){
+ errln("Did not get the expected result for "+UnicodeString(testName) +" null terminated source. Expected : "
+ + prettify(UnicodeString(expected,expectedLen))
+ + " Got: " + prettify(UnicodeString(dest,destLen))
+ );
+ }
+ }else{
+ errln( "%s null terminated source failed. Requires destCapacity > 300\n",testName);
+ }
+ }
+
+ if(status != expectedStatus){
+ errln( "Did not get the expected error for "+
+ UnicodeString(testName)+
+ " null terminated source. Expected: " +UnicodeString(u_errorName(expectedStatus))
+ + " Got: "+ UnicodeString(u_errorName(status))
+ + " Source: " + prettify(UnicodeString(src))
+ );
+ free(tSrc);
+ return;
+ }
+ if(testUnassigned ){
+ status = U_ZERO_ERROR;
+ destLen = func(src,-1,NULL,0,options | UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ status = U_ZERO_ERROR; // reset error code
+ if(destLen+1 < MAX_DEST_SIZE){
+ dest = destStack;
+ destLen = func(src,-1,dest,destLen+1,options | UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+ // TODO : compare output with expected
+ if(U_SUCCESS(status) && (doCompare==TRUE) && u_strCaseCompare(dest,destLen, expected,expectedLen,0,&status)!=0){
+ //errln("Did not get the expected result for %s null terminated source with both options set.\n",testName);
+ errln("Did not get the expected result for "+UnicodeString(testName) +
+ " null terminated source "+ prettify(src) +
+ " with both options set. Expected: "+ prettify(UnicodeString(expected,expectedLen))+
+ "Got: " + prettify(UnicodeString(dest,destLen)));
+
+ debug(src,-1,options | UIDNA_ALLOW_UNASSIGNED);
+
+ }
+ }else{
+ errln( "%s null terminated source failed. Requires destCapacity > 300\n",testName);
+ }
+ }
+ //testing query string
+ if(status != expectedStatus && expectedStatus != U_IDNA_UNASSIGNED_ERROR){
+ errln( "Did not get the expected error for "+
+ UnicodeString(testName)+
+ " null terminated source with options set. Expected: " +UnicodeString(u_errorName(expectedStatus))
+ + " Got: "+ UnicodeString(u_errorName(status))
+ + " Source: " + prettify(UnicodeString(src))
+ );
+ }
+ }
+
+ status = U_ZERO_ERROR;
+
+ // test source with lengthand return value of number of UChars required
+ destLen = func(tSrc, tSrcLen, NULL,0,options, &parseError, &status);
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ status = U_ZERO_ERROR; // reset error code
+ if(destLen+1 < MAX_DEST_SIZE){
+ dest = destStack;
+ destLen = func(src,u_strlen(src),dest,destLen+1,options, &parseError, &status);
+ // TODO : compare output with expected
+ if(U_SUCCESS(status) && (doCompare==TRUE) && u_strCaseCompare(dest,destLen, expected,expectedLen,0,&status)!=0){
+ errln("Did not get the expected result for %s with source length.\n",testName);
+ }
+ }else{
+ errln( "%s with source length failed. Requires destCapacity > 300\n",testName);
+ }
+ }
+
+ if(status != expectedStatus){
+ errln( "Did not get the expected error for "+
+ UnicodeString(testName)+
+ " with source length. Expected: " +UnicodeString(u_errorName(expectedStatus))
+ + " Got: "+ UnicodeString(u_errorName(status))
+ + " Source: " + prettify(UnicodeString(src))
+ );
+ }
+ if(testUnassigned){
+ status = U_ZERO_ERROR;
+
+ destLen = func(tSrc,tSrcLen,NULL,0,options | UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ status = U_ZERO_ERROR; // reset error code
+ if(destLen+1 < MAX_DEST_SIZE){
+ dest = destStack;
+ destLen = func(src,u_strlen(src),dest,destLen+1,options | UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+ // TODO : compare output with expected
+ if(U_SUCCESS(status) && (doCompare==TRUE) && u_strCaseCompare(dest,destLen, expected,expectedLen,0,&status)!=0){
+ errln("Did not get the expected result for %s with source length and both options set.\n",testName);
+ }
+ }else{
+ errln( "%s with source length failed. Requires destCapacity > 300\n",testName);
+ }
+ }
+ //testing query string
+ if(status != expectedStatus && expectedStatus != U_IDNA_UNASSIGNED_ERROR){
+ errln( "Did not get the expected error for "+
+ UnicodeString(testName)+
+ " with source length and options set. Expected: " +UnicodeString(u_errorName(expectedStatus))
+ + " Got: "+ UnicodeString(u_errorName(status))
+ + " Source: " + prettify(UnicodeString(src))
+ );
+ }
+ }
+
+ status = U_ZERO_ERROR;
+ if(testSTD3ASCIIRules==TRUE){
+ destLen = func(src,-1,NULL,0,options | UIDNA_USE_STD3_RULES, &parseError, &status);
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ status = U_ZERO_ERROR; // reset error code
+ if(destLen+1 < MAX_DEST_SIZE){
+ dest = destStack;
+ destLen = func(src,-1,dest,destLen+1,options | UIDNA_USE_STD3_RULES, &parseError, &status);
+ // TODO : compare output with expected
+ if(U_SUCCESS(status) && (doCompare==TRUE) && u_strCaseCompare(dest,destLen, expected,expectedLen,0,&status)!=0){
+ //errln("Did not get the expected result for %s null terminated source with both options set.\n",testName);
+ errln("Did not get the expected result for "+UnicodeString(testName) +" null terminated source with both options set. Expected: "+ prettify(UnicodeString(expected,expectedLen)));
+
+ }
+ }else{
+ errln( "%s null terminated source failed. Requires destCapacity > 300\n",testName);
+ }
+ }
+ //testing query string
+ if(status != expectedStatus){
+ errln( "Did not get the expected error for "+
+ UnicodeString(testName)+
+ " null terminated source with options set. Expected: " +UnicodeString(u_errorName(expectedStatus))
+ + " Got: "+ UnicodeString(u_errorName(status))
+ + " Source: " + prettify(UnicodeString(src))
+ );
+ }
+
+ status = U_ZERO_ERROR;
+
+ destLen = func(tSrc,tSrcLen,NULL,0,options | UIDNA_USE_STD3_RULES, &parseError, &status);
+
+ if(status == U_BUFFER_OVERFLOW_ERROR){
+ status = U_ZERO_ERROR; // reset error code
+ if(destLen+1 < MAX_DEST_SIZE){
+ dest = destStack;
+ destLen = func(src,u_strlen(src),dest,destLen+1,options | UIDNA_USE_STD3_RULES, &parseError, &status);
+ // TODO : compare output with expected
+ if(U_SUCCESS(status) && (doCompare==TRUE) && u_strCaseCompare(dest,destLen, expected,expectedLen,0,&status)!=0){
+ errln("Did not get the expected result for %s with source length and both options set.\n",testName);
+ }
+ }else{
+ errln( "%s with source length failed. Requires destCapacity > 300\n",testName);
+ }
+ }
+ //testing query string
+ if(status != expectedStatus && expectedStatus != U_IDNA_UNASSIGNED_ERROR){
+ errln( "Did not get the expected error for "+
+ UnicodeString(testName)+
+ " with source length and options set. Expected: " +UnicodeString(u_errorName(expectedStatus))
+ + " Got: "+ UnicodeString(u_errorName(status))
+ + " Source: " + prettify(UnicodeString(src))
+ );
+ }
+ }
+ free(tSrc);
+}
+
+void TestIDNA::testCompare(const UChar* s1, int32_t s1Len,
+ const UChar* s2, int32_t s2Len,
+ const char* testName, CompareFunc func,
+ UBool isEqual){
+
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t retVal = func(s1,-1,s2,-1,UIDNA_DEFAULT,&status);
+
+ if(isEqual==TRUE && retVal !=0){
+ errln("Did not get the expected result for %s with null termniated strings.\n",testName);
+ }
+ if(U_FAILURE(status)){
+ errln( "%s null terminated source failed. Error: %s\n", testName,u_errorName(status));
+ }
+
+ status = U_ZERO_ERROR;
+ retVal = func(s1,-1,s2,-1,UIDNA_ALLOW_UNASSIGNED,&status);
+
+ if(isEqual==TRUE && retVal !=0){
+ errln("Did not get the expected result for %s with null termniated strings with options set.\n", testName);
+ }
+ if(U_FAILURE(status)){
+ errln( "%s null terminated source and options set failed. Error: %s\n",testName, u_errorName(status));
+ }
+
+ status = U_ZERO_ERROR;
+ retVal = func(s1,s1Len,s2,s2Len,UIDNA_DEFAULT,&status);
+
+ if(isEqual==TRUE && retVal !=0){
+ errln("Did not get the expected result for %s with string length.\n",testName);
+ }
+ if(U_FAILURE(status)){
+ errln( "%s with string length. Error: %s\n",testName, u_errorName(status));
+ }
+
+ status = U_ZERO_ERROR;
+ retVal = func(s1,s1Len,s2,s2Len,UIDNA_ALLOW_UNASSIGNED,&status);
+
+ if(isEqual==TRUE && retVal !=0){
+ errln("Did not get the expected result for %s with string length and options set.\n",testName);
+ }
+ if(U_FAILURE(status)){
+ errln( "%s with string length and options set. Error: %s\n", u_errorName(status), testName);
+ }
+}
+
+void TestIDNA::testToASCII(const char* testName, TestFunc func){
+
+ int32_t i;
+ UChar buf[MAX_DEST_SIZE];
+
+ for(i=0;i< (int32_t)(sizeof(unicodeIn)/sizeof(unicodeIn[0])); i++){
+ u_charsToUChars(asciiIn[i],buf, (int32_t)(strlen(asciiIn[i])+1));
+ testAPI(unicodeIn[i], buf,testName, FALSE,U_ZERO_ERROR, TRUE, TRUE, func);
+
+ }
+}
+
+void TestIDNA::testToUnicode(const char* testName, TestFunc func){
+
+ int32_t i;
+ UChar buf[MAX_DEST_SIZE];
+
+ for(i=0;i< (int32_t)(sizeof(asciiIn)/sizeof(asciiIn[0])); i++){
+ u_charsToUChars(asciiIn[i],buf, (int32_t)(strlen(asciiIn[i])+1));
+ testAPI(buf,unicodeIn[i],testName,FALSE,U_ZERO_ERROR, TRUE, TRUE, func);
+ }
+}
+
+
+void TestIDNA::testIDNToUnicode(const char* testName, TestFunc func){
+ int32_t i;
+ UChar buf[MAX_DEST_SIZE];
+ UChar expected[MAX_DEST_SIZE];
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t bufLen = 0;
+ UParseError parseError;
+ for(i=0;i< (int32_t)(sizeof(domainNames)/sizeof(domainNames[0])); i++){
+ bufLen = (int32_t)strlen(domainNames[i]);
+ bufLen = u_unescape(domainNames[i],buf, bufLen+1);
+ func(buf,bufLen,expected,MAX_DEST_SIZE, UIDNA_ALLOW_UNASSIGNED, &parseError,&status);
+ if(U_FAILURE(status)){
+ errln( "%s failed to convert domainNames[%i].Error: %s \n",testName, i, u_errorName(status));
+ break;
+ }
+ testAPI(buf,expected,testName,FALSE,U_ZERO_ERROR, TRUE, TRUE, func);
+ //test toUnicode with all labels in the string
+ testAPI(buf,expected,testName, FALSE,U_ZERO_ERROR, TRUE, TRUE, func);
+ if(U_FAILURE(status)){
+ errln( "%s failed to convert domainNames[%i].Error: %s \n",testName,i, u_errorName(status));
+ break;
+ }
+ }
+
+}
+
+void TestIDNA::testIDNToASCII(const char* testName, TestFunc func){
+ int32_t i;
+ UChar buf[MAX_DEST_SIZE];
+ UChar expected[MAX_DEST_SIZE];
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t bufLen = 0;
+ UParseError parseError;
+ for(i=0;i< (int32_t)(sizeof(domainNames)/sizeof(domainNames[0])); i++){
+ bufLen = (int32_t)strlen(domainNames[i]);
+ bufLen = u_unescape(domainNames[i],buf, bufLen+1);
+ func(buf,bufLen,expected,MAX_DEST_SIZE, UIDNA_ALLOW_UNASSIGNED, &parseError,&status);
+ if(U_FAILURE(status)){
+ errln( "%s failed to convert domainNames[%i].Error: %s \n",testName,i, u_errorName(status));
+ break;
+ }
+ testAPI(buf,expected,testName, FALSE,U_ZERO_ERROR, TRUE, TRUE, func);
+ //test toASCII with all labels in the string
+ testAPI(buf,expected,testName, FALSE,U_ZERO_ERROR, FALSE, TRUE, func);
+ if(U_FAILURE(status)){
+ errln( "%s failed to convert domainNames[%i].Error: %s \n",testName,i, u_errorName(status));
+ break;
+ }
+ }
+
+}
+
+void TestIDNA::testCompare(const char* testName, CompareFunc func){
+ int32_t i;
+
+
+ UChar www[] = {0x0057, 0x0057, 0x0057, 0x002E, 0x0000};
+ UChar com[] = {0x002E, 0x0043, 0x004F, 0x004D, 0x0000};
+ UChar buf[MAX_DEST_SIZE]={0x0057, 0x0057, 0x0057, 0x002E, 0x0000};
+
+ UnicodeString source(www), uni0(www),uni1(www), ascii0(www), ascii1(www);
+
+ uni0.append(unicodeIn[0]);
+ uni0.append(com);
+ uni0.append((UChar)0x0000);
+
+ uni1.append(unicodeIn[1]);
+ uni1.append(com);
+ uni1.append((UChar)0x0000);
+
+ ascii0.append(asciiIn[0]);
+ ascii0.append(com);
+ ascii0.append((UChar)0x0000);
+
+ ascii1.append(asciiIn[1]);
+ ascii1.append(com);
+ ascii1.append((UChar)0x0000);
+
+ for(i=0;i< (int32_t)(sizeof(unicodeIn)/sizeof(unicodeIn[0])); i++){
+
+ u_charsToUChars(asciiIn[i],buf+4, (int32_t)(strlen(asciiIn[i])+1));
+ u_strcat(buf,com);
+
+ // for every entry in unicodeIn array
+ // prepend www. and append .com
+ source.truncate(4);
+ source.append(unicodeIn[i]);
+ source.append(com);
+ source.append((UChar)0x0000);
+ // a) compare it with itself
+ const UChar* src = source.getBuffer();
+ int32_t srcLen = u_strlen(src); //subtract null
+
+ testCompare(src,srcLen,src,srcLen,testName, func, TRUE);
+
+ // b) compare it with asciiIn equivalent
+ testCompare(src,srcLen,buf,u_strlen(buf),testName, func,TRUE);
+
+ // c) compare it with unicodeIn not equivalent
+ if(i==0){
+ testCompare(src,srcLen,uni1.getBuffer(),uni1.length()-1,testName, func,FALSE);
+ }else{
+ testCompare(src,srcLen,uni0.getBuffer(),uni0.length()-1,testName, func,FALSE);
+ }
+ // d) compare it with asciiIn not equivalent
+ if(i==0){
+ testCompare(src,srcLen,ascii1.getBuffer(),ascii1.length()-1,testName, func,FALSE);
+ }else{
+ testCompare(src,srcLen,ascii0.getBuffer(),ascii0.length()-1,testName, func,FALSE);
+ }
+
+ }
+}
+
+#if 0
+
+static int32_t
+getNextSeperator(UChar *src,int32_t srcLength,
+ UChar **limit){
+ if(srcLength == -1){
+ int32_t i;
+ for(i=0 ; ;i++){
+ if(src[i] == 0){
+ *limit = src + i; // point to null
+ return i;
+ }
+ if(src[i]==0x002e){
+ *limit = src + (i+1); // go past the delimiter
+ return i;
+ }
+ }
+ // we have not found the delimiter
+ if(i==srcLength){
+ *limit = src+srcLength;
+ }
+ return i;
+ }else{
+ int32_t i;
+ for(i=0;i<srcLength;i++){
+ if(src[i]==0x002e){
+ *limit = src + (i+1); // go past the delimiter
+ return i;
+ }
+ }
+ // we have not found the delimiter
+ if(i==srcLength){
+ *limit = src+srcLength;
+ }
+ return i;
+ }
+}
+
+void printPunycodeOutput(){
+
+ UChar dest[MAX_DEST_SIZE];
+ int32_t destCapacity=MAX_DEST_SIZE;
+ UChar* start;
+ UChar* limit;
+ int32_t labelLen=0;
+ UBool caseFlags[MAX_DEST_SIZE];
+
+ for(int32_t i=0;i< sizeof(errorCases)/sizeof(errorCases[0]);i++){
+ ErrorCases errorCase = errorCases[i];
+ UErrorCode status = U_ZERO_ERROR;
+ start = errorCase.unicode;
+ int32_t srcLen = u_strlen(start);
+ labelLen = getNextSeperator(start,srcLen,&limit);
+ start = limit;
+ labelLen=getNextSeperator(start,srcLen-labelLen,&limit);
+ int32_t destLen = u_strToPunycode(dest,destCapacity,start,labelLen,caseFlags, &status);
+ if(U_FAILURE(status)){
+ printf("u_strToPunycode failed for index %i\n",i);
+ continue;
+ }
+ for(int32_t j=0; j<destLen; j++){
+ printf("%c",(char)dest[j]);
+ }
+ printf("\n");
+ }
+}
+#endif
+
+void TestIDNA::testErrorCases(const char* IDNToASCIIName, TestFunc IDNToASCII,
+ const char* IDNToUnicodeName, TestFunc IDNToUnicode){
+ UChar buf[MAX_DEST_SIZE];
+ int32_t bufLen=0;
+
+ for(int32_t i=0;i< (int32_t)(sizeof(errorCases)/sizeof(errorCases[0]));i++){
+ ErrorCases errorCase = errorCases[i];
+ UChar* src =NULL;
+ if(errorCase.ascii != NULL){
+ bufLen = (int32_t)strlen(errorCase.ascii);
+ u_charsToUChars(errorCase.ascii,buf, bufLen+1);
+ }else{
+ bufLen = 1 ;
+ memset(buf,0,U_SIZEOF_UCHAR*MAX_DEST_SIZE);
+ }
+
+ if(errorCase.unicode[0]!=0){
+ src = errorCase.unicode;
+ }
+ // test toASCII
+ testAPI(src,buf,
+ IDNToASCIIName, errorCase.useSTD3ASCIIRules,
+ errorCase.expected, TRUE, TRUE, IDNToASCII);
+ if(errorCase.testLabel ==TRUE){
+ testAPI(src,buf,
+ IDNToASCIIName, errorCase.useSTD3ASCIIRules,
+ errorCase.expected, FALSE,TRUE, IDNToASCII);
+ }
+ if(errorCase.testToUnicode ==TRUE){
+ testAPI((src==NULL)? NULL : buf,src,
+ IDNToUnicodeName, errorCase.useSTD3ASCIIRules,
+ errorCase.expected, TRUE, TRUE, IDNToUnicode);
+ }
+
+ }
+
+}
+/*
+void TestIDNA::testConformance(const char* toASCIIName, TestFunc toASCII,
+ const char* IDNToASCIIName, TestFunc IDNToASCII,
+ const char* IDNToUnicodeName, TestFunc IDNToUnicode,
+ const char* toUnicodeName, TestFunc toUnicode){
+ UChar src[MAX_DEST_SIZE];
+ int32_t srcLen=0;
+ UChar expected[MAX_DEST_SIZE];
+ int32_t expectedLen = 0;
+ for(int32_t i=0;i< (int32_t)(sizeof(conformanceTestCases)/sizeof(conformanceTestCases[0]));i++){
+ const char* utf8Chars1 = conformanceTestCases[i].in;
+ int32_t utf8Chars1Len = (int32_t)strlen(utf8Chars1);
+ const char* utf8Chars2 = conformanceTestCases[i].out;
+ int32_t utf8Chars2Len = (utf8Chars2 == NULL) ? 0 : (int32_t)strlen(utf8Chars2);
+
+ UErrorCode status = U_ZERO_ERROR;
+ u_strFromUTF8(src,MAX_DEST_SIZE,&srcLen,utf8Chars1,utf8Chars1Len,&status);
+ if(U_FAILURE(status)){
+ errln(UnicodeString("Conversion of UTF8 source in conformanceTestCases[") + i +UnicodeString( "].in ( ")+prettify(utf8Chars1) +UnicodeString(" ) failed. Error: ")+ UnicodeString(u_errorName(status)));
+ continue;
+ }
+ if(utf8Chars2 != NULL){
+ u_strFromUTF8(expected,MAX_DEST_SIZE,&expectedLen,utf8Chars2,utf8Chars2Len, &status);
+ if(U_FAILURE(status)){
+ errln(UnicodeString("Conversion of UTF8 source in conformanceTestCases[") + i +UnicodeString( "].in ( ")+prettify(utf8Chars1) +UnicodeString(" ) failed. Error: ")+ UnicodeString(u_errorName(status)));
+ continue;
+ }
+ }
+
+ if(conformanceTestCases[i].expectedStatus != U_ZERO_ERROR){
+ // test toASCII
+ testAPI(src,expected,
+ IDNToASCIIName, FALSE,
+ conformanceTestCases[i].expectedStatus,
+ TRUE,
+ (conformanceTestCases[i].expectedStatus != U_IDNA_UNASSIGNED_ERROR),
+ IDNToASCII);
+
+ testAPI(src,expected,
+ toASCIIName, FALSE,
+ conformanceTestCases[i].expectedStatus, TRUE,
+ (conformanceTestCases[i].expectedStatus != U_IDNA_UNASSIGNED_ERROR),
+ toASCII);
+ }
+
+ testAPI(src,src,
+ IDNToUnicodeName, FALSE,
+ conformanceTestCases[i].expectedStatus, TRUE, TRUE, IDNToUnicode);
+ testAPI(src,src,
+ toUnicodeName, FALSE,
+ conformanceTestCases[i].expectedStatus, TRUE, TRUE, toUnicode);
+
+ }
+
+}
+*/
+// test and ascertain
+// func(func(func(src))) == func(src)
+void TestIDNA::testChaining(const UChar* src,int32_t numIterations,const char* testName,
+ UBool useSTD3ASCIIRules, UBool caseInsensitive, TestFunc func){
+ UChar even[MAX_DEST_SIZE];
+ UChar odd[MAX_DEST_SIZE];
+ UChar expected[MAX_DEST_SIZE];
+ int32_t i=0,evenLen=0,oddLen=0,expectedLen=0;
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t srcLen = u_strlen(src);
+ int32_t options = (useSTD3ASCIIRules == TRUE) ? UIDNA_USE_STD3_RULES : UIDNA_DEFAULT;
+ UParseError parseError;
+
+ // test null-terminated source
+ expectedLen = func(src,-1,expected,MAX_DEST_SIZE, options, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s null terminated source failed. Error: %s\n",testName, u_errorName(status));
+ }
+ memcpy(odd,expected,(expectedLen+1) * U_SIZEOF_UCHAR);
+ memcpy(even,expected,(expectedLen+1) * U_SIZEOF_UCHAR);
+ for(;i<=numIterations; i++){
+ if((i%2) ==0){
+ evenLen = func(odd,-1,even,MAX_DEST_SIZE,options, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s null terminated source failed\n",testName);
+ break;
+ }
+ }else{
+ oddLen = func(even,-1,odd,MAX_DEST_SIZE,options, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s null terminated source failed\n",testName);
+ break;
+ }
+ }
+ }
+ if(caseInsensitive ==TRUE){
+ if( u_strCaseCompare(even,evenLen, expected,expectedLen, 0, &status) !=0 ||
+ u_strCaseCompare(odd,oddLen, expected,expectedLen, 0, &status) !=0 ){
+
+ errln("Chaining for %s null terminated source failed\n",testName);
+ }
+ }else{
+ if( u_strncmp(even,expected,expectedLen) != 0 ||
+ u_strncmp(odd,expected,expectedLen) !=0 ){
+
+ errln("Chaining for %s null terminated source failed\n",testName);
+ }
+ }
+
+ // test null-terminated source
+ status = U_ZERO_ERROR;
+ expectedLen = func(src,-1,expected,MAX_DEST_SIZE,options|UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s null terminated source with options set failed. Error: %s\n",testName, u_errorName(status));
+ }
+ memcpy(odd,expected,(expectedLen+1) * U_SIZEOF_UCHAR);
+ memcpy(even,expected,(expectedLen+1) * U_SIZEOF_UCHAR);
+ for(;i<=numIterations; i++){
+ if((i%2) ==0){
+ evenLen = func(odd,-1,even,MAX_DEST_SIZE,options|UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s null terminated source with options set failed\n",testName);
+ break;
+ }
+ }else{
+ oddLen = func(even,-1,odd,MAX_DEST_SIZE,options|UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s null terminated source with options set failed\n",testName);
+ break;
+ }
+ }
+ }
+ if(caseInsensitive ==TRUE){
+ if( u_strCaseCompare(even,evenLen, expected,expectedLen, 0, &status) !=0 ||
+ u_strCaseCompare(odd,oddLen, expected,expectedLen, 0, &status) !=0 ){
+
+ errln("Chaining for %s null terminated source with options set failed\n",testName);
+ }
+ }else{
+ if( u_strncmp(even,expected,expectedLen) != 0 ||
+ u_strncmp(odd,expected,expectedLen) !=0 ){
+
+ errln("Chaining for %s null terminated source with options set failed\n",testName);
+ }
+ }
+
+
+ // test source with length
+ status = U_ZERO_ERROR;
+ expectedLen = func(src,srcLen,expected,MAX_DEST_SIZE,options, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s null terminated source failed. Error: %s\n",testName, u_errorName(status));
+ }
+ memcpy(odd,expected,(expectedLen+1) * U_SIZEOF_UCHAR);
+ memcpy(even,expected,(expectedLen+1) * U_SIZEOF_UCHAR);
+ for(;i<=numIterations; i++){
+ if((i%2) ==0){
+ evenLen = func(odd,oddLen,even,MAX_DEST_SIZE,options, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s source with source length failed\n",testName);
+ break;
+ }
+ }else{
+ oddLen = func(even,evenLen,odd,MAX_DEST_SIZE,options, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s source with source length failed\n",testName);
+ break;
+ }
+ }
+ }
+ if(caseInsensitive ==TRUE){
+ if( u_strCaseCompare(even,evenLen, expected,expectedLen, 0, &status) !=0 ||
+ u_strCaseCompare(odd,oddLen, expected,expectedLen, 0, &status) !=0 ){
+
+ errln("Chaining for %s source with source length failed\n",testName);
+ }
+ }else{
+ if( u_strncmp(even,expected,expectedLen) != 0 ||
+ u_strncmp(odd,expected,expectedLen) !=0 ){
+
+ errln("Chaining for %s source with source length failed\n",testName);
+ }
+ }
+ status = U_ZERO_ERROR;
+ expectedLen = func(src,srcLen,expected,MAX_DEST_SIZE,options|UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s null terminated source with options set failed. Error: %s\n",testName, u_errorName(status));
+ }
+ memcpy(odd,expected,(expectedLen+1) * U_SIZEOF_UCHAR);
+ memcpy(even,expected,(expectedLen+1) * U_SIZEOF_UCHAR);
+ for(;i<=numIterations; i++){
+ if((i%2) ==0){
+ evenLen = func(odd,oddLen,even,MAX_DEST_SIZE,options|UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s source with source length and options set failed\n",testName);
+ break;
+ }
+ }else{
+ oddLen = func(even,evenLen,odd,MAX_DEST_SIZE,options|UIDNA_ALLOW_UNASSIGNED, &parseError, &status);
+ if(U_FAILURE(status)){
+ errln("%s source with source length and options set failed\n",testName);
+ break;
+ }
+ }
+ }
+ if(caseInsensitive ==TRUE){
+ if( u_strCaseCompare(even,evenLen, expected,expectedLen, 0, &status) !=0 ||
+ u_strCaseCompare(odd,oddLen, expected,expectedLen, 0, &status) !=0 ){
+
+ errln("Chaining for %s source with source length and options set failed\n",testName);
+ }
+ }else{
+ if( u_strncmp(even,expected,expectedLen) != 0 ||
+ u_strncmp(odd,expected,expectedLen) !=0 ){
+
+ errln("Chaining for %s source with source length and options set failed\n",testName);
+ }
+ }
+}
+void TestIDNA::testChaining(const char* toASCIIName, TestFunc toASCII,
+ const char* toUnicodeName, TestFunc toUnicode){
+ int32_t i;
+ UChar buf[MAX_DEST_SIZE];
+
+ for(i=0;i< (int32_t)(sizeof(asciiIn)/sizeof(asciiIn[0])); i++){
+ u_charsToUChars(asciiIn[i],buf, (int32_t)(strlen(asciiIn[i])+1));
+ testChaining(buf,5,toUnicodeName, FALSE, FALSE, toUnicode);
+ }
+ for(i=0;i< (int32_t)(sizeof(unicodeIn)/sizeof(unicodeIn[0])); i++){
+ testChaining(unicodeIn[i], 5,toASCIIName, FALSE, TRUE, toASCII);
+ }
+}
+
+
+void TestIDNA::testRootLabelSeparator(const char* testName, CompareFunc func,
+ const char* IDNToASCIIName, TestFunc IDNToASCII,
+ const char* IDNToUnicodeName, TestFunc IDNToUnicode){
+ int32_t i;
+
+
+ UChar www[] = {0x0057, 0x0057, 0x0057, 0x002E, 0x0000};
+ UChar com[] = {0x002E, 0x0043, 0x004F, 0x004D, 0x002E, /* root label separator */0x0000};
+ UChar buf[MAX_DEST_SIZE]={0x0057, 0x0057, 0x0057, 0x002E, 0x0000};
+
+ UnicodeString source(www), uni0(www),uni1(www), ascii0(www), ascii1(www);
+
+ uni0.append(unicodeIn[0]);
+ uni0.append(com);
+ uni0.append((UChar)0x0000);
+
+ uni1.append(unicodeIn[1]);
+ uni1.append(com);
+ uni1.append((UChar)0x0000);
+
+ ascii0.append(asciiIn[0]);
+ ascii0.append(com);
+ ascii0.append((UChar)0x0000);
+
+ ascii1.append(asciiIn[1]);
+ ascii1.append(com);
+ ascii1.append((UChar)0x0000);
+
+ for(i=0;i< (int32_t)(sizeof(unicodeIn)/sizeof(unicodeIn[0])); i++){
+
+ u_charsToUChars(asciiIn[i],buf+4, (int32_t)(strlen(asciiIn[i])+1));
+ u_strcat(buf,com);
+
+ // for every entry in unicodeIn array
+ // prepend www. and append .com
+ source.truncate(4);
+ source.append(unicodeIn[i]);
+ source.append(com);
+ source.append((UChar)0x0000);
+
+ const UChar* src = source.getBuffer();
+ int32_t srcLen = u_strlen(src); //subtract null
+
+ // b) compare it with asciiIn equivalent
+ testCompare(src,srcLen,buf,u_strlen(buf),testName, func,TRUE);
+
+ // a) compare it with itself
+ testCompare(src,srcLen,src,srcLen,testName, func,TRUE);
+
+
+ // IDNToASCII comparison
+ testAPI(src,buf,IDNToASCIIName,FALSE,U_ZERO_ERROR,TRUE, TRUE, IDNToASCII);
+ // IDNToUnicode comparison
+ testAPI(buf,src,IDNToUnicodeName, FALSE,U_ZERO_ERROR, TRUE, TRUE, IDNToUnicode);
+
+ // c) compare it with unicodeIn not equivalent
+ if(i==0){
+ testCompare(src,srcLen,uni1.getBuffer(),uni1.length()-1,testName, func,FALSE);
+ }else{
+ testCompare(src,srcLen,uni0.getBuffer(),uni0.length()-1,testName, func,FALSE);
+ }
+ // d) compare it with asciiIn not equivalent
+ if(i==0){
+ testCompare(src,srcLen,ascii1.getBuffer(),ascii1.length()-1,testName, func,FALSE);
+ }else{
+ testCompare(src,srcLen,ascii0.getBuffer(),ascii0.length()-1,testName, func,FALSE);
+ }
+ }
+}
+
+//---------------------------------------------
+// runIndexedTest
+//---------------------------------------------
+
+void TestIDNA::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par)
+{
+ if (exec) logln((UnicodeString)"TestSuite IDNA API ");
+ switch (index) {
+
+ case 0: name = "TestToASCII"; if (exec) TestToASCII(); break;
+ case 1: name = "TestToUnicode"; if (exec) TestToUnicode(); break;
+ case 2: name = "TestIDNToASCII"; if (exec) TestIDNToASCII(); break;
+ case 3: name = "TestIDNToUnicode"; if (exec) TestIDNToUnicode(); break;
+ case 4: name = "TestCompare"; if (exec) TestCompare(); break;
+ case 5: name = "TestErrorCases"; if (exec) TestErrorCases(); break;
+ case 6: name = "TestChaining"; if (exec) TestChaining(); break;
+ case 7: name = "TestRootLabelSeparator"; if(exec) TestRootLabelSeparator(); break;
+ case 8: name = "TestCompareReferenceImpl"; if(exec) TestCompareReferenceImpl(); break;
+ case 9: name = "TestDataFile"; if(exec) TestDataFile(); break;
+ case 10: name = "TestRefIDNA"; if(exec) TestRefIDNA(); break;
+ case 11: name = "TestIDNAMonkeyTest"; if(exec) TestIDNAMonkeyTest(); break;
+ case 12:
+ {
+ name = "TestConformanceTestVectors";
+ if(exec){
+ logln("TestSuite IDNA conf----"); logln();
+ IdnaConfTest test;
+ callTest(test, par);
+ }
+ break;
+ }
+ default: name = ""; break; /*needed to end loop*/
+ }
+}
+void TestIDNA::TestToASCII(){
+ testToASCII("uidna_toASCII", uidna_toASCII);
+}
+void TestIDNA::TestToUnicode(){
+ testToUnicode("uidna_toUnicode", uidna_toUnicode);
+}
+void TestIDNA::TestIDNToASCII(){
+ testIDNToASCII("uidna_IDNToASCII", uidna_IDNToASCII);
+}
+void TestIDNA::TestIDNToUnicode(){
+ testIDNToUnicode("uidna_IDNToUnicode", uidna_IDNToUnicode);
+}
+void TestIDNA::TestCompare(){
+ testCompare("uidna_compare",uidna_compare);
+}
+void TestIDNA::TestErrorCases(){
+ testErrorCases( "uidna_IDNToASCII",uidna_IDNToASCII,
+ "uidna_IDNToUnicode",uidna_IDNToUnicode);
+}
+void TestIDNA::TestRootLabelSeparator(){
+ testRootLabelSeparator( "uidna_compare",uidna_compare,
+ "uidna_IDNToASCII", uidna_IDNToASCII,
+ "uidna_IDNToUnicode",uidna_IDNToUnicode
+ );
+}
+void TestIDNA::TestChaining(){
+ testChaining("uidna_toASCII",uidna_toASCII, "uidna_toUnicode", uidna_toUnicode);
+}
+
+
+static const int loopCount = 100;
+static const int maxCharCount = 20;
+static const int maxCodePoint = 0x10ffff;
+static uint32_t
+randul()
+{
+ static UBool initialized = FALSE;
+ if (!initialized)
+ {
+ srand((unsigned)time(NULL));
+ initialized = TRUE;
+ }
+ // Assume rand has at least 12 bits of precision
+ uint32_t l = 0;
+ for (uint32_t i=0; i<sizeof(l); ++i)
+ ((char*)&l)[i] = (char)((rand() & 0x0FF0) >> 4);
+ return l;
+}
+
+/**
+ * Return a random integer i where 0 <= i < n.
+ * A special function that gets random codepoints from planes 0,1,2 and 14
+ */
+static int32_t rand_uni()
+{
+ int32_t retVal = (int32_t)(randul()& 0x3FFFF);
+ if(retVal >= 0x30000){
+ retVal+=0xB0000;
+ }
+ return retVal;
+}
+
+static int32_t randi(int32_t n){
+ return (int32_t) (randul() % (n+1));
+}
+
+void getTestSource(UnicodeString& fillIn) {
+ int32_t i = 0;
+ int32_t charCount = (randi(maxCharCount) + 1);
+ while (i <charCount ) {
+ int32_t codepoint = rand_uni();
+ if(codepoint == 0x0000){
+ continue;
+ }
+ fillIn.append((UChar32)codepoint);
+ i++;
+ }
+
+}
+
+UnicodeString TestIDNA::testCompareReferenceImpl(UnicodeString& src,
+ TestFunc refIDNA, const char* refIDNAName,
+ TestFunc uIDNA, const char* uIDNAName,
+ int32_t options){
+
+ const UChar* srcUChars = src.getBuffer();
+ UChar exp[MAX_DEST_SIZE]={0};
+ int32_t expCap = MAX_DEST_SIZE, expLen=0;
+ UErrorCode expStatus = U_ZERO_ERROR;
+ UParseError parseError;
+
+ logln("Comparing "+ UnicodeString(refIDNAName)
+ + " with "+ UnicodeString(uIDNAName)
+ +" for input: " + prettify(srcUChars));
+
+ expLen = refIDNA(srcUChars, src.length()-1, exp, expCap,
+ options, &parseError, &expStatus);
+
+ UChar got[MAX_DEST_SIZE]={0};
+ int32_t gotCap = MAX_DEST_SIZE, gotLen=0;
+ UErrorCode gotStatus = U_ZERO_ERROR;
+
+ gotLen = uIDNA(srcUChars, src.length()-1, got, gotCap,
+ options, &parseError, &gotStatus);
+
+ if(expStatus != gotStatus){
+ errln("Did not get the expected status while comparing " + UnicodeString(refIDNAName)
+ + " with " + UnicodeString(uIDNAName)
+ + " Expected: " + UnicodeString(u_errorName(expStatus))
+ + " Got: " + UnicodeString(u_errorName(gotStatus))
+ + " for Source: "+ prettify(srcUChars)
+ + " Options: " + options);
+ return UnicodeString("");
+ }
+
+ // now we know that both implementations yielded same error
+ if(U_SUCCESS(expStatus)){
+ // compare the outputs if status == U_ZERO_ERROR
+ if(u_strCompare(exp, expLen, got, gotLen, TRUE) != 0){
+ errln("Did not get the expected output while comparing " + UnicodeString(refIDNAName)
+ + " with " + UnicodeString(uIDNAName)
+ + " Expected: " + prettify(UnicodeString(exp, expLen))
+ + " Got: " + prettify(UnicodeString(got, gotLen))
+ + " for Source: "+ prettify(srcUChars)
+ + " Options: " + options);
+ }
+ return UnicodeString(exp, expLen);
+
+ }else{
+ logln("Got the same error while comparing "
+ + UnicodeString(refIDNAName)
+ + " with "+ UnicodeString(uIDNAName)
+ +" for input: " + prettify(srcUChars));
+ }
+ return UnicodeString("");
+}
+
+void TestIDNA::testCompareReferenceImpl(const UChar* src, int32_t srcLen){
+ UnicodeString label(src,srcLen);
+ label.append((UChar)0x0000);
+
+ //test idnaref_toASCII and idnare
+ UnicodeString asciiLabel = testCompareReferenceImpl(label,
+ idnaref_toASCII, "idnaref_toASCII",
+ uidna_toASCII, "uidna_toASCII",
+ UIDNA_ALLOW_UNASSIGNED);
+ testCompareReferenceImpl(label,
+ idnaref_toASCII, "idnaref_toASCII",
+ uidna_toASCII, "uidna_toASCII",
+ UIDNA_DEFAULT);
+ testCompareReferenceImpl(label,
+ idnaref_toASCII, "idnaref_toASCII",
+ uidna_toASCII, "uidna_toASCII",
+ UIDNA_USE_STD3_RULES);
+ testCompareReferenceImpl(label,
+ idnaref_toASCII, "idnaref_toASCII",
+ uidna_toASCII, "uidna_toASCII",
+ UIDNA_USE_STD3_RULES | UIDNA_ALLOW_UNASSIGNED);
+
+ if(asciiLabel.length()!=0){
+ asciiLabel.append((UChar)0x0000);
+
+ // test toUnciode
+ testCompareReferenceImpl(asciiLabel,
+ idnaref_toUnicode, "idnaref_toUnicode",
+ uidna_toUnicode, "uidna_toUnicode",
+ UIDNA_ALLOW_UNASSIGNED);
+ testCompareReferenceImpl(asciiLabel,
+ idnaref_toUnicode, "idnaref_toUnicode",
+ uidna_toUnicode, "uidna_toUnicode",
+ UIDNA_DEFAULT);
+ testCompareReferenceImpl(asciiLabel,
+ idnaref_toUnicode, "idnaref_toUnicode",
+ uidna_toUnicode, "uidna_toUnicode",
+ UIDNA_USE_STD3_RULES);
+ testCompareReferenceImpl(asciiLabel,
+ idnaref_toUnicode, "idnaref_toUnicode",
+ uidna_toUnicode, "uidna_toUnicode",
+ UIDNA_USE_STD3_RULES | UIDNA_ALLOW_UNASSIGNED);
+ }
+
+}
+const char* failures[] ={
+ "\\uAA42\\U0001F8DD\\U00019D01\\U000149A3\\uD385\\U000EE0F5\\U00018B92\\U000179D1\\U00018624\\U0002227F\\U000E83C0\\U000E8DCD\\u5460\\U00017F34\\U0001570B\\u43D1\\U0002C9C9\\U000281EC\\u2105\\U000180AE\\uC5D4",
+ "\\U0002F5A6\\uD638\\u0D0A\\u9E9C\\uFE5B\\U0001FCCB\\u66C4",
+};
+
+void TestIDNA::TestIDNAMonkeyTest(){
+ UnicodeString source;
+ UErrorCode status = U_ZERO_ERROR;
+ int i;
+
+ getInstance(status); // Init prep
+ if (U_FAILURE(status)) {
+ errln("Test could not initialize. Got %s", u_errorName(status));
+ return;
+ }
+
+ for(i=0; i<loopCount; i++){
+ source.truncate(0);
+ getTestSource(source);
+ source.append((UChar)0x0000);
+ const UChar* src = source.getBuffer();
+ testCompareReferenceImpl(src,source.length()-1);
+ testCompareReferenceImpl(src,source.length()-1);
+ }
+
+ /* for debugging */
+ for (i=0; i<(int)(sizeof(failures)/sizeof(failures[0])); i++){
+ source.truncate(0);
+ source.append( failures[i] );
+ source = source.unescape();
+ source.append((UChar)0x0000);
+ const UChar *src = source.getBuffer();
+ testCompareReferenceImpl(src,source.length()-1);
+ //debug(source.getBuffer(),source.length(),UIDNA_ALLOW_UNASSIGNED);
+ }
+
+
+ source.truncate(0);
+ source.append("\\uCF18\\U00021161\\U000EEF11\\U0002BB82\\U0001D63C");
+ debug(source.getBuffer(),source.length(),UIDNA_ALLOW_UNASSIGNED);
+
+ { // test deletion of code points
+ UnicodeString source("\\u043f\\u00AD\\u034f\\u043e\\u0447\\u0435\\u043c\\u0443\\u0436\\u0435\\u043e\\u043d\\u0438\\u043d\\u0435\\u0433\\u043e\\u0432\\u043e\\u0440\\u044f\\u0442\\u043f\\u043e\\u0440\\u0443\\u0441\\u0441\\u043a\\u0438\\u0000");
+ source = source.unescape();
+ UnicodeString expected("\\u043f\\u043e\\u0447\\u0435\\u043c\\u0443\\u0436\\u0435\\u043e\\u043d\\u0438\\u043d\\u0435\\u0433\\u043e\\u0432\\u043e\\u0440\\u044f\\u0442\\u043f\\u043e\\u0440\\u0443\\u0441\\u0441\\u043a\\u0438\\u0000");
+ expected = expected.unescape();
+ UnicodeString ascii("xn--b1abfaaepdrnnbgefbadotcwatmq2g4l");
+ ascii.append((UChar)0x0000);
+ testAPI(source.getBuffer(),ascii.getBuffer(), "uidna_toASCII", FALSE, U_ZERO_ERROR, TRUE, TRUE, uidna_toASCII);
+
+ testAPI(source.getBuffer(),ascii.getBuffer(), "idnaref_toASCII", FALSE, U_ZERO_ERROR, TRUE, TRUE, idnaref_toASCII);
+
+ testCompareReferenceImpl(source.getBuffer(), source.length()-1);
+ }
+
+}
+
+void TestIDNA::TestCompareReferenceImpl(){
+
+ UChar src [2] = {0,0};
+ int32_t srcLen = 0;
+
+
+ for(int32_t i = 0x40000 ; i< 0x10ffff; i++){
+ if(quick==TRUE && i> 0x1FFFF){
+ return;
+ }
+ if(i >= 0x30000 && i <= 0xF0000){
+ i+=0xB0000;
+ }
+ if(i>0xFFFF){
+ src[0] = U16_LEAD(i);
+ src[1] = U16_TRAIL(i);
+ srcLen =2;
+ }else{
+ src[0] = (UChar)i;
+ src[1] = 0;
+ srcLen = 1;
+ }
+ testCompareReferenceImpl(src, srcLen);
+ }
+}
+
+void TestIDNA::TestRefIDNA(){
+ UErrorCode status = U_ZERO_ERROR;
+ getInstance(status); // Init prep
+ if (U_FAILURE(status)) {
+ errln("Test could not initialize. Got %s", u_errorName(status));
+ return;
+ }
+
+ testToASCII("idnaref_toASCII", idnaref_toASCII);
+ testToUnicode("idnaref_toUnicode", idnaref_toUnicode);
+ testIDNToASCII("idnaref_IDNToASCII", idnaref_IDNToASCII);
+ testIDNToUnicode("idnaref_IDNToUnicode", idnaref_IDNToUnicode);
+ testCompare("idnaref_compare",idnaref_compare);
+ testErrorCases( "idnaref_IDNToASCII",idnaref_IDNToASCII,
+ "idnaref_IDNToUnicode",idnaref_IDNToUnicode);
+ testChaining("idnaref_toASCII",idnaref_toASCII, "idnaref_toUnicode", idnaref_toUnicode);
+
+ testRootLabelSeparator( "idnaref_compare",idnaref_compare,
+ "idnaref_IDNToASCII", idnaref_IDNToASCII,
+ "idnaref_IDNToUnicode",idnaref_IDNToUnicode
+ );
+ testChaining("idnaref_toASCII",idnaref_toASCII, "idnaref_toUnicode", idnaref_toUnicode);
+}
+
+
+void TestIDNA::TestDataFile(){
+ testData(*this);
+}
+TestIDNA::~TestIDNA(){
+ if(gPrep!=NULL){
+ delete gPrep;
+ gPrep = NULL;
+ }
+}
+
+NamePrepTransform* TestIDNA::gPrep = NULL;
+
+NamePrepTransform* TestIDNA::getInstance(UErrorCode& status){
+ if(TestIDNA::gPrep == NULL){
+ UParseError parseError;
+ TestIDNA::gPrep = NamePrepTransform::createInstance(parseError, status);
+ if(TestIDNA::gPrep ==NULL){
+ //status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ }
+ return TestIDNA::gPrep;
+
+}
+#endif /* #if !UCONFIG_NO_IDNA */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/testidna.h b/Build/source/libs/icu/icu-xetex/test/intltest/testidna.h
new file mode 100644
index 00000000000..58567df59fd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/testidna.h
@@ -0,0 +1,120 @@
+/*
+ *******************************************************************************
+ *
+ * Copyright (C) 2003-2006, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *
+ *******************************************************************************
+ * file name: testidna.h
+ * encoding: US-ASCII
+ * tab size: 8 (not used)
+ * indentation:4
+ *
+ * created on: 2003feb1
+ * created by: Ram Viswanadha
+ */
+
+#ifndef TESTIDNA_H
+#define TESTIDNA_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_IDNA && !UCONFIG_NO_TRANSLITERATION
+
+#include "intltest.h"
+#include "unicode/parseerr.h"
+#include "unicode/uidna.h"
+
+U_CDECL_BEGIN
+typedef int32_t
+(U_EXPORT2 *TestFunc) ( const UChar *src, int32_t srcLength,
+ UChar *dest, int32_t destCapacity,
+ int32_t options, UParseError *parseError,
+ UErrorCode *status);
+typedef int32_t
+(U_EXPORT2 *CompareFunc) (const UChar *s1, int32_t s1Len,
+ const UChar *s2, int32_t s2Len,
+ int32_t options,
+ UErrorCode *status);
+
+
+U_CDECL_END
+
+// test the API
+
+class NamePrepTransform;
+
+/**
+ * @test
+ * @summary General test of HexadecimalToUnicodeTransliterator
+ */
+class TestIDNA : public IntlTest {
+public:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par=NULL);
+ void TestDataFile();
+ void TestToASCII();
+ void TestToUnicode();
+ void TestIDNToUnicode();
+ void TestIDNToASCII();
+ void TestCompare();
+ void TestErrorCases();
+ void TestChaining();
+ void TestRootLabelSeparator();
+ void TestCompareReferenceImpl();
+ void TestRefIDNA();
+ void TestIDNAMonkeyTest();
+ void TestConformance();
+ static NamePrepTransform* getInstance(UErrorCode& status);
+ static NamePrepTransform* gPrep;
+ virtual ~TestIDNA();
+
+private:
+ void testToASCII(const char* testName, TestFunc func);
+ void testToUnicode(const char* testName, TestFunc func);
+ void testIDNToUnicode(const char* testName, TestFunc func);
+ void testIDNToASCII(const char* testName, TestFunc func);
+ void testCompare(const char* testName, CompareFunc func);
+ void testChaining(const char* toASCIIName, TestFunc toASCII,
+ const char* toUnicodeName, TestFunc toUnicode);
+ void debug(const UChar* src, int32_t srcLength, int32_t options);
+ // main testing functions
+ void testAPI(const UChar *src, const UChar *expected, const char *testName,
+ UBool useSTD3ASCIIRules, UErrorCode expectedStatus,
+ UBool doCompare, UBool testUnassigned, TestFunc func, UBool testSTD3ASCIIRules=TRUE);
+
+ void testCompare(const UChar* s1, int32_t s1Len,
+ const UChar* s2, int32_t s2Len,
+ const char* testName, CompareFunc func,
+ UBool isEqual);
+
+ void testErrorCases(const char* IDNToASCIIName, TestFunc IDNToASCII,
+ const char* IDNToUnicodeName, TestFunc IDNToUnicode);
+
+ void testChaining(const UChar* src,int32_t numIterations,const char* testName,
+ UBool useSTD3ASCIIRules, UBool caseInsensitive, TestFunc func);
+
+ void testRootLabelSeparator(const char* testName, CompareFunc func,
+ const char* IDNToASCIIName, TestFunc IDNToASCII,
+ const char* IDNToUnicodeName, TestFunc IDNToUnicode);
+
+ void testCompareReferenceImpl(const UChar* src, int32_t srcLen);
+
+ UnicodeString testCompareReferenceImpl(UnicodeString& src,
+ TestFunc refIDNA, const char* refIDNAName,
+ TestFunc uIDNA, const char* uIDNAName,
+ int32_t options);
+
+ void testConformance(const char* toASCIIName, TestFunc toASCII,
+ const char* IDNToASCIIName, TestFunc IDNToASCII,
+ const char* IDNToUnicodeName, TestFunc IDNToUnicode,
+ const char* toUnicodeName, TestFunc toUnicode
+ );
+
+};
+
+// test the TRIE data structure
+int testData(TestIDNA& test);
+
+#endif /* #if !UCONFIG_NO_IDNA */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/testutil.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/testutil.cpp
new file mode 100644
index 00000000000..56ec038ab4a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/testutil.cpp
@@ -0,0 +1,37 @@
+/*
+**********************************************************************
+* Copyright (C) 2001, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/23/00 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/unistr.h"
+#include "testutil.h"
+
+static const UChar HEX[16]={48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70};
+
+UnicodeString TestUtility::hex(UChar ch) {
+ UnicodeString buf;
+ buf.append(HEX[0xF&(ch>>12)]);
+ buf.append(HEX[0xF&(ch>>8)]);
+ buf.append(HEX[0xF&(ch>>4)]);
+ buf.append(HEX[0xF&ch]);
+ return buf;
+}
+
+UnicodeString TestUtility::hex(const UnicodeString& s) {
+ return hex(s, 44 /*,*/);
+}
+
+UnicodeString TestUtility::hex(const UnicodeString& s, UChar sep) {
+ if (s.length() == 0) return "";
+ UnicodeString result = hex(s.charAt(0));
+ for (int32_t i = 1; i < s.length(); ++i) {
+ result.append(sep);
+ result.append(hex(s.charAt(i)));
+ }
+ return result;
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/testutil.h b/Build/source/libs/icu/icu-xetex/test/intltest/testutil.h
new file mode 100644
index 00000000000..9c14a2860b9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/testutil.h
@@ -0,0 +1,34 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/23/00 aliu Creation.
+**********************************************************************
+*/
+#ifndef TESTUTIL_H
+#define TESTUTIL_H
+
+#include "intltest.h"
+
+/**
+ * Utility methods. Everything in this class is static -- do not
+ * attempt to instantiate.
+ */
+class TestUtility {
+
+public:
+
+ static UnicodeString hex(UChar ch);
+
+ static UnicodeString hex(const UnicodeString& s);
+
+ static UnicodeString hex(const UnicodeString& s, UChar sep);
+
+private:
+
+ TestUtility() {} // Prevent instantiation
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/textfile.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/textfile.cpp
new file mode 100644
index 00000000000..fe193b0fcbd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/textfile.cpp
@@ -0,0 +1,179 @@
+/*
+**********************************************************************
+* Copyright (c) 2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: March 19 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include "textfile.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "intltest.h"
+#include "util.h"
+
+// If the symbol CCP is defined, then the 'name' and 'encoding'
+// constructor parameters are copied. Otherwise they are aliased.
+// #define CCP
+
+TextFile::TextFile(const char* _name, const char* _encoding, UErrorCode& ec) :
+ file(0),
+ name(0), encoding(0),
+ buffer(0),
+ capacity(0),
+ lineNo(0)
+{
+ if (U_FAILURE(ec) || _name == 0 || _encoding == 0) {
+ if (U_SUCCESS(ec)) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ }
+ return;
+ }
+
+#ifdef CCP
+ name = uprv_malloc(uprv_strlen(_name) + 1);
+ encoding = uprv_malloc(uprv_strlen(_encoding) + 1);
+ if (name == 0 || encoding == 0) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_strcpy(name, _name);
+ uprv_strcpy(encoding, _encoding);
+#else
+ name = (char*) _name;
+ encoding = (char*) _encoding;
+#endif
+
+ const char* testDir = IntlTest::getSourceTestData(ec);
+ if (U_FAILURE(ec)) {
+ return;
+ }
+ if (!ensureCapacity((int32_t)(uprv_strlen(testDir) + uprv_strlen(name) + 1))) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_strcpy(buffer, testDir);
+ uprv_strcat(buffer, name);
+
+ file = T_FileStream_open(buffer, "rb");
+ if (file == 0) {
+ ec = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+}
+
+TextFile::~TextFile() {
+ if (file != 0) T_FileStream_close(file);
+ if (buffer != 0) uprv_free(buffer);
+#ifdef CCP
+ uprv_free(name);
+ uprv_free(encoding);
+#endif
+}
+
+UBool TextFile::readLine(UnicodeString& line, UErrorCode& ec) {
+ if (T_FileStream_eof(file)) {
+ return FALSE;
+ }
+ // Note: 'buffer' may change after ensureCapacity() is called,
+ // so don't use
+ // p=buffer; *p++=c;
+ // but rather
+ // i=; buffer[i++]=c;
+ int32_t n = 0;
+ for (;;) {
+ int c = T_FileStream_getc(file); // sic: int, not int32_t
+ if (c < 0 || c == 0xD || c == 0xA) {
+ // consume 0xA following 0xD
+ if (c == 0xD) {
+ c = T_FileStream_getc(file);
+ if (c != 0xA && c >= 0) {
+ T_FileStream_ungetc(c, file);
+ }
+ }
+ break;
+ }
+ if (!setBuffer(n++, c, ec)) return FALSE;
+ }
+ if (!setBuffer(n++, 0, ec)) return FALSE;
+ UnicodeString str(buffer, encoding);
+ // Remove BOM in first line, if present
+ if (lineNo == 0 && str[0] == 0xFEFF) {
+ str.remove(0, 1);
+ }
+ ++lineNo;
+ line = str.unescape();
+ return TRUE;
+}
+
+UBool TextFile::readLineSkippingComments(UnicodeString& line, UErrorCode& ec,
+ UBool trim) {
+ for (;;) {
+ if (!readLine(line, ec)) return FALSE;
+ // Skip over white space
+ int32_t pos = 0;
+ ICU_Utility::skipWhitespace(line, pos, TRUE);
+ // Ignore blank lines and comment lines
+ if (pos == line.length() || line.charAt(pos) == 0x23/*'#'*/) {
+ continue;
+ }
+ // Process line
+ if (trim) line.remove(0, pos);
+ return TRUE;
+ }
+}
+
+/**
+ * Set buffer[index] to c, growing buffer if necessary. Return TRUE if
+ * successful.
+ */
+UBool TextFile::setBuffer(int32_t index, char c, UErrorCode& ec) {
+ if (capacity <= index) {
+ if (!ensureCapacity(index+1)) {
+ ec = U_MEMORY_ALLOCATION_ERROR;
+ return FALSE;
+ }
+ }
+ buffer[index] = c;
+ return TRUE;
+}
+
+/**
+ * Make sure that 'buffer' has at least 'mincapacity' bytes.
+ * Return TRUE upon success. Upon return, 'buffer' may change
+ * value. In any case, previous contents are preserved.
+ */
+UBool TextFile::ensureCapacity(int32_t mincapacity) {
+ if (capacity >= mincapacity) {
+ return TRUE;
+ }
+
+ // Grow by factor of 2 to prevent frequent allocation
+ // Note: 'capacity' may be 0
+ int32_t i;
+ for (i = capacity || 1024; i < mincapacity; ) {
+ i <<= 1;
+ if (i < 0) {
+ i = 0x7FFFFFFF;
+ break;
+ }
+ }
+ mincapacity = i;
+
+ // Simple realloc() no good; contents not preserved
+ // Note: 'buffer' may be 0
+ char* newbuffer = (char*) uprv_malloc(mincapacity);
+ if (newbuffer == 0) {
+ return FALSE;
+ }
+ if (buffer != 0) {
+ uprv_strncpy(newbuffer, buffer, capacity);
+ uprv_free(buffer);
+ }
+ buffer = newbuffer;
+ capacity = mincapacity;
+ return TRUE;
+}
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/textfile.h b/Build/source/libs/icu/icu-xetex/test/intltest/textfile.h
new file mode 100644
index 00000000000..3fcea074abc
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/textfile.h
@@ -0,0 +1,72 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: March 19 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#ifndef __ICU_INTLTEST_TEXTFILE__
+#define __ICU_INTLTEST_TEXTFILE__
+
+#include "intltest.h"
+#include "filestrm.h"
+
+/**
+ * This class implements access to a text data file located in the
+ * icu/source/test/testdata/ directory.
+ */
+class TextFile {
+ public:
+ /**
+ * Open a file with the given name, in the given encoding, in the
+ * ICU testdata directory. See textfile.cpp to determine if the
+ * 'name' and 'encoding' parameters are aliased or copied.
+ */
+ TextFile(const char* name, const char* encoding, UErrorCode& ec);
+
+ virtual ~TextFile();
+
+ /**
+ * Read a line terminated by ^J or ^M or ^M^J, and convert it from
+ * this file's encoding to Unicode. The EOL character(s) are not
+ * included in 'line'.
+ * @return TRUE if a line was read, or FALSE if the EOF
+ * was reached or an error occurred
+ */
+ UBool readLine(UnicodeString& line, UErrorCode& ec);
+
+ /**
+ * Read a line, ignoring blank lines and lines that start with
+ * '#'. Trim leading white space.
+ * @param trim if TRUE then remove leading rule white space
+ * @return TRUE if a line was read, or FALSE if the EOF
+ * was reached or an error occurred
+ */
+ UBool readLineSkippingComments(UnicodeString& line, UErrorCode& ec,
+ UBool trim = FALSE);
+
+ /**
+ * Return the line number of the last line returned by readLine().
+ */
+ inline int32_t getLineNumber() const;
+
+ private:
+ UBool ensureCapacity(int32_t capacity);
+ UBool setBuffer(int32_t index, char c, UErrorCode& ec);
+
+ FileStream* file;
+ char* name;
+ char* encoding;
+ char* buffer;
+ int32_t capacity;
+ int32_t lineNo;
+};
+
+inline int32_t TextFile::getLineNumber() const {
+ return lineNo;
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tfsmalls.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tfsmalls.cpp
new file mode 100644
index 00000000000..6cc69a01210
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tfsmalls.cpp
@@ -0,0 +1,387 @@
+
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+#include "tfsmalls.h"
+
+#include "unicode/msgfmt.h"
+#include "unicode/choicfmt.h"
+
+#include "unicode/parsepos.h"
+#include "unicode/fieldpos.h"
+#include "unicode/fmtable.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+/*static UBool chkstatus( UErrorCode &status, char* msg = NULL )
+{
+ UBool ok = (status == U_ZERO_ERROR);
+ if (!ok) it_errln( msg );
+ return ok;
+}*/
+
+void test_ParsePosition( void )
+{
+ ParsePosition* pp1 = new ParsePosition();
+ if (pp1 && (pp1->getIndex() == 0)) {
+ it_logln("PP constructor() tested.");
+ }else{
+ it_errln("*** PP getIndex or constructor() result");
+ }
+ delete pp1;
+
+
+ {
+ int32_t to = 5;
+ ParsePosition pp2( to );
+ if (pp2.getIndex() == 5) {
+ it_logln("PP getIndex and constructor(int32_t) tested.");
+ }else{
+ it_errln("*** PP getIndex or constructor(int32_t) result");
+ }
+ pp2.setIndex( 3 );
+ if (pp2.getIndex() == 3) {
+ it_logln("PP setIndex tested.");
+ }else{
+ it_errln("*** PP getIndex or setIndex result");
+ }
+ }
+
+ ParsePosition pp2, pp3;
+ pp2 = 3;
+ pp3 = 5;
+ ParsePosition pp4( pp3 );
+ if ((pp2 != pp3) && (pp3 == pp4)) {
+ it_logln("PP copy contructor, operator== and operator != tested.");
+ }else{
+ it_errln("*** PP operator== or operator != result");
+ }
+
+ ParsePosition pp5;
+ pp5 = pp4;
+ if ((pp4 == pp5) && (!(pp4 != pp5))) {
+ it_logln("PP operator= tested.");
+ }else{
+ it_errln("*** PP operator= operator== or operator != result");
+ }
+
+
+}
+
+#include "unicode/decimfmt.h"
+
+void test_FieldPosition_example( void )
+{
+ //***** no error detection yet !!!!!!!
+ //***** this test is for compiler checks and visual verification only.
+ double doubleNum[] = { 123456789.0, -12345678.9, 1234567.89, -123456.789,
+ 12345.6789, -1234.56789, 123.456789, -12.3456789, 1.23456789};
+ int32_t dNumSize = (int32_t)(sizeof(doubleNum)/sizeof(double));
+
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat* fmt = (DecimalFormat*) NumberFormat::createInstance(status);
+ if (U_FAILURE(status)) {
+ it_dataerrln("NumberFormat::createInstance() error");
+ return;
+ }
+ fmt->setDecimalSeparatorAlwaysShown(TRUE);
+
+ const int32_t tempLen = 20;
+ char temp[tempLen];
+
+ for (int32_t i=0; i<dNumSize; i++) {
+ FieldPosition pos(NumberFormat::INTEGER_FIELD);
+ UnicodeString buf;
+ //char fmtText[tempLen];
+ //ToCharString(fmt->format(doubleNum[i], buf, pos), fmtText);
+ UnicodeString res = fmt->format(doubleNum[i], buf, pos);
+ for (int32_t j=0; j<tempLen; j++) temp[j] = '='; // clear with spaces
+ int32_t tempOffset = (tempLen <= (tempLen - pos.getEndIndex())) ?
+ tempLen : (tempLen - pos.getEndIndex());
+ temp[tempOffset] = '\0';
+ it_logln(UnicodeString("FP ") + UnicodeString(temp) + res);
+ }
+ delete fmt;
+
+ it_logln("");
+
+}
+
+void test_FieldPosition( void )
+{
+
+ FieldPosition fp( 7 );
+
+ if (fp.getField() == 7) {
+ it_logln("FP constructor(int32_t) and getField tested.");
+ }else{
+ it_errln("*** FP constructor(int32_t) or getField");
+ }
+
+ FieldPosition* fph = new FieldPosition( 3 );
+ if ( fph->getField() != 3) it_errln("*** FP getField or heap constr.");
+ delete fph;
+
+ UBool err1 = FALSE;
+ UBool err2 = FALSE;
+ UBool err3 = FALSE;
+ for (int32_t i = -50; i < 50; i++ ) {
+ fp.setField( i+8 );
+ fp.setBeginIndex( i+6 );
+ fp.setEndIndex( i+7 );
+ if (fp.getField() != i+8) err1 = TRUE;
+ if (fp.getBeginIndex() != i+6) err2 = TRUE;
+ if (fp.getEndIndex() != i+7) err3 = TRUE;
+ }
+ if (!err1) {
+ it_logln("FP setField and getField tested.");
+ }else{
+ it_errln("*** FP setField or getField");
+ }
+ if (!err2) {
+ it_logln("FP setBeginIndex and getBeginIndex tested.");
+ }else{
+ it_errln("*** FP setBeginIndex or getBeginIndex");
+ }
+ if (!err3) {
+ it_logln("FP setEndIndex and getEndIndex tested.");
+ }else{
+ it_errln("*** FP setEndIndex or getEndIndex");
+ }
+
+ it_logln("");
+
+}
+
+void test_Formattable( void )
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable* ftp = new Formattable();
+ if (!ftp || !(ftp->getType() == Formattable::kLong) || !(ftp->getLong() == 0)) {
+ it_errln("*** Formattable constructor or getType or getLong");
+ }
+ delete ftp;
+
+ Formattable fta, ftb;
+ fta.setLong(1); ftb.setLong(2);
+ if ((fta != ftb) || !(fta == ftb)) {
+ it_logln("FT setLong, operator== and operator!= tested.");
+ status = U_ZERO_ERROR;
+ fta.getLong(&status);
+ if ( status == U_INVALID_FORMAT_ERROR){
+ it_errln("*** FT getLong(UErrorCode* status) failed on real Long");
+ } else {
+ it_logln("FT getLong(UErrorCode* status) tested.");
+ }
+ }else{
+ it_errln("*** Formattable setLong or operator== or !=");
+ }
+ fta = ftb;
+ if ((fta == ftb) || !(fta != ftb)) {
+ it_logln("FT operator= tested.");
+ }else{
+ it_errln("*** FT operator= or operator== or operator!=");
+ }
+
+ fta.setDouble( 3.0 );
+ if ((fta.getType() == Formattable::kDouble) && (fta.getDouble() == 3.0)) {
+ it_logln("FT set- and getDouble tested.");
+ }else{
+ it_errln("*** FT set- or getDouble");
+ }
+
+ fta.getDate(status = U_ZERO_ERROR);
+ if (status != U_INVALID_FORMAT_ERROR){
+ it_errln("*** FT getDate with status should fail on non-Date");
+ }
+ fta.setDate( 4.0 );
+ if ((fta.getType() == Formattable::kDate) && (fta.getDate() == 4.0)) {
+ it_logln("FT set- and getDate tested.");
+ status = U_ZERO_ERROR;
+ fta.getDate(status);
+ if ( status == U_INVALID_FORMAT_ERROR){
+ it_errln("*** FT getDate with status failed on real Date");
+ } else {
+ it_logln("FT getDate with status tested.");
+ }
+ }else{
+ it_errln("*** FT set- or getDate");
+ }
+
+ status = U_ZERO_ERROR;
+ fta.getLong(&status);
+ if (status != U_INVALID_FORMAT_ERROR){
+ it_errln("*** FT getLong(UErrorCode* status) should fail on non-Long");
+ }
+
+ fta.setString("abc");
+ const Formattable ftc(fta);
+ UnicodeString res;
+
+ {
+ UBool t;
+ t = (fta.getType() == Formattable::kString)
+ && (fta.getString(res) == "abc")
+ && (fta.getString() == "abc");
+ res = fta.getString(status = U_ZERO_ERROR);
+ t = t && (status != U_INVALID_FORMAT_ERROR && res == "abc");
+ res = ftc.getString(status = U_ZERO_ERROR);
+ t = t && (status != U_INVALID_FORMAT_ERROR && res == "abc");
+ ftc.getString(res,status = U_ZERO_ERROR);
+ t = t && (status != U_INVALID_FORMAT_ERROR && res == "abc");
+ if (t) {
+ it_logln("FT set- and getString tested.");
+ }else{
+ it_errln("*** FT set- or getString");
+ }
+ }
+
+ UnicodeString ucs = "unicode-string";
+ UnicodeString* ucs_ptr = new UnicodeString("pointed-to-unicode-string");
+
+ const Formattable ftarray[] =
+ {
+ Formattable( 1.0, Formattable::kIsDate ),
+ 2.0,
+ (int32_t)3,
+ ucs,
+ ucs_ptr
+ };
+ const int32_t ft_cnt = LENGTHOF(ftarray);
+ Formattable ft_arr( ftarray, ft_cnt );
+ UnicodeString temp;
+ if ((ft_arr[0].getType() == Formattable::kDate) && (ft_arr[0].getDate() == 1.0)
+ && (ft_arr[1].getType() == Formattable::kDouble) && (ft_arr[1].getDouble() == 2.0)
+ && (ft_arr[2].getType() == Formattable::kLong) && (ft_arr[2].getLong() == (int32_t)3)
+ && (ft_arr[3].getType() == Formattable::kString) && (ft_arr[3].getString(temp) == ucs)
+ && (ft_arr[4].getType() == Formattable::kString) && (ft_arr[4].getString(temp) == *ucs_ptr) ) {
+ it_logln("FT constr. for date, double, long, ustring, ustring* and array tested");
+ }else{
+ it_errln("*** FT constr. for date, double, long, ustring, ustring* or array");
+ }
+
+ int32_t i, res_cnt;
+ const Formattable* res_array = ft_arr.getArray( res_cnt );
+ if (res_cnt == ft_cnt) {
+ UBool same = TRUE;
+ for (i = 0; i < res_cnt; i++ ) {
+ if (res_array[i] != ftarray[i]) {
+ same = FALSE;
+ }
+ }
+ if (same) {
+ it_logln("FT getArray tested");
+ res_array = ft_arr.getArray( res_cnt, status = U_ZERO_ERROR);
+ if (status == U_INVALID_FORMAT_ERROR){
+ it_errln("*** FT getArray with status failed on real array");
+ } else {
+ it_logln("FT getArray with status tested on real array");
+ }
+ }else{
+ it_errln("*** FT getArray comparison");
+ }
+ }else{
+ it_errln(UnicodeString("*** FT getArray count res_cnt=") + res_cnt + UnicodeString("ft_cnt=") + ft_cnt);
+ }
+
+ res_array = fta.getArray(res_cnt, status = U_ZERO_ERROR);
+ if (status == U_INVALID_FORMAT_ERROR){
+ if (res_cnt == 0 && res_array == NULL){
+ it_logln("FT getArray with status tested on non array");
+ } else {
+ it_errln("*** FT getArray with status return values are not consistent");
+ }
+ } else {
+ it_errln("*** FT getArray with status should fail on non-array");
+ }
+
+
+ Formattable *pf;
+ for(i = 0; i < ft_cnt; ++i) {
+ pf = ftarray[i].clone();
+ if(pf == (ftarray + i) || *pf != ftarray[i]) {
+ it_errln("Formattable.clone() failed for item %d" + i);
+ }
+ delete pf;
+ }
+
+ const Formattable ftarr1[] = { Formattable( (int32_t)1 ), Formattable( (int32_t)2 ) };
+ const Formattable ftarr2[] = { Formattable( (int32_t)3 ), Formattable( (int32_t)4 ) };
+
+ const int32_t ftarr1_cnt = (int32_t)(sizeof(ftarr1) / sizeof(Formattable));
+ const int32_t ftarr2_cnt = (int32_t)(sizeof(ftarr2) / sizeof(Formattable));
+
+ ft_arr.setArray( ftarr1, ftarr1_cnt );
+ if ((ft_arr[0].getType() == Formattable::kLong) && (ft_arr[0].getLong() == (int32_t)1)) {
+ it_logln("FT setArray tested");
+ }else{
+ it_errln("*** FT setArray");
+ }
+
+ Formattable* ft_dynarr = new Formattable[ftarr2_cnt];
+ for (i = 0; i < ftarr2_cnt; i++ ) {
+ ft_dynarr[i] = ftarr2[i];
+ }
+ if ((ft_dynarr[0].getType() == Formattable::kLong) && (ft_dynarr[0].getLong() == (int32_t)3)
+ && (ft_dynarr[1].getType() == Formattable::kLong) && (ft_dynarr[1].getLong() == (int32_t)4)) {
+ it_logln("FT operator= and array operations tested");
+ }else{
+ it_errln("*** FT operator= or array operations");
+ }
+
+ ft_arr.adoptArray( ft_dynarr, ftarr2_cnt );
+ if ((ft_arr[0].getType() == Formattable::kLong) && (ft_arr[0].getLong() == (int32_t)3)
+ && (ft_arr[1].getType() == Formattable::kLong) && (ft_arr[1].getLong() == (int32_t)4)) {
+ it_logln("FT adoptArray tested");
+ }else{
+ it_errln("*** FT adoptArray or operator[]");
+ }
+
+ ft_arr.setLong(0); // calls 'dispose' and deletes adopted array !
+
+ UnicodeString* ucs_dyn = new UnicodeString("ttt");
+ UnicodeString tmp2;
+
+ fta.adoptString( ucs_dyn );
+ if ((fta.getType() == Formattable::kString) && (fta.getString(tmp2) == "ttt")) {
+ it_logln("FT adoptString tested");
+ }else{
+ it_errln("*** FT adoptString or getString");
+ }
+ fta.setLong(0); // calls 'dispose' and deletes adopted string !
+
+ it_logln();
+}
+
+void TestFormatSmallClasses::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ switch (index) {
+ case 0: name = "pp";
+ if (exec) logln("TestSuite Format/SmallClasses/ParsePosition (f/chc/sma/pp): ");
+ if (exec) test_ParsePosition();
+ break;
+ case 1: name = "fp";
+ if (exec) logln("TestSuite Format/SmallClasses/FieldPosition (f/chc/sma/fp): ");
+ if (exec) test_FieldPosition();
+ break;
+ case 2: name = "fpe";
+ if (exec) logln("TestSuite Format/SmallClasses/FieldPositionExample (f/chc/sma/fpe): ");
+ if (exec) test_FieldPosition_example();
+ break;
+ case 3: name = "ft";
+ if (exec) logln("TestSuite Format/SmallClasses/Formattable (f/chc/sma/ft): ");
+ if (exec) test_Formattable();
+ break;
+ default: name = ""; break; //needed to end loop
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tfsmalls.h b/Build/source/libs/icu/icu-xetex/test/intltest/tfsmalls.h
new file mode 100644
index 00000000000..26f13279bb3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tfsmalls.h
@@ -0,0 +1,27 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#ifndef TESTFORMATSMALLCLASSES_H
+#define TESTFORMATSMALLCLASSES_H
+
+#include "intltest.h"
+
+/**
+ * tests 3 smaller classes in the format library
+ **/
+class TestFormatSmallClasses: public IntlTest {
+ /**
+ * runs tests in 4 local routines,
+ * performs test for API and funtionalty of 3 smaller format classes:
+ * ParsePosition in test_ParsePosition(),
+ * FieldPosition in test_FieldPosition(),
+ * Formattable in test_Formattable().
+ **/
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/thcoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/thcoll.cpp
new file mode 100644
index 00000000000..1fd99e7fb24
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/thcoll.cpp
@@ -0,0 +1,459 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 12/09/99 aliu Ported from Java.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "thcoll.h"
+#include "unicode/utypes.h"
+#include "unicode/coll.h"
+#include "unicode/sortkey.h"
+#include "unicode/ustring.h"
+#include "cstring.h"
+#include "filestrm.h"
+#include "textfile.h"
+
+/**
+ * The TestDictionary test expects a file of this name, with this
+ * encoding, to be present in the directory $ICU/source/test/testdata.
+ */
+//#define TEST_FILE "th18057.txt"
+
+/**
+ * This is the most failures we show in TestDictionary. If this number
+ * is < 0, we show all failures.
+ */
+#define MAX_FAILURES_TO_SHOW -1
+
+CollationThaiTest::CollationThaiTest() {
+ UErrorCode status = U_ZERO_ERROR;
+ coll = Collator::createInstance(Locale("th", "TH", ""), status);
+ if (coll && U_SUCCESS(status)) {
+ //coll->setStrength(Collator::TERTIARY);
+ } else {
+ delete coll;
+ coll = 0;
+ }
+}
+
+CollationThaiTest::~CollationThaiTest() {
+ delete coll;
+}
+
+void CollationThaiTest::runIndexedTest(int32_t index, UBool exec, const char* &name,
+ char* /*par*/) {
+
+ if((!coll) && exec) {
+ errln(__FILE__ " cannot test - failed to create collator.");
+ name = "some test";
+ return;
+ }
+
+ switch (index) {
+ TESTCASE(0,TestDictionary);
+ TESTCASE(1,TestCornerCases);
+ TESTCASE(2,TestNamesList);
+ TESTCASE(3,TestInvalidThai);
+ TESTCASE(4,TestReordering);
+ default: name = ""; break;
+ }
+}
+
+/**
+ * Read the external names list, and confirms that the collator
+ * gets the same results when comparing lines one to another
+ * using regular and iterative comparison.
+ */
+void CollationThaiTest::TestNamesList(void) {
+ if (coll == 0) {
+ errln("Error: could not construct Thai collator");
+ return;
+ }
+
+ UErrorCode ec = U_ZERO_ERROR;
+ TextFile names("TestNames_Thai.txt", "UTF16LE", ec);
+ if (U_FAILURE(ec)) {
+ logln("Can't open TestNames_Thai.txt: %s; skipping test",
+ u_errorName(ec));
+ return;
+ }
+
+ //
+ // Loop through each word in the dictionary and compare it to the previous
+ // word. They should be in sorted order.
+ //
+ UnicodeString lastWord, word;
+ //int32_t failed = 0;
+ int32_t wordCount = 0;
+ while (names.readLineSkippingComments(word, ec, FALSE) && U_SUCCESS(ec)) {
+
+ // Show the first 8 words being compared, so we can see what's happening
+ ++wordCount;
+ if (wordCount <= 8) {
+ UnicodeString str;
+ logln((UnicodeString)"Word " + wordCount + ": " + IntlTest::prettify(word, str));
+ }
+
+ if (lastWord.length() > 0) {
+ Collator::EComparisonResult result = coll->compare(lastWord, word);
+ doTest(coll, lastWord, word, result);
+ }
+ lastWord = word;
+ }
+
+ assertSuccess("readLine", ec);
+
+ logln((UnicodeString)"Words checked: " + wordCount);
+}
+
+/**
+ * Read the external dictionary file, which is already in proper
+ * sorted order, and confirm that the collator compares each line as
+ * preceding the following line.
+ */
+void CollationThaiTest::TestDictionary(void) {
+ if (coll == 0) {
+ errln("Error: could not construct Thai collator");
+ return;
+ }
+
+ UErrorCode ec = U_ZERO_ERROR;
+ TextFile riwords("riwords.txt", "UTF8", ec);
+ if (U_FAILURE(ec)) {
+ logln("Can't open riwords.txt: %s; skipping test",
+ u_errorName(ec));
+ return;
+ }
+
+ //
+ // Loop through each word in the dictionary and compare it to the previous
+ // word. They should be in sorted order.
+ //
+ UnicodeString lastWord, word;
+ int32_t failed = 0;
+ int32_t wordCount = 0;
+ while (riwords.readLineSkippingComments(word, ec, FALSE) && U_SUCCESS(ec)) {
+
+ // Show the first 8 words being compared, so we can see what's happening
+ ++wordCount;
+ if (wordCount <= 8) {
+ UnicodeString str;
+ logln((UnicodeString)"Word " + wordCount + ": " + IntlTest::prettify(word, str));
+ }
+
+ if (lastWord.length() > 0) {
+ // line enabled for j2720
+ doTest(coll, lastWord, word, Collator::LESS);
+ int32_t result = coll->compare(lastWord, word);
+
+ if (result >= 0) {
+ failed++;
+ if (MAX_FAILURES_TO_SHOW < 0 || failed <= MAX_FAILURES_TO_SHOW) {
+ UnicodeString str;
+ UnicodeString msg =
+ UnicodeString("--------------------------------------------\n")
+ + riwords.getLineNumber()
+ + " compare(" + IntlTest::prettify(lastWord, str);
+ msg += UnicodeString(", ")
+ + IntlTest::prettify(word, str) + ") returned " + result
+ + ", expected -1\n";
+ UErrorCode status = U_ZERO_ERROR;
+ CollationKey k1, k2;
+ coll->getCollationKey(lastWord, k1, status);
+ coll->getCollationKey(word, k2, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"Fail: getCollationKey returned " + u_errorName(status));
+ return;
+ }
+ msg.append("key1: ").append(prettify(k1, str)).append("\n");
+ msg.append("key2: ").append(prettify(k2, str));
+ errln(msg);
+ }
+ }
+ }
+ lastWord = word;
+ }
+
+ assertSuccess("readLine", ec);
+
+ if (failed != 0) {
+ if (failed > MAX_FAILURES_TO_SHOW) {
+ errln((UnicodeString)"Too many failures; only the first " +
+ MAX_FAILURES_TO_SHOW + " failures were shown");
+ }
+ errln((UnicodeString)"Summary: " + failed + " of " + (riwords.getLineNumber() - 1) +
+ " comparisons failed");
+ }
+
+ logln((UnicodeString)"Words checked: " + wordCount);
+}
+
+/**
+ * Odd corner conditions taken from "How to Sort Thai Without Rewriting Sort",
+ * by Doug Cooper, http://seasrc.th.net/paper/thaisort.zip
+ */
+void CollationThaiTest::TestCornerCases(void) {
+ const char* TESTS[] = {
+ // Shorter words precede longer
+ "\\u0e01", "<", "\\u0e01\\u0e01",
+
+ // Tone marks are considered after letters (i.e. are primary ignorable)
+ "\\u0e01\\u0e32", "<", "\\u0e01\\u0e49\\u0e32",
+
+ // ditto for other over-marks
+ "\\u0e01\\u0e32", "<", "\\u0e01\\u0e32\\u0e4c",
+
+ // commonly used mark-in-context order.
+ // In effect, marks are sorted after each syllable.
+ "\\u0e01\\u0e32\\u0e01\\u0e49\\u0e32", "<", "\\u0e01\\u0e48\\u0e32\\u0e01\\u0e49\\u0e32",
+
+ // Hyphens and other punctuation follow whitespace but come before letters
+ "\\u0e01\\u0e32", "<", "\\u0e01\\u0e32-",
+ "\\u0e01\\u0e32-", "<", "\\u0e01\\u0e32\\u0e01\\u0e32",
+
+ // Doubler follows an indentical word without the doubler
+ "\\u0e01\\u0e32", "<", "\\u0e01\\u0e32\\u0e46",
+ "\\u0e01\\u0e32\\u0e46", "<", "\\u0e01\\u0e32\\u0e01\\u0e32",
+
+
+ // \\u0e45 after either \\u0e24 or \\u0e26 is treated as a single
+ // combining character, similar to "c < ch" in traditional spanish.
+ // TODO: beef up this case
+ "\\u0e24\\u0e29\\u0e35", "<", "\\u0e24\\u0e45\\u0e29\\u0e35",
+ "\\u0e26\\u0e29\\u0e35", "<", "\\u0e26\\u0e45\\u0e29\\u0e35",
+
+ // Vowels reorder, should compare \\u0e2d and \\u0e34
+ "\\u0e40\\u0e01\\u0e2d", "<", "\\u0e40\\u0e01\\u0e34",
+
+ // Tones are compared after the rest of the word (e.g. primary ignorable)
+ "\\u0e01\\u0e32\\u0e01\\u0e48\\u0e32", "<", "\\u0e01\\u0e49\\u0e32\\u0e01\\u0e32",
+
+ // Periods are ignored entirely
+ "\\u0e01.\\u0e01.", "<", "\\u0e01\\u0e32",
+ };
+ const int32_t TESTS_length = (int32_t)(sizeof(TESTS)/sizeof(TESTS[0]));
+
+ if (coll == 0) {
+ errln("Error: could not construct Thai collator");
+ return;
+ }
+ compareArray(*coll, TESTS, TESTS_length);
+}
+
+//------------------------------------------------------------------------
+// Internal utilities
+//------------------------------------------------------------------------
+
+void CollationThaiTest::compareArray(Collator& c, const char* tests[],
+ int32_t testsLength) {
+ for (int32_t i = 0; i < testsLength; i += 3) {
+
+ Collator::EComparisonResult expect;
+ if (tests[i+1][0] == '<') {
+ expect = Collator::LESS;
+ } else if (tests[i+1][0] == '>') {
+ expect = Collator::GREATER;
+ } else if (tests[i+1][0] == '=') {
+ expect = Collator::EQUAL;
+ } else {
+ // expect = Integer.decode(tests[i+1]).intValue();
+ errln((UnicodeString)"Error: unknown operator " + tests[i+1]);
+ return;
+ }
+
+ UnicodeString s1, s2;
+ parseChars(s1, tests[i]);
+ parseChars(s2, tests[i+2]);
+
+ doTest(&c, s1, s2, expect);
+#if 0
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t result = c.compare(s1, s2);
+ if (sign(result) != sign(expect))
+ {
+ UnicodeString t1, t2;
+ errln(UnicodeString("") +
+ i/3 + ": compare(" + IntlTest::prettify(s1, t1)
+ + " , " + IntlTest::prettify(s2, t2)
+ + ") got " + result + "; expected " + expect);
+
+ CollationKey k1, k2;
+ c.getCollationKey(s1, k1, status);
+ c.getCollationKey(s2, k2, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"Fail: getCollationKey returned " + u_errorName(status));
+ return;
+ }
+ errln((UnicodeString)" key1: " + prettify(k1, t1) );
+ errln((UnicodeString)" key2: " + prettify(k2, t2) );
+ }
+ else
+ {
+ // Collator.compare worked OK; now try the collation keys
+ CollationKey k1, k2;
+ c.getCollationKey(s1, k1, status);
+ c.getCollationKey(s2, k2, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"Fail: getCollationKey returned " + u_errorName(status));
+ return;
+ }
+
+ result = k1.compareTo(k2);
+ if (sign(result) != sign(expect)) {
+ UnicodeString t1, t2;
+ errln(UnicodeString("") +
+ i/3 + ": key(" + IntlTest::prettify(s1, t1)
+ + ").compareTo(key(" + IntlTest::prettify(s2, t2)
+ + ")) got " + result + "; expected " + expect);
+
+ errln((UnicodeString)" " + prettify(k1, t1) + " vs. " + prettify(k2, t2));
+ }
+ }
+#endif
+ }
+}
+
+int8_t CollationThaiTest::sign(int32_t i) {
+ if (i < 0) return -1;
+ if (i > 0) return 1;
+ return 0;
+}
+
+/**
+ * Set a UnicodeString corresponding to the given string. Use
+ * UnicodeString and the default converter, unless we see the sequence
+ * "\\u", in which case we interpret the subsequent escape.
+ */
+UnicodeString& CollationThaiTest::parseChars(UnicodeString& result,
+ const char* chars) {
+ return result = CharsToUnicodeString(chars);
+}
+
+UCollator *thaiColl = NULL;
+
+U_CDECL_BEGIN
+static int U_CALLCONV
+StrCmp(const void *p1, const void *p2) {
+ return ucol_strcoll(thaiColl, *(UChar **) p1, -1, *(UChar **)p2, -1);
+}
+U_CDECL_END
+
+
+#define LINES 6
+
+void CollationThaiTest::TestInvalidThai(void) {
+ const char *tests[LINES] = {
+ "\\u0E44\\u0E01\\u0E44\\u0E01",
+ "\\u0E44\\u0E01\\u0E01\\u0E44",
+ "\\u0E01\\u0E44\\u0E01\\u0E44",
+ "\\u0E01\\u0E01\\u0E44\\u0E44",
+ "\\u0E44\\u0E44\\u0E01\\u0E01",
+ "\\u0E01\\u0E44\\u0E44\\u0E01",
+ };
+
+ UChar strings[LINES][20];
+
+ UChar *toSort[LINES];
+
+ int32_t i = 0, j = 0, len = 0;
+
+ UErrorCode coll_status = U_ZERO_ERROR;
+ UnicodeString iteratorText;
+
+ thaiColl = ucol_open ("th_TH", &coll_status);
+ if (U_FAILURE(coll_status)) {
+ errln("Error opening Thai collator: %s", u_errorName(coll_status));
+ return;
+ }
+
+ CollationElementIterator* c = ((RuleBasedCollator *)coll)->createCollationElementIterator( iteratorText );
+
+ for(i = 0; i < (int32_t)(sizeof(tests)/sizeof(tests[0])); i++) {
+ len = u_unescape(tests[i], strings[i], 20);
+ strings[i][len] = 0;
+ toSort[i] = strings[i];
+ }
+
+ qsort (toSort, LINES, sizeof (UChar *), StrCmp);
+
+ for (i=0; i < LINES; i++)
+ {
+ logln("%i", i);
+ for (j=i+1; j < LINES; j++) {
+ if (ucol_strcoll (thaiColl, toSort[i], -1, toSort[j], -1) == UCOL_GREATER)
+ {
+ // inconsistency ordering found!
+ errln("Inconsistent ordering between strings %i and %i", i, j);
+ }
+ }
+ iteratorText.setTo(toSort[i]);
+ c->setText(iteratorText, coll_status);
+ backAndForth(*c);
+ }
+
+
+ ucol_close(thaiColl);
+ delete c;
+}
+
+void CollationThaiTest::TestReordering(void) {
+ const char *tests[] = {
+ "\\u0E41c\\u0301", "=", "\\u0E41\\u0107", // composition
+ "\\u0E41\\uD835\\uDFCE", "<", "\\u0E41\\uD835\\uDFCF", // supplementaries
+ "\\u0E41\\uD834\\uDD5F", "=", "\\u0E41\\uD834\\uDD58\\uD834\\uDD65", // supplementary composition decomps to supplementary
+ "\\u0E41\\uD87E\\uDC02", "=", "\\u0E41\\u4E41", // supplementary composition decomps to BMP
+ "\\u0E41\\u0301", "=", "\\u0E41\\u0301", // unsafe (just checking backwards iteration)
+ "\\u0E41\\u0301\\u0316", "=", "\\u0E41\\u0316\\u0301",
+ // after UCA 4.1, the two lines below are not equal anymore do not have equal sign
+ "\\u0e24\\u0e41", "<", "\\u0e41\\u0e24", // exiting contraction bug
+ "\\u0e3f\\u0e3f\\u0e24\\u0e41", "<", "\\u0e3f\\u0e3f\\u0e41\\u0e24",
+
+ "abc\\u0E41c\\u0301", "=", "abc\\u0E41\\u0107", // composition
+ "abc\\u0E41\\uD834\\uDC00", "<", "abc\\u0E41\\uD834\\uDC01", // supplementaries
+ "abc\\u0E41\\uD834\\uDD5F", "=", "abc\\u0E41\\uD834\\uDD58\\uD834\\uDD65", // supplementary composition decomps to supplementary
+ "abc\\u0E41\\uD87E\\uDC02", "=", "abc\\u0E41\\u4E41", // supplementary composition decomps to BMP
+ "abc\\u0E41\\u0301", "=", "abc\\u0E41\\u0301", // unsafe (just checking backwards iteration)
+ "abc\\u0E41\\u0301\\u0316", "=", "abc\\u0E41\\u0316\\u0301",
+
+ "\\u0E41c\\u0301abc", "=", "\\u0E41\\u0107abc", // composition
+ "\\u0E41\\uD834\\uDC00abc", "<", "\\u0E41\\uD834\\uDC01abc", // supplementaries
+ "\\u0E41\\uD834\\uDD5Fabc", "=", "\\u0E41\\uD834\\uDD58\\uD834\\uDD65abc", // supplementary composition decomps to supplementary
+ "\\u0E41\\uD87E\\uDC02abc", "=", "\\u0E41\\u4E41abc", // supplementary composition decomps to BMP
+ "\\u0E41\\u0301abc", "=", "\\u0E41\\u0301abc", // unsafe (just checking backwards iteration)
+ "\\u0E41\\u0301\\u0316abc", "=", "\\u0E41\\u0316\\u0301abc",
+
+ "abc\\u0E41c\\u0301abc", "=", "abc\\u0E41\\u0107abc", // composition
+ "abc\\u0E41\\uD834\\uDC00abc", "<", "abc\\u0E41\\uD834\\uDC01abc", // supplementaries
+ "abc\\u0E41\\uD834\\uDD5Fabc", "=", "abc\\u0E41\\uD834\\uDD58\\uD834\\uDD65abc", // supplementary composition decomps to supplementary
+ "abc\\u0E41\\uD87E\\uDC02abc", "=", "abc\\u0E41\\u4E41abc", // supplementary composition decomps to BMP
+ "abc\\u0E41\\u0301abc", "=", "abc\\u0E41\\u0301abc", // unsafe (just checking backwards iteration)
+ "abc\\u0E41\\u0301\\u0316abc", "=", "abc\\u0E41\\u0316\\u0301abc",
+ };
+
+ compareArray(*coll, tests, sizeof(tests)/sizeof(tests[0]));
+
+ const char *rule = "& c < ab";
+ const char *testcontraction[] = { "\\u0E41ab", ">", "\\u0E41c"}; // After UCA 4.1 Thai are normal so won't break a contraction
+ UnicodeString rules;
+ UErrorCode status = U_ZERO_ERROR;
+ parseChars(rules, rule);
+ RuleBasedCollator *rcoll = new RuleBasedCollator(rules, status);
+ if(U_SUCCESS(status)) {
+ compareArray(*rcoll, testcontraction, 3);
+ delete rcoll;
+ } else {
+ errln("Couldn't instantiate collator from rules");
+ }
+
+}
+
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/thcoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/thcoll.h
new file mode 100644
index 00000000000..2b10c201118
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/thcoll.h
@@ -0,0 +1,80 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2003, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 12/09/99 aliu Ported from Java.
+**********************************************************************
+*/
+
+#ifndef COLLATIONTHAITEST_H
+#define COLLATIONTHAITEST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class CollationThaiTest : public IntlTestCollator {
+ Collator* coll; // Thai collator
+
+public:
+
+ CollationThaiTest();
+ virtual ~CollationThaiTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+private:
+
+ /**
+ * Read the external dictionary file, which is already in proper
+ * sorted order, and confirm that the collator compares each line as
+ * preceding the following line.
+ */
+ void TestDictionary(void);
+
+ /**
+ * Odd corner conditions taken from "How to Sort Thai Without Rewriting Sort",
+ * by Doug Cooper, http://seasrc.th.net/paper/thaisort.zip
+ */
+ void TestCornerCases(void);
+
+ /**
+ * Read the external names list, and confirms that the collator
+ * gets the same results when comparing lines one to another
+ * using regular and iterative comparison.
+ */
+ void TestNamesList(void);
+
+ /**
+ * test that invalid Thai sorts properly
+ */
+ void TestInvalidThai(void);
+
+ /**
+ * test that reording is done properly
+ */
+ void TestReordering(void);
+
+private:
+
+ void compareArray(Collator& c, const char* tests[],
+ int32_t testsLength);
+
+ int8_t sign(int32_t i);
+
+ /**
+ * Set a UnicodeString corresponding to the given string. Use
+ * UnicodeString and the default converter, unless we see the sequence
+ * "\\u", in which case we interpret the subsequent escape.
+ */
+ UnicodeString& parseChars(UnicodeString& result,
+ const char* chars);
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tmsgfmt.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tmsgfmt.cpp
new file mode 100644
index 00000000000..aef0179f167
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tmsgfmt.cpp
@@ -0,0 +1,1256 @@
+/********************************************************************
+ * Copyright (c) 1997-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************
+ * File TMSGFMT.CPP
+ *
+ * Modification History:
+ *
+ * Date Name Description
+ * 03/24/97 helena Converted from Java.
+ * 07/11/97 helena Updated to work on AIX.
+ * 08/04/97 jfitz Updated to intltest
+ *******************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tmsgfmt.h"
+
+#include "unicode/format.h"
+#include "unicode/decimfmt.h"
+#include "unicode/locid.h"
+#include "unicode/msgfmt.h"
+#include "unicode/numfmt.h"
+#include "unicode/choicfmt.h"
+#include "unicode/gregocal.h"
+#include <stdio.h>
+
+void
+TestMessageFormat::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ TESTCASE(0,testBug1);
+ TESTCASE(1,testBug2);
+ TESTCASE(2,sample);
+ TESTCASE(3,PatternTest);
+ TESTCASE(4,testStaticFormat);
+ TESTCASE(5,testSimpleFormat);
+ TESTCASE(6,testMsgFormatChoice);
+ TESTCASE(7,testCopyConstructor);
+ TESTCASE(8,testAssignment);
+ TESTCASE(9,testClone);
+ TESTCASE(10,testEquals);
+ TESTCASE(11,testNotEquals);
+ TESTCASE(12,testSetLocale);
+ TESTCASE(13,testFormat);
+ TESTCASE(14,testParse);
+ TESTCASE(15,testAdopt);
+ TESTCASE(16,testCopyConstructor2);
+ TESTCASE(17,TestUnlimitedArgsAndSubformats);
+ TESTCASE(18,TestRBNF);
+ TESTCASE(19,TestTurkishCasing);
+ TESTCASE(20,testAutoQuoteApostrophe);
+ default: name = ""; break;
+ }
+}
+
+void TestMessageFormat::testBug3()
+{
+ double myNumber = -123456;
+ DecimalFormat *form = 0;
+ Locale locale[] = {
+ Locale("ar", "", ""),
+ Locale("be", "", ""),
+ Locale("bg", "", ""),
+ Locale("ca", "", ""),
+ Locale("cs", "", ""),
+ Locale("da", "", ""),
+ Locale("de", "", ""),
+ Locale("de", "AT", ""),
+ Locale("de", "CH", ""),
+ Locale("el", "", ""), // 10
+ Locale("en", "CA", ""),
+ Locale("en", "GB", ""),
+ Locale("en", "IE", ""),
+ Locale("en", "US", ""),
+ Locale("es", "", ""),
+ Locale("et", "", ""),
+ Locale("fi", "", ""),
+ Locale("fr", "", ""),
+ Locale("fr", "BE", ""),
+ Locale("fr", "CA", ""), // 20
+ Locale("fr", "CH", ""),
+ Locale("he", "", ""),
+ Locale("hr", "", ""),
+ Locale("hu", "", ""),
+ Locale("is", "", ""),
+ Locale("it", "", ""),
+ Locale("it", "CH", ""),
+ Locale("ja", "", ""),
+ Locale("ko", "", ""),
+ Locale("lt", "", ""), // 30
+ Locale("lv", "", ""),
+ Locale("mk", "", ""),
+ Locale("nl", "", ""),
+ Locale("nl", "BE", ""),
+ Locale("no", "", ""),
+ Locale("pl", "", ""),
+ Locale("pt", "", ""),
+ Locale("ro", "", ""),
+ Locale("ru", "", ""),
+ Locale("sh", "", ""), // 40
+ Locale("sk", "", ""),
+ Locale("sl", "", ""),
+ Locale("sq", "", ""),
+ Locale("sr", "", ""),
+ Locale("sv", "", ""),
+ Locale("tr", "", ""),
+ Locale("uk", "", ""),
+ Locale("zh", "", ""),
+ Locale("zh", "TW", "") // 49
+ };
+ int32_t i;
+ for (i= 0; i < 49; i++) {
+ UnicodeString buffer;
+ logln(locale[i].getDisplayName(buffer));
+ UErrorCode success = U_ZERO_ERROR;
+// form = (DecimalFormat*)NumberFormat::createCurrencyInstance(locale[i], success);
+ form = (DecimalFormat*)NumberFormat::createInstance(locale[i], success);
+ if (U_FAILURE(success)) {
+ errln("Err: Number Format ");
+ logln("Number format creation failed.");
+ continue;
+ }
+ Formattable result;
+ FieldPosition pos(0);
+ buffer.remove();
+ form->format(myNumber, buffer, pos);
+ success = U_ZERO_ERROR;
+ ParsePosition parsePos;
+ form->parse(buffer, result, parsePos);
+ logln(UnicodeString(" -> ") /* + << dec*/ + toString(result) + UnicodeString("[supposed output for result]"));
+ if (U_FAILURE(success)) {
+ errln("Err: Number Format parse");
+ logln("Number format parse failed.");
+ }
+ delete form;
+ }
+}
+
+void TestMessageFormat::testBug1()
+{
+ const double limit[] = {0.0, 1.0, 2.0};
+ const UnicodeString formats[] = {"0.0<=Arg<1.0",
+ "1.0<=Arg<2.0",
+ "2.0<-Arg"};
+ ChoiceFormat *cf = new ChoiceFormat(limit, formats, 3);
+ FieldPosition status(0);
+ UnicodeString toAppendTo;
+ cf->format((int32_t)1, toAppendTo, status);
+ if (toAppendTo != "1.0<=Arg<2.0") {
+ errln("ChoiceFormat cmp in testBug1");
+ }
+ logln(toAppendTo);
+ delete cf;
+}
+
+void TestMessageFormat::testBug2()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString result;
+ // {sfb} use double format in pattern, so result will match (not strictly necessary)
+ const UnicodeString pattern = "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}. ";
+ logln("The input pattern : " + pattern);
+ MessageFormat *fmt = new MessageFormat(pattern, status);
+ if (U_FAILURE(status)) {
+ errln("MessageFormat pattern creation failed.");
+ return;
+ }
+ logln("The output pattern is : " + fmt->toPattern(result));
+ if (pattern != result) {
+ errln("MessageFormat::toPattern() failed.");
+ }
+ delete fmt;
+}
+
+#if 0
+#if defined(_DEBUG) && U_IOSTREAM_SOURCE!=0
+//----------------------------------------------------
+// console I/O
+//----------------------------------------------------
+
+#if U_IOSTREAM_SOURCE >= 199711
+# include <iostream>
+ std::ostream& operator<<(std::ostream& stream, const Formattable& obj);
+#elif U_IOSTREAM_SOURCE >= 198506
+# include <iostream.h>
+ ostream& operator<<(ostream& stream, const Formattable& obj);
+#endif
+
+#include "unicode/datefmt.h"
+#include <stdlib.h>
+#include <string.h>
+
+IntlTest&
+operator<<( IntlTest& stream,
+ const Formattable& obj)
+{
+ static DateFormat *defDateFormat = 0;
+
+ UnicodeString buffer;
+ switch(obj.getType()) {
+ case Formattable::kDate :
+ if (defDateFormat == 0) {
+ defDateFormat = DateFormat::createInstance();
+ }
+ defDateFormat->format(obj.getDate(), buffer);
+ stream << buffer;
+ break;
+ case Formattable::kDouble :
+ char convert[20];
+ sprintf( convert, "%lf", obj.getDouble() );
+ stream << convert << "D";
+ break;
+ case Formattable::kLong :
+ stream << obj.getLong() << "L";
+ break;
+ case Formattable::kString:
+ stream << "\"" << obj.getString(buffer) << "\"";
+ break;
+ case Formattable::kArray:
+ int32_t i, count;
+ const Formattable* array;
+ array = obj.getArray(count);
+ stream << "[";
+ for (i=0; i<count; ++i) stream << array[i] << ( (i==(count-1)) ? "" : ", " );
+ stream << "]";
+ break;
+ default:
+ stream << "INVALID_Formattable";
+ }
+ return stream;
+}
+#endif /* defined(_DEBUG) && U_IOSTREAM_SOURCE!=0 */
+#endif
+
+void TestMessageFormat::PatternTest()
+{
+ Formattable testArgs[] = {
+ Formattable(double(1)), Formattable(double(3456)),
+ Formattable("Disk"), Formattable(UDate((int32_t)1000000000L), Formattable::kIsDate)
+ };
+ UnicodeString testCases[] = {
+ "Quotes '', '{', 'a' {0} '{0}'",
+ "Quotes '', '{', 'a' {0,number} '{0}'",
+ "'{'1,number,'#',##} {1,number,'#',##}",
+ "There are {1} files on {2} at {3}.",
+ "On {2}, there are {1} files, with {0,number,currency}.",
+ "'{1,number,percent}', {1,number,percent},",
+ "'{1,date,full}', {1,date,full},",
+ "'{3,date,full}', {3,date,full},",
+ "'{1,number,#,##}' {1,number,#,##}",
+ };
+
+ UnicodeString testResultPatterns[] = {
+ "Quotes '', '{', a {0} '{'0}",
+ "Quotes '', '{', a {0,number} '{'0}",
+ "'{'1,number,#,##} {1,number,'#'#,##}",
+ "There are {1} files on {2} at {3}.",
+ "On {2}, there are {1} files, with {0,number,currency}.",
+ "'{'1,number,percent}, {1,number,percent},",
+ "'{'1,date,full}, {1,date,full},",
+ "'{'3,date,full}, {3,date,full},",
+ "'{'1,number,#,##} {1,number,#,##}"
+ };
+
+ UnicodeString testResultStrings[] = {
+ "Quotes ', {, a 1 {0}",
+ "Quotes ', {, a 1 {0}",
+ "{1,number,#,##} #34,56",
+ "There are 3,456 files on Disk at 1/12/70 5:46 AM.",
+ "On Disk, there are 3,456 files, with $1.00.",
+ "{1,number,percent}, 345,600%,",
+ "{1,date,full}, Wednesday, December 31, 1969,",
+ "{3,date,full}, Monday, January 12, 1970,",
+ "{1,number,#,##} 34,56"
+ };
+
+
+ for (int32_t i = 0; i < 9; ++i) {
+ //it_out << "\nPat in: " << testCases[i]);
+
+ MessageFormat *form = 0;
+ UErrorCode success = U_ZERO_ERROR;
+ UnicodeString buffer;
+ form = new MessageFormat(testCases[i], Locale::getUS(), success);
+ if (U_FAILURE(success)) {
+ errln("MessageFormat creation failed.#1");
+ logln(((UnicodeString)"MessageFormat for ") + testCases[i] + " creation failed.\n");
+ continue;
+ }
+ if (form->toPattern(buffer) != testResultPatterns[i]) {
+ errln(UnicodeString("TestMessageFormat::PatternTest failed test #2, i = ") + i);
+ //form->toPattern(buffer);
+ errln(((UnicodeString)" Orig: ") + testCases[i]);
+ errln(((UnicodeString)" Exp: ") + testResultPatterns[i]);
+ errln(((UnicodeString)" Got: ") + buffer);
+ }
+
+ //it_out << "Pat out: " << form->toPattern(buffer));
+ UnicodeString result;
+ int32_t count = 4;
+ FieldPosition fieldpos(0);
+ form->format(testArgs, count, result, fieldpos, success);
+ if (U_FAILURE(success)) {
+ errln("MessageFormat failed test #3");
+ logln("TestMessageFormat::PatternTest failed test #3");
+ continue;
+ }
+ if (result != testResultStrings[i]) {
+ errln("TestMessageFormat::PatternTest failed test #4");
+ logln("TestMessageFormat::PatternTest failed #4.");
+ logln(UnicodeString(" Result: ") + result );
+ logln(UnicodeString(" Expected: ") + testResultStrings[i] );
+ }
+
+
+ //it_out << "Result: " << result);
+#if 0
+ /* TODO: Look at this test and see if this is still a valid test */
+ logln("---------------- test parse ----------------");
+
+ form->toPattern(buffer);
+ logln("MSG pattern for parse: " + buffer);
+
+ int32_t parseCount = 0;
+ Formattable* values = form->parse(result, parseCount, success);
+ if (U_FAILURE(success)) {
+ errln("MessageFormat failed test #5");
+ logln(UnicodeString("MessageFormat failed test #5 with error code ")+(int32_t)success);
+ } else if (parseCount != count) {
+ errln("MSG count not %d as expected. Got %d", count, parseCount);
+ }
+ UBool failed = FALSE;
+ for (int32_t j = 0; j < parseCount; ++j) {
+ if (values == 0 || testArgs[j] != values[j]) {
+ errln(((UnicodeString)"MSG testargs[") + j + "]: " + toString(testArgs[j]));
+ errln(((UnicodeString)"MSG values[") + j + "] : " + toString(values[j]));
+ failed = TRUE;
+ }
+ }
+ if (failed)
+ errln("MessageFormat failed test #6");
+#endif
+ delete form;
+ }
+}
+
+void TestMessageFormat::sample()
+{
+ MessageFormat *form = 0;
+ UnicodeString buffer1, buffer2;
+ UErrorCode success = U_ZERO_ERROR;
+ form = new MessageFormat("There are {0} files on {1}", success);
+ if (U_FAILURE(success)) {
+ errln("Err: Message format creation failed");
+ logln("Sample message format creation failed.");
+ return;
+ }
+ UnicodeString abc("abc");
+ UnicodeString def("def");
+ Formattable testArgs1[] = { abc, def };
+ FieldPosition fieldpos(0);
+ assertEquals("format",
+ "There are abc files on def",
+ form->format(testArgs1, 2, buffer2, fieldpos, success));
+ assertSuccess("format", success);
+ delete form;
+}
+
+void TestMessageFormat::testStaticFormat()
+{
+ UErrorCode err = U_ZERO_ERROR;
+ Formattable arguments[] = {
+ (int32_t)7,
+ Formattable(UDate(8.71068e+011), Formattable::kIsDate),
+ "a disturbance in the Force"
+ };
+
+ UnicodeString result;
+ result = MessageFormat::format(
+ "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
+ arguments,
+ 3,
+ result,
+ err);
+
+ if (U_FAILURE(err)) {
+ errln("TestMessageFormat::testStaticFormat #1");
+ logln(UnicodeString("TestMessageFormat::testStaticFormat failed test #1 with error code ")+(int32_t)err);
+ return;
+ }
+
+ const UnicodeString expected(
+ "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", "");
+ if (result != expected) {
+ errln("TestMessageFormat::testStaticFormat failed on test");
+ logln( UnicodeString(" Result: ") + result );
+ logln( UnicodeString(" Expected: ") + expected );
+ }
+}
+
+/* When the default locale is tr, make sure that the pattern can still be parsed. */
+void TestMessageFormat::TestTurkishCasing()
+{
+ UErrorCode err = U_ZERO_ERROR;
+ Locale saveDefaultLocale;
+ Locale::setDefault( Locale("tr"), err );
+
+ Formattable arguments[] = {
+ (int32_t)7,
+ Formattable(UDate(8.71068e+011), Formattable::kIsDate),
+ "a disturbance in the Force"
+ };
+
+ UnicodeString result;
+ result = MessageFormat::format(
+ "At {1,TIME} on {1,DATE,SHORT}, there was {2} on planet {0,NUMBER,INTEGER}.",
+ arguments,
+ 3,
+ result,
+ err);
+
+ if (U_FAILURE(err)) {
+ errln("TestTurkishCasing #1 with error code %s", u_errorName(err));
+ return;
+ }
+
+ const UnicodeString expected(
+ "At 12:20:00 on 08.08.1997, there was a disturbance in the Force on planet 7.", "");
+ if (result != expected) {
+ errln("TestTurkishCasing failed on test");
+ errln( UnicodeString(" Result: ") + result );
+ errln( UnicodeString(" Expected: ") + expected );
+ }
+ Locale::setDefault( saveDefaultLocale, err );
+}
+
+void TestMessageFormat::testSimpleFormat(/* char* par */)
+{
+ logln("running TestMessageFormat::testSimpleFormat");
+
+ UErrorCode err = U_ZERO_ERROR;
+
+ Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
+ Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
+ Formattable testArgs3[] = {(int32_t)12, "MyDisk"};
+
+ MessageFormat* form = new MessageFormat(
+ "The disk \"{1}\" contains {0} file(s).", err);
+
+ UnicodeString string;
+ FieldPosition ignore(FieldPosition::DONT_CARE);
+ form->format(testArgs1, 2, string, ignore, err);
+ if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 0 file(s).") {
+ errln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #1"));
+ }
+
+ ignore.setField(FieldPosition::DONT_CARE);
+ string.remove();
+ form->format(testArgs2, 2, string, ignore, err);
+ if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 1 file(s).") {
+ logln(string);
+ errln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #2")+string);
+ }
+
+ ignore.setField(FieldPosition::DONT_CARE);
+ string.remove();
+ form->format(testArgs3, 2, string, ignore, err);
+ if (U_FAILURE(err) || string != "The disk \"MyDisk\" contains 12 file(s).") {
+ errln(UnicodeString("TestMessageFormat::testSimpleFormat failed on test #3")+string);
+ }
+
+ delete form;
+ }
+
+void TestMessageFormat::testMsgFormatChoice(/* char* par */)
+{
+ logln("running TestMessageFormat::testMsgFormatChoice");
+
+ UErrorCode err = U_ZERO_ERROR;
+
+ MessageFormat* form = new MessageFormat("The disk \"{1}\" contains {0}.", err);
+ double filelimits[] = {0,1,2};
+ UnicodeString filepart[] = {"no files","one file","{0,number} files"};
+ ChoiceFormat* fileform = new ChoiceFormat(filelimits, filepart, 3);
+ form->setFormat(1,*fileform); // NOT zero, see below
+ //is the format adopted?
+
+ FieldPosition ignore(FieldPosition::DONT_CARE);
+ UnicodeString string;
+ Formattable testArgs1[] = {(int32_t)0, "MyDisk"};
+ form->format(testArgs1, 2, string, ignore, err);
+ if (string != "The disk \"MyDisk\" contains no files.") {
+ errln("TestMessageFormat::testMsgFormatChoice failed on test #1");
+ }
+
+ ignore.setField(FieldPosition::DONT_CARE);
+ string.remove();
+ Formattable testArgs2[] = {(int32_t)1, "MyDisk"};
+ form->format(testArgs2, 2, string, ignore, err);
+ if (string != "The disk \"MyDisk\" contains one file.") {
+ errln("TestMessageFormat::testMsgFormatChoice failed on test #2");
+ }
+
+ ignore.setField(FieldPosition::DONT_CARE);
+ string.remove();
+ Formattable testArgs3[] = {(int32_t)1273, "MyDisk"};
+ form->format(testArgs3, 2, string, ignore, err);
+ if (string != "The disk \"MyDisk\" contains 1,273 files.") {
+ errln("TestMessageFormat::testMsgFormatChoice failed on test #3");
+ }
+
+ delete form;
+ delete fileform;
+}
+
+
+//---------------------------------
+// API Tests
+//---------------------------------
+
+void TestMessageFormat::testCopyConstructor()
+{
+ UErrorCode success = U_ZERO_ERROR;
+ MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
+ MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
+ MessageFormat *y = 0;
+ y = new MessageFormat(*x);
+ if ( (*x == *y) &&
+ (*x != *z) &&
+ (*y != *z) )
+ logln("First test (operator ==): Passed!");
+ else {
+ errln("TestMessageFormat::testCopyConstructor failed #1");
+ logln("First test (operator ==): Failed!");
+ }
+ if ( ((*x == *y) && (*y == *x)) &&
+ ((*x != *z) && (*z != *x)) &&
+ ((*y != *z) && (*z != *y)) )
+ logln("Second test (equals): Passed!");
+ else {
+ errln("TestMessageFormat::testCopyConstructor failed #2");
+ logln("Second test (equals): Failed!");
+ }
+
+ delete x;
+ delete y;
+ delete z;
+}
+
+
+void TestMessageFormat::testAssignment()
+{
+ UErrorCode success = U_ZERO_ERROR;
+ MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
+ MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
+ MessageFormat *y = new MessageFormat("There are {0} files on {1} created", success);
+ *y = *x;
+ if ( (*x == *y) &&
+ (*x != *z) &&
+ (*y != *z) )
+ logln("First test (operator ==): Passed!");
+ else {
+ errln( "TestMessageFormat::testAssignment failed #1");
+ logln("First test (operator ==): Failed!");
+ }
+ if ( ((*x == *y) && (*y == *x)) &&
+ ((*x != *z) && (*z != *x)) &&
+ ((*y != *z) && (*z != *y)) )
+ logln("Second test (equals): Passed!");
+ else {
+ errln("TestMessageFormat::testAssignment failed #2");
+ logln("Second test (equals): Failed!");
+ }
+
+ delete x;
+ delete y;
+ delete z;
+}
+
+void TestMessageFormat::testClone()
+{
+ UErrorCode success = U_ZERO_ERROR;
+ MessageFormat *x = new MessageFormat("There are {0} files on {1}", success);
+ MessageFormat *z = new MessageFormat("There are {0} files on {1} created", success);
+ MessageFormat *y = 0;
+ y = (MessageFormat*)x->clone();
+ if ( (*x == *y) &&
+ (*x != *z) &&
+ (*y != *z) )
+ logln("First test (operator ==): Passed!");
+ else {
+ errln("TestMessageFormat::testClone failed #1");
+ logln("First test (operator ==): Failed!");
+ }
+ if ( ((*x == *y) && (*y == *x)) &&
+ ((*x != *z) && (*z != *x)) &&
+ ((*y != *z) && (*z != *y)) )
+ logln("Second test (equals): Passed!");
+ else {
+ errln("TestMessageFormat::testClone failed #2");
+ logln("Second test (equals): Failed!");
+ }
+
+ delete x;
+ delete y;
+ delete z;
+}
+
+void TestMessageFormat::testEquals()
+{
+ UErrorCode success = U_ZERO_ERROR;
+ MessageFormat x("There are {0} files on {1}", success);
+ MessageFormat y("There are {0} files on {1}", success);
+ if (!(x == y)) {
+ errln( "TestMessageFormat::testEquals failed #1");
+ logln("First test (operator ==): Failed!");
+ }
+
+}
+
+void TestMessageFormat::testNotEquals()
+{
+ UErrorCode success = U_ZERO_ERROR;
+ MessageFormat x("There are {0} files on {1}", success);
+ MessageFormat y(x);
+ y.setLocale(Locale("fr"));
+ if (!(x != y)) {
+ errln( "TestMessageFormat::testEquals failed #1");
+ logln("First test (operator !=): Failed!");
+ }
+ y = x;
+ y.applyPattern("There are {0} files on {1} the disk", success);
+ if (!(x != y)) {
+ errln( "TestMessageFormat::testEquals failed #1");
+ logln("Second test (operator !=): Failed!");
+ }
+}
+
+
+void TestMessageFormat::testSetLocale()
+{
+ UErrorCode err = U_ZERO_ERROR;
+ GregorianCalendar cal(err);
+ Formattable arguments[] = {
+ 456.83,
+ Formattable(UDate(8.71068e+011), Formattable::kIsDate),
+ "deposit"
+ };
+
+ UnicodeString result;
+
+ //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
+ UnicodeString formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
+ // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
+ // Just use unlocalized currency symbol.
+ //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
+ UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of ";
+ compareStrEng += (UChar) 0x00a4;
+ compareStrEng += "456.83.";
+ // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
+ // Just use unlocalized currency symbol.
+ //UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM.";
+ UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of ";
+ compareStrGer += "456,83 ";
+ compareStrGer += (UChar) 0x00a4;
+ compareStrGer += ".";
+
+ MessageFormat msg( formatStr, err);
+ result = "";
+ FieldPosition pos(0);
+ result = msg.format(
+ arguments,
+ 3,
+ result,
+ pos,
+ err);
+
+ logln(result);
+ if (result != compareStrEng) {
+ errln("*** MSG format err.");
+ }
+
+ msg.setLocale(Locale::getEnglish());
+ UBool getLocale_ok = TRUE;
+ if (msg.getLocale() != Locale::getEnglish()) {
+ errln("*** MSG getLocal err.");
+ getLocale_ok = FALSE;
+ }
+
+ msg.setLocale(Locale::getGerman());
+
+ if (msg.getLocale() != Locale::getGerman()) {
+ errln("*** MSG getLocal err.");
+ getLocale_ok = FALSE;
+ }
+
+ msg.applyPattern( formatStr, err);
+
+ pos.setField(0);
+ result = "";
+ result = msg.format(
+ arguments,
+ 3,
+ result,
+ pos,
+ err);
+
+ logln(result);
+ if (result == compareStrGer) {
+ logln("MSG setLocale tested.");
+ }else{
+ errln( "*** MSG setLocale err.");
+ }
+
+ if (getLocale_ok) {
+ logln("MSG getLocale tested.");
+ }
+}
+
+void TestMessageFormat::testFormat()
+{
+ UErrorCode err = U_ZERO_ERROR;
+ GregorianCalendar cal(err);
+
+ const Formattable ftarray[] =
+ {
+ Formattable( UDate(8.71068e+011), Formattable::kIsDate )
+ };
+ const int32_t ft_cnt = sizeof(ftarray) / sizeof(Formattable);
+ Formattable ft_arr( ftarray, ft_cnt );
+
+ Formattable* fmt = new Formattable(UDate(8.71068e+011), Formattable::kIsDate);
+
+ UnicodeString result;
+
+ //UnicodeString formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
+ UnicodeString formatStr = "On {0,date}, it began.";
+ UnicodeString compareStr = "On Aug 8, 1997, it began.";
+
+ err = U_ZERO_ERROR;
+ MessageFormat msg( formatStr, err);
+ FieldPosition fp(0);
+
+ result = "";
+ fp = 0;
+ result = msg.format(
+ *fmt,
+ result,
+ //FieldPosition(0),
+ fp,
+ err);
+
+ if (err != U_ILLEGAL_ARGUMENT_ERROR) {
+ errln("*** MSG format without expected error code.");
+ }
+ err = U_ZERO_ERROR;
+
+ result = "";
+ fp = 0;
+ result = msg.format(
+ ft_arr,
+ result,
+ //FieldPosition(0),
+ fp,
+ err);
+
+ logln("MSG format( Formattable&, ... ) expected:" + compareStr);
+ logln("MSG format( Formattable&, ... ) result:" + result);
+ if (result != compareStr) {
+ errln("*** MSG format( Formattable&, .... ) err.");
+ }else{
+ logln("MSG format( Formattable&, ... ) tested.");
+ }
+
+ delete fmt;
+
+}
+
+void TestMessageFormat::testParse()
+{
+ UErrorCode err = U_ZERO_ERROR;
+ int32_t count;
+ UnicodeString msgFormatString = "{0} =sep= {1}";
+ MessageFormat msg( msgFormatString, err);
+ UnicodeString source = "abc =sep= def";
+ UnicodeString tmp1, tmp2;
+
+ Formattable* fmt_arr = msg.parse( source, count, err );
+ if (U_FAILURE(err) || (!fmt_arr)) {
+ errln("*** MSG parse (ustring, count, err) error.");
+ }else{
+ logln("MSG parse -- count: %d", count);
+ if (count != 2) {
+ errln("*** MSG parse (ustring, count, err) count err.");
+ }else{
+ if ((fmt_arr[0].getType() == Formattable::kString)
+ && (fmt_arr[1].getType() == Formattable::kString)
+ && (fmt_arr[0].getString(tmp1) == "abc")
+ && (fmt_arr[1].getString(tmp2) == "def")) {
+ logln("MSG parse (ustring, count, err) tested.");
+ }else{
+ errln("*** MSG parse (ustring, count, err) result err.");
+ }
+ }
+ }
+ delete[] fmt_arr;
+
+ ParsePosition pp(0);
+
+ fmt_arr = msg.parse( source, pp, count );
+ if ((pp == 0) || (!fmt_arr)) {
+ errln("*** MSG parse (ustring, parsepos., count) error.");
+ }else{
+ logln("MSG parse -- count: %d", count);
+ if (count != 2) {
+ errln("*** MSG parse (ustring, parsepos., count) count err.");
+ }else{
+ if ((fmt_arr[0].getType() == Formattable::kString)
+ && (fmt_arr[1].getType() == Formattable::kString)
+ && (fmt_arr[0].getString(tmp1) == "abc")
+ && (fmt_arr[1].getString(tmp2) == "def")) {
+ logln("MSG parse (ustring, parsepos., count) tested.");
+ }else{
+ errln("*** MSG parse (ustring, parsepos., count) result err.");
+ }
+ }
+ }
+ delete[] fmt_arr;
+
+ pp = 0;
+ Formattable fmta;
+
+ msg.parseObject( source, fmta, pp );
+ if (pp == 0) {
+ errln("*** MSG parse (ustring, Formattable, parsepos ) error.");
+ }else{
+ logln("MSG parse -- count: %d", count);
+ fmta.getArray(count);
+ if (count != 2) {
+ errln("*** MSG parse (ustring, Formattable, parsepos ) count err.");
+ }else{
+ if ((fmta[0].getType() == Formattable::kString)
+ && (fmta[1].getType() == Formattable::kString)
+ && (fmta[0].getString(tmp1) == "abc")
+ && (fmta[1].getString(tmp2) == "def")) {
+ logln("MSG parse (ustring, Formattable, parsepos ) tested.");
+ }else{
+ errln("*** MSG parse (ustring, Formattable, parsepos ) result err.");
+ }
+ }
+ }
+}
+
+
+void TestMessageFormat::testAdopt()
+{
+ UErrorCode err = U_ZERO_ERROR;
+
+ UnicodeString formatStr("{0,date},{1},{2,number}", "");
+ UnicodeString formatStrChange("{0,number},{1,number},{2,date}", "");
+ err = U_ZERO_ERROR;
+ MessageFormat msg( formatStr, err);
+ MessageFormat msgCmp( formatStr, err);
+ int32_t count, countCmp;
+ const Format** formats = msg.getFormats(count);
+ const Format** formatsCmp = msgCmp.getFormats(countCmp);
+ const Format** formatsChg = 0;
+ const Format** formatsAct = 0;
+ int32_t countAct;
+ const Format* a;
+ const Format* b;
+ UnicodeString patCmp;
+ UnicodeString patAct;
+ Format** formatsToAdopt;
+
+ if (!formats || !formatsCmp || (count <= 0) || (count != countCmp)) {
+ errln("Error getting Formats");
+ return;
+ }
+
+ int32_t i;
+
+ for (i = 0; i < count; i++) {
+ a = formats[i];
+ b = formatsCmp[i];
+ if ((a != NULL) && (b != NULL)) {
+ if (*a != *b) {
+ errln("a != b");
+ return;
+ }
+ }else if ((a != NULL) || (b != NULL)) {
+ errln("(a != NULL) || (b != NULL)");
+ return;
+ }
+ }
+
+ msg.applyPattern( formatStrChange, err ); //set msg formats to something different
+ int32_t countChg;
+ formatsChg = msg.getFormats(countChg); // tested function
+ if (!formatsChg || (countChg != count)) {
+ errln("Error getting Formats");
+ return;
+ }
+
+ UBool diff;
+ diff = TRUE;
+ for (i = 0; i < count; i++) {
+ a = formatsChg[i];
+ b = formatsCmp[i];
+ if ((a != NULL) && (b != NULL)) {
+ if (*a == *b) {
+ logln("formatsChg == formatsCmp at index %d", i);
+ diff = FALSE;
+ }
+ }
+ }
+ if (!diff) {
+ errln("*** MSG getFormats diff err.");
+ return;
+ }
+
+ logln("MSG getFormats tested.");
+
+ msg.setFormats( formatsCmp, countCmp ); //tested function
+
+ formatsAct = msg.getFormats(countAct);
+ if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
+ errln("Error getting Formats");
+ return;
+ }
+
+ assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
+ assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
+
+ for (i = 0; i < countAct; i++) {
+ a = formatsAct[i];
+ b = formatsCmp[i];
+ if ((a != NULL) && (b != NULL)) {
+ if (*a != *b) {
+ logln("formatsAct != formatsCmp at index %d", i);
+ errln("a != b");
+ return;
+ }
+ }else if ((a != NULL) || (b != NULL)) {
+ errln("(a != NULL) || (b != NULL)");
+ return;
+ }
+ }
+ logln("MSG setFormats tested.");
+
+ //----
+
+ msg.applyPattern( formatStrChange, err ); //set msg formats to something different
+
+ formatsToAdopt = new Format* [countCmp];
+ if (!formatsToAdopt) {
+ errln("memory allocation error");
+ return;
+ }
+
+ for (i = 0; i < countCmp; i++) {
+ if (formatsCmp[i] == NULL) {
+ formatsToAdopt[i] = NULL;
+ }else{
+ formatsToAdopt[i] = formatsCmp[i]->clone();
+ if (!formatsToAdopt[i]) {
+ errln("Can't clone format at index %d", i);
+ return;
+ }
+ }
+ }
+ msg.adoptFormats( formatsToAdopt, countCmp ); // function to test
+ delete[] formatsToAdopt;
+
+ assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
+ assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
+
+ formatsAct = msg.getFormats(countAct);
+ if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
+ errln("Error getting Formats");
+ return;
+ }
+
+ for (i = 0; i < countAct; i++) {
+ a = formatsAct[i];
+ b = formatsCmp[i];
+ if ((a != NULL) && (b != NULL)) {
+ if (*a != *b) {
+ errln("a != b");
+ return;
+ }
+ }else if ((a != NULL) || (b != NULL)) {
+ errln("(a != NULL) || (b != NULL)");
+ return;
+ }
+ }
+ logln("MSG adoptFormats tested.");
+
+ //---- adoptFormat
+
+ msg.applyPattern( formatStrChange, err ); //set msg formats to something different
+
+ formatsToAdopt = new Format* [countCmp];
+ if (!formatsToAdopt) {
+ errln("memory allocation error");
+ return;
+ }
+
+ for (i = 0; i < countCmp; i++) {
+ if (formatsCmp[i] == NULL) {
+ formatsToAdopt[i] = NULL;
+ }else{
+ formatsToAdopt[i] = formatsCmp[i]->clone();
+ if (!formatsToAdopt[i]) {
+ errln("Can't clone format at index %d", i);
+ return;
+ }
+ }
+ }
+
+ for ( i = 0; i < countCmp; i++ ) {
+ msg.adoptFormat( i, formatsToAdopt[i] ); // function to test
+ }
+ delete[] formatsToAdopt; // array itself not needed in this case;
+
+ assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern(patCmp.remove()));
+ assertEquals("msg.toPattern()", formatStr, msg.toPattern(patAct.remove()));
+
+ formatsAct = msg.getFormats(countAct);
+ if (!formatsAct || (countAct <=0) || (countAct != countCmp)) {
+ errln("Error getting Formats");
+ return;
+ }
+
+ for (i = 0; i < countAct; i++) {
+ a = formatsAct[i];
+ b = formatsCmp[i];
+ if ((a != NULL) && (b != NULL)) {
+ if (*a != *b) {
+ errln("a != b");
+ return;
+ }
+ }else if ((a != NULL) || (b != NULL)) {
+ errln("(a != NULL) || (b != NULL)");
+ return;
+ }
+ }
+ logln("MSG adoptFormat tested.");
+}
+
+// This test is a regression test for a fixed bug in the copy constructor.
+// It is kept as a global function rather than as a method since the test depends on memory values.
+// (At least before the bug was fixed, whether it showed up or not depended on memory contents,
+// which is probably why it didn't show up in the regular test for the copy constructor.)
+// For this reason, the test isn't changed even though it contains function calls whose results are
+// not tested and had no problems. Actually, the test failed by *crashing*.
+static void _testCopyConstructor2()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString formatStr("Hello World on {0,date,full}", "");
+ UnicodeString resultStr(" ", "");
+ UnicodeString result;
+ FieldPosition fp(0);
+ UDate d = Calendar::getNow();
+ const Formattable fargs( d, Formattable::kIsDate );
+
+ MessageFormat* fmt1 = new MessageFormat( formatStr, status );
+ MessageFormat* fmt2 = new MessageFormat( *fmt1 );
+ MessageFormat* fmt3;
+ MessageFormat* fmt4;
+
+ if (fmt1 == NULL) it_err("testCopyConstructor2: (fmt1 != NULL)");
+
+ result = fmt1->format( &fargs, 1, resultStr, fp, status );
+
+ if (fmt2 == NULL) it_err("testCopyConstructor2: (fmt2 != NULL)");
+
+ fmt3 = (MessageFormat*) fmt1->clone();
+ fmt4 = (MessageFormat*) fmt2->clone();
+
+ if (fmt3 == NULL) it_err("testCopyConstructor2: (fmt3 != NULL)");
+ if (fmt4 == NULL) it_err("testCopyConstructor2: (fmt4 != NULL)");
+
+ result = fmt1->format( &fargs, 1, resultStr, fp, status );
+ result = fmt2->format( &fargs, 1, resultStr, fp, status );
+ result = fmt3->format( &fargs, 1, resultStr, fp, status );
+ result = fmt4->format( &fargs, 1, resultStr, fp, status );
+ delete fmt1;
+ delete fmt2;
+ delete fmt3;
+ delete fmt4;
+}
+
+void TestMessageFormat::testCopyConstructor2() {
+ _testCopyConstructor2();
+}
+
+/**
+ * Verify that MessageFormat accomodates more than 10 arguments and
+ * more than 10 subformats.
+ */
+void TestMessageFormat::TestUnlimitedArgsAndSubformats() {
+ UErrorCode ec = U_ZERO_ERROR;
+ const UnicodeString pattern =
+ "On {0,date} (aka {0,date,short}, aka {0,date,long}) "
+ "at {0,time} (aka {0,time,short}, aka {0,time,long}) "
+ "there were {1,number} werjes "
+ "(a {3,number,percent} increase over {2,number}) "
+ "despite the {4}''s efforts "
+ "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}.";
+ MessageFormat msg(pattern, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: constructor failed");
+ return;
+ }
+
+ const Formattable ARGS[] = {
+ Formattable(UDate(1e13), Formattable::kIsDate),
+ Formattable((int32_t)1303),
+ Formattable((int32_t)1202),
+ Formattable(1303.0/1202 - 1),
+ Formattable("Glimmung"),
+ Formattable("the printers"),
+ Formattable("Nick"),
+ Formattable("his father"),
+ Formattable("his mother"),
+ Formattable("the spiddles"),
+ Formattable("of course"),
+ Formattable("Horace"),
+ };
+ const int32_t ARGS_LENGTH = sizeof(ARGS) / sizeof(ARGS[0]);
+ Formattable ARGS_OBJ(ARGS, ARGS_LENGTH);
+
+ UnicodeString expected =
+ "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "
+ "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "
+ "there were 1,303 werjes "
+ "(a 8% increase over 1,202) "
+ "despite the Glimmung's efforts "
+ "and to delight of the printers, Nick, his father, "
+ "his mother, the spiddles, and of course Horace.";
+ UnicodeString result;
+ msg.format(ARGS_OBJ, result, ec);
+ if (result == expected) {
+ logln(result);
+ } else {
+ errln((UnicodeString)"FAIL: Got " + result +
+ ", expected " + expected);
+ }
+}
+
+// test RBNF extensions to message format
+void TestMessageFormat::TestRBNF(void) {
+ // WARNING: this depends on the RBNF formats for en_US
+ Locale locale("en", "US", "");
+
+ UErrorCode ec = U_ZERO_ERROR;
+
+ UnicodeString values[] = {
+ // decimal values do not format completely for ordinal or duration, and
+ // do not always parse, so do not include them
+ "0", "1", "12", "100", "123", "1001", "123,456", "-17",
+ };
+ int32_t values_count = sizeof(values)/sizeof(values[0]);
+
+ UnicodeString formats[] = {
+ "There are {0,spellout} files to search.",
+ "There are {0,spellout,%simplified} files to search.",
+ "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.",
+ "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse
+ "Searching this file will take {0,duration} to complete.",
+ "Searching this file will take {0,duration,%with-words} to complete.",
+ };
+ int32_t formats_count = sizeof(formats)/sizeof(formats[0]);
+
+ Formattable args[1];
+
+ NumberFormat* numFmt = NumberFormat::createInstance(locale, ec);
+ if (U_FAILURE(ec)) {
+ dataerrln("Error calling NumberFormat::createInstance()");
+ return;
+ }
+
+ for (int i = 0; i < formats_count; ++i) {
+ MessageFormat* fmt = new MessageFormat(formats[i], locale, ec);
+ logln((UnicodeString)"Testing format pattern: '" + formats[i] + "'");
+
+ for (int j = 0; j < values_count; ++j) {
+ ec = U_ZERO_ERROR;
+ numFmt->parse(values[j], args[0], ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"Failed to parse test argument " + values[j]);
+ } else {
+ FieldPosition fp(0);
+ UnicodeString result;
+ fmt->format(args, 1, result, fp, ec);
+ logln((UnicodeString)"value: " + toString(args[0]) + " --> " + result + UnicodeString(" ec: ") + u_errorName(ec));
+
+ if (i != 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3)
+ int32_t count = 0;
+ Formattable* parseResult = fmt->parse(result, count, ec);
+ if (count != 1) {
+ errln((UnicodeString)"parse returned " + count + " args");
+ } else if (parseResult[0] != args[0]) {
+ errln((UnicodeString)"parsed argument " + toString(parseResult[0]) + " != " + toString(args[0]));
+ }
+ delete []parseResult;
+ }
+ }
+ }
+ delete fmt;
+ }
+ delete numFmt;
+}
+
+void TestMessageFormat::testAutoQuoteApostrophe(void) {
+ const char* patterns[] = { // pattern, expected pattern
+ "'", "''",
+ "''", "''",
+ "'{", "'{'",
+ "' {", "'' {",
+ "'a", "''a",
+ "'{'a", "'{'a",
+ "'{a'", "'{a'",
+ "'{}", "'{}'",
+ "{'", "{'",
+ "{'a", "{'a",
+ "{'a{}'a}'a", "{'a{}'a}''a",
+ "'}'", "'}'",
+ "'} '{'}'", "'} '{'}''",
+ "'} {{{''", "'} {{{'''",
+ };
+ int32_t pattern_count = sizeof(patterns)/sizeof(patterns[0]);
+
+ for (int i = 0; i < pattern_count; i += 2) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString result = MessageFormat::autoQuoteApostrophe(patterns[i], status);
+ UnicodeString target(patterns[i+1]);
+ if (target != result) {
+ const int BUF2_LEN = 64;
+ char buf[256];
+ char buf2[BUF2_LEN];
+ int32_t len = result.extract(0, result.length(), buf2, BUF2_LEN);
+ if (len >= BUF2_LEN) {
+ buf2[BUF2_LEN-1] = 0;
+ }
+ sprintf(buf, "[%2d] test \"%s\": target (\"%s\") != result (\"%s\")\n", i/2, patterns[i], patterns[i+1], buf2);
+ errln(buf);
+ }
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tmsgfmt.h b/Build/source/libs/icu/icu-xetex/test/intltest/tmsgfmt.h
new file mode 100644
index 00000000000..5534dadfe14
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tmsgfmt.h
@@ -0,0 +1,96 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+
+#ifndef _TESTMESSAGEFORMAT
+#define _TESTMESSAGEFORMAT
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/fmtable.h"
+#include "intltest.h"
+
+/**
+ * TestMessageFormat tests MessageFormat, and also a few unctions in ChoiceFormat
+ */
+class TestMessageFormat: public IntlTest {
+public:
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ /**
+ * regression test for a specific bug regarding ChoiceFormat boundaries
+ **/
+ void testBug1(void);
+ /**
+ * regression test for a specific bug regarding MessageFormat using ChoiceFormat
+ **/
+ void testBug2(void);
+ /**
+ * regression test for a specific bug involving NumberFormat and Locales
+ **/
+ void testBug3(void);
+ /**
+ * test MessageFormat with various given patterns
+ **/
+ void PatternTest(void);
+ /**
+ * test MesageFormat formatting functionality in a simple example
+ **/
+ void sample(void);
+
+ /**
+ * tests the static MessageFormat::format method
+ **/
+ void testStaticFormat(/* char* par */);
+ /**
+ * tests MesageFormat functionality with a simple format
+ **/
+ void testSimpleFormat(/* char* par */);
+ /**
+ * tests MesageFormat functionality with a format including a ChoiceFormat
+ **/
+ void testMsgFormatChoice(/* char* par */);
+
+ /**
+ * Verify that MessageFormat accomodates more than 10 arguments
+ * and more than 10 subformats.
+ */
+ void TestUnlimitedArgsAndSubformats();
+
+ /**
+ * Test RBNF extensions to MessageFormat.
+ */
+ void TestRBNF();
+
+ //
+ /**
+ * ------------ API tests ----------
+ * These routines test various API functionality.
+ * In addition to the methods their name suggests,
+ * they often test other methods as well.
+ **/
+ void testCopyConstructor(void);
+ void testCopyConstructor2(void);
+ void testAssignment(void);
+ void testClone(void);
+ void testEquals(void);
+ void testNotEquals(void);
+ void testSetLocale(void);
+ void testFormat(void);
+ void testParse(void);
+ void testAdopt(void);
+ void TestTurkishCasing(void);
+ void testAutoQuoteApostrophe(void);
+
+private:
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tokiter.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tokiter.cpp
new file mode 100644
index 00000000000..202cbd93e3d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tokiter.cpp
@@ -0,0 +1,107 @@
+/*
+**********************************************************************
+* Copyright (c) 2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: March 22 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#include "tokiter.h"
+#include "textfile.h"
+#include "util.h"
+#include "uprops.h"
+
+TokenIterator::TokenIterator(TextFile* r) {
+ reader = r;
+ done = haveLine = FALSE;
+ pos = lastpos = -1;
+}
+
+TokenIterator::~TokenIterator() {
+}
+
+UBool TokenIterator::next(UnicodeString& token, UErrorCode& ec) {
+ if (done || U_FAILURE(ec)) {
+ return FALSE;
+ }
+ token.truncate(0);
+ for (;;) {
+ if (!haveLine) {
+ if (!reader->readLineSkippingComments(line, ec)) {
+ done = TRUE;
+ return FALSE;
+ }
+ haveLine = TRUE;
+ pos = 0;
+ }
+ lastpos = pos;
+ if (!nextToken(token, ec)) {
+ haveLine = FALSE;
+ if (U_FAILURE(ec)) return FALSE;
+ continue;
+ }
+ return TRUE;
+ }
+}
+
+int32_t TokenIterator::getLineNumber() const {
+ return reader->getLineNumber();
+}
+
+/**
+ * Read the next token from 'this->line' and append it to 'token'.
+ * Tokens are separated by rule white space. Tokens may also be
+ * delimited by double or single quotes. The closing quote must match
+ * the opening quote. If a '#' is encountered, the rest of the line
+ * is ignored, unless it is backslash-escaped or within quotes.
+ * @param token the token is appended to this StringBuffer
+ * @param ec input-output error code
+ * @return TRUE if a valid token is found, or FALSE if the end
+ * of the line is reached or an error occurs
+ */
+UBool TokenIterator::nextToken(UnicodeString& token, UErrorCode& ec) {
+ ICU_Utility::skipWhitespace(line, pos, TRUE);
+ if (pos == line.length()) {
+ return FALSE;
+ }
+ UChar c = line.charAt(pos++);
+ UChar quote = 0;
+ switch (c) {
+ case 34/*'"'*/:
+ case 39/*'\\'*/:
+ quote = c;
+ break;
+ case 35/*'#'*/:
+ return FALSE;
+ default:
+ token.append(c);
+ break;
+ }
+ while (pos < line.length()) {
+ c = line.charAt(pos); // 16-bit ok
+ if (c == 92/*'\\'*/) {
+ UChar32 c32 = line.unescapeAt(pos);
+ if (c32 < 0) {
+ ec = U_MALFORMED_UNICODE_ESCAPE;
+ return FALSE;
+ }
+ token.append(c32);
+ } else if ((quote != 0 && c == quote) ||
+ (quote == 0 && uprv_isRuleWhiteSpace(c))) {
+ ++pos;
+ return TRUE;
+ } else if (quote == 0 && c == '#') {
+ return TRUE; // do NOT increment
+ } else {
+ token.append(c);
+ ++pos;
+ }
+ }
+ if (quote != 0) {
+ ec = U_UNTERMINATED_QUOTE;
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tokiter.h b/Build/source/libs/icu/icu-xetex/test/intltest/tokiter.h
new file mode 100644
index 00000000000..5db5753ae4d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tokiter.h
@@ -0,0 +1,71 @@
+/*
+**********************************************************************
+* Copyright (c) 2004-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Author: Alan Liu
+* Created: March 22 2004
+* Since: ICU 3.0
+**********************************************************************
+*/
+#ifndef __ICU_INTLTEST_TOKITER__
+#define __ICU_INTLTEST_TOKITER__
+
+#include "intltest.h"
+
+class TextFile;
+
+/**
+ * An iterator class that returns successive string tokens from some
+ * source. String tokens are, in general, separated by rule white
+ * space in the source test. Furthermore, they may be delimited by
+ * either single or double quotes (opening and closing quotes must
+ * match). Escapes are processed using standard ICU unescaping.
+ */
+class TokenIterator {
+ public:
+
+ /**
+ * Construct an iterator over the tokens returned by the given
+ * TextFile, ignoring blank lines and comment lines (first
+ * non-blank character is '#'). Note that trailing comments on a
+ * line, beginning with the first unquoted '#', are recognized.
+ */
+ TokenIterator(TextFile* r);
+
+ virtual ~TokenIterator();
+
+ /**
+ * Return the next token from this iterator.
+ * @return TRUE if a token was read, or FALSE if no more tokens
+ * are available or an error occurred.
+ */
+ UBool next(UnicodeString& token, UErrorCode& ec);
+
+ /**
+ * Return the one-based line number of the line of the last token
+ * returned by next(). Should only be called after a call to
+ * next(); otherwise the return value is undefined.
+ */
+ int32_t getLineNumber() const;
+
+ /**
+ * Return a string description of the position of the last line
+ * returned by readLine() or readLineSkippingComments().
+ */
+ //public String describePosition() {
+ // return reader.describePosition() + ':' + (lastpos+1);
+ //}
+
+ private:
+ UBool nextToken(UnicodeString& token, UErrorCode& ec);
+
+ TextFile* reader; // alias
+ UnicodeString line;
+ UBool done;
+ UBool haveLine;
+ int32_t pos;
+ int32_t lastpos;
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/transapi.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/transapi.cpp
new file mode 100644
index 00000000000..faf995c16fc
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/transapi.cpp
@@ -0,0 +1,984 @@
+/************************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2000-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ************************************************************************/
+/************************************************************************
+* Date Name Description
+* 1/03/2000 Madhu Creation.
+************************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "ittrans.h"
+#include "transapi.h"
+#include "unicode/utypes.h"
+#include "unicode/translit.h"
+#include "unicode/unifilt.h"
+#include "cpdtrans.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "unicode/rep.h"
+#include "unicode/locid.h"
+#include "unicode/uniset.h"
+
+int32_t getInt(UnicodeString str)
+{
+ char buffer[20];
+ int len=str.length();
+ if(len>=20) {
+ len=19;
+ }
+ str.extract(0, len, buffer, "");
+ buffer[len]=0;
+ return atoi(buffer);
+}
+
+//---------------------------------------------
+// runIndexedTest
+//---------------------------------------------
+
+void
+TransliteratorAPITest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ TESTCASE(0,TestgetInverse);
+ TESTCASE(1,TestgetID);
+ TESTCASE(2,TestGetDisplayName);
+ TESTCASE(3,TestTransliterate1);
+ TESTCASE(4,TestTransliterate2);
+ TESTCASE(5,TestTransliterate3);
+ TESTCASE(6,TestSimpleKeyboardTransliterator);
+ TESTCASE(7,TestKeyboardTransliterator1);
+ TESTCASE(8,TestKeyboardTransliterator2);
+ TESTCASE(9,TestKeyboardTransliterator3);
+ TESTCASE(10,TestGetAdoptFilter);
+ TESTCASE(11,TestClone);
+ TESTCASE(12,TestNullTransliterator);
+ TESTCASE(13,TestRegisterUnregister);
+ TESTCASE(14,TestUnicodeFunctor);
+ default: name = ""; break;
+ }
+}
+
+
+void TransliteratorAPITest::TestgetID() {
+ UnicodeString trans="Latin-Greek";
+ UnicodeString ID;
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* t= Transliterator::createInstance(trans, UTRANS_FORWARD, parseError, status);
+ if(t==0 || U_FAILURE(status)){
+ errln("FAIL: construction of Latin-Greek");
+ return;
+ }else{
+ ID= t->getID();
+ if(ID != trans)
+ errln("FAIL: getID returned " + ID + " instead of Latin-Greek");
+ delete t;
+ }
+ int i;
+ for (i=0; i<Transliterator::countAvailableIDs(); i++){
+ status = U_ZERO_ERROR;
+ ID = (UnicodeString) Transliterator::getAvailableID(i);
+ if(ID.indexOf("Thai")>-1){
+ continue;
+ }
+ t = Transliterator::createInstance(ID, UTRANS_FORWARD, parseError, status);
+ if(t == 0){
+ errln("FAIL: " + ID);
+ continue;
+ }
+ if(ID != t->getID())
+ errln("FAIL: getID() returned " + t->getID() + " instead of " + ID);
+ delete t;
+ }
+ ID=(UnicodeString)Transliterator::getAvailableID(i);
+ if(ID != (UnicodeString)Transliterator::getAvailableID(0)){
+ errln("FAIL: calling getAvailableID(index > coundAvailableIDs) should make index=0\n");
+ }
+
+ Transliterator* t1=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
+ Transliterator* t2=Transliterator::createInstance("Latin-Greek", UTRANS_FORWARD, parseError, status);
+ if(t1 ==0 || t2 == 0){
+ errln("FAIL: construction");
+ return;
+ }
+ Transliterator* t3=t1->clone();
+ Transliterator* t4=t2->clone();
+
+ if(t1->getID() != t3->getID() || t2->getID() != t4->getID() ||
+ t1->getID() == t4->getID() || t2->getID() == t3->getID() ||
+ t1->getID()== t4->getID() )
+ errln("FAIL: getID or clone failed");
+
+
+ Transliterator* t5=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
+ if(t5 == 0)
+ errln("FAIL: construction");
+ else if(t1->getID() != t5->getID() || t5->getID() != t3->getID() || t1->getID() != t3->getID())
+ errln("FAIL: getID or clone failed");
+
+
+ delete t1;
+ delete t2;
+ delete t3;
+ delete t4;
+ delete t5;
+}
+
+void TransliteratorAPITest::TestgetInverse() {
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator* t1 = Transliterator::createInstance("Katakana-Latin", UTRANS_FORWARD, parseError, status);
+ Transliterator* invt1 = Transliterator::createInstance("Latin-Katakana", UTRANS_FORWARD, parseError, status);
+ Transliterator* t2 = Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
+ Transliterator* invt2 = Transliterator::createInstance("Devanagari-Latin", UTRANS_FORWARD, parseError, status);
+ if(t1 == 0 || invt1 == 0 || t2 == 0 || invt2 == 0) {
+ errln("FAIL: in instantiation");
+ return;
+ }
+
+ Transliterator* inverse1=t1->createInverse(status);
+ Transliterator* inverse2=t2->createInverse(status);
+ if(inverse1->getID() != invt1->getID() || inverse2->getID() != invt2->getID()
+ || inverse1->getID() == invt2->getID() || inverse2->getID() == invt1->getID() )
+ errln("FAIL: getInverse() ");
+
+ UnicodeString TransID[]={
+ "Halfwidth-Fullwidth",
+ "Fullwidth-Halfwidth",
+ "Greek-Latin" ,
+ "Latin-Greek",
+ //"Arabic-Latin", // removed in 2.0
+ //"Latin-Arabic",
+ "Katakana-Latin",
+ "Latin-Katakana",
+ //"Hebrew-Latin", // removed in 2.0
+ //"Latin-Hebrew",
+ "Cyrillic-Latin",
+ "Latin-Cyrillic",
+ "Devanagari-Latin",
+ "Latin-Devanagari",
+ "Any-Hex",
+ "Hex-Any"
+ };
+ for(uint32_t i=0; i<sizeof(TransID)/sizeof(TransID[0]); i=i+2){
+ Transliterator *trans1=Transliterator::createInstance(TransID[i], UTRANS_FORWARD, parseError, status);
+ if(t1 == 0){
+ errln("FAIL: in instantiation for" + TransID[i]);
+ continue;
+ }
+ Transliterator *inver1=trans1->createInverse(status);
+ if(inver1->getID() != TransID[i+1] )
+ errln("FAIL :getInverse() for " + TransID[i] + " returned " + inver1->getID() + " instead of " + TransID[i+1]);
+ delete inver1;
+ delete trans1;
+ }
+ delete t1;
+ delete t2;
+ delete invt1;
+ delete invt2;
+ delete inverse1;
+ delete inverse2;
+
+}
+
+void TransliteratorAPITest::TestClone(){
+ Transliterator *t1, *t2, *t3, *t4;
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ t1=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
+ t2=Transliterator::createInstance("Latin-Greek", UTRANS_FORWARD, parseError, status);
+ if(t1 == 0 || t2 == 0){
+ errln("FAIL: construction");
+ return;
+ }
+ t3=t1->clone();
+ t4=t2->clone();
+
+ if(t1->getID() != t3->getID() || t2->getID() != t4->getID() )
+ errln("FAIL: clone or getID failed");
+ if(t1->getID()==t4->getID() || t2->getID()==t3->getID() || t1->getID()==t4->getID())
+ errln("FAIL: clone or getID failed");
+
+ delete t1;
+ delete t2;
+ delete t3;
+ delete t4;
+
+}
+
+void TransliteratorAPITest::TestGetDisplayName() {
+ UnicodeString dispNames[]= {
+ //ID, displayName
+ //"CurlyQuotes-StraightQuotes" ,"CurlyQuotes to StraightQuotes",
+ "Any-Hex" ,"Any to Hex Escape",
+ "Halfwidth-Fullwidth" ,"Halfwidth to Fullwidth" ,
+ //"Latin-Arabic" ,"Latin to Arabic" ,
+ "Latin-Devanagari" ,"Latin to Devanagari" ,
+ "Greek-Latin" ,"Greek to Latin" ,
+ //"Arabic-Latin" ,"Arabic to Latin" ,
+ "Hex-Any" ,"Hex Escape to Any",
+ "Cyrillic-Latin" ,"Cyrillic to Latin" ,
+ "Latin-Greek" ,"Latin to Greek" ,
+ "Latin-Katakana" ,"Latin to Katakana" ,
+ //"Latin-Hebrew" ,"Latin to Hebrew" ,
+ "Katakana-Latin" ,"Katakana to Latin"
+ };
+ UnicodeString name="";
+ Transliterator* t;
+ UnicodeString message;
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+
+#if UCONFIG_NO_FORMATTING
+ logln("Skipping, UCONFIG_NO_FORMATTING is set\n");
+ return;
+#else
+
+ for (uint32_t i=0; i<sizeof(dispNames)/sizeof(dispNames[0]); i=i+2 ) {
+ t = Transliterator::createInstance(dispNames[i+0], UTRANS_FORWARD, parseError, status);
+ if(t==0){
+ errln("FAIL: construction: " + dispNames[i+0]);
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ t->getDisplayName(t->getID(), name);
+ message="Display name for ID:" + t->getID();
+ // doTest(message, name, dispNames[i+1]); //!!! This will obviously fail for any locale other than english and its children!!!
+ name="";
+ t->getDisplayName(t->getID(), Locale::getUS(), name);
+ message.remove();
+ message.append("Display name for on english locale ID:");
+ message.append(t->getID());
+ // message="Display name for on english locale ID:" + t->getID();
+ doTest(message, name, dispNames[i+1]);
+ name="";
+
+ delete t;
+ }
+#endif
+
+}
+
+void TransliteratorAPITest::TestTransliterate1(){
+
+ UnicodeString Data[]={
+ //ID, input string, transliterated string
+ "Any-Hex", "hello", UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F", "") ,
+ "Hex-Any", UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F", ""), "hello" ,
+ "Latin-Devanagari",CharsToUnicodeString("bha\\u0304rata"), CharsToUnicodeString("\\u092D\\u093E\\u0930\\u0924") ,
+ "Latin-Devanagari",UnicodeString("kra ksha khra gra cra dya dhya",""), CharsToUnicodeString("\\u0915\\u094D\\u0930 \\u0915\\u094D\\u0936 \\u0916\\u094D\\u0930 \\u0917\\u094D\\u0930 \\u091a\\u094D\\u0930 \\u0926\\u094D\\u092F \\u0927\\u094D\\u092F") ,
+
+ "Devanagari-Latin", CharsToUnicodeString("\\u092D\\u093E\\u0930\\u0924"), UnicodeString("bh\\u0101rata"),
+ // "Contracted-Expanded", CharsToUnicodeString("\\u00C0\\u00C1\\u0042"), CharsToUnicodeString("\\u0041\\u0300\\u0041\\u0301\\u0042") ,
+ // "Expanded-Contracted", CharsToUnicodeString("\\u0041\\u0300\\u0041\\u0301\\u0042"), CharsToUnicodeString("\\u00C0\\u00C1\\u0042") ,
+ //"Latin-Arabic", "aap", CharsToUnicodeString("\\u0627\\u06A4") ,
+ //"Arabic-Latin", CharsToUnicodeString("\\u0627\\u06A4"), "aap"
+ };
+
+ UnicodeString gotResult;
+ UnicodeString temp;
+ UnicodeString message;
+ Transliterator* t;
+ logln("Testing transliterate");
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+
+ for(uint32_t i=0;i<sizeof(Data)/sizeof(Data[0]); i=i+3){
+ t=Transliterator::createInstance(Data[i+0], UTRANS_FORWARD, parseError, status);
+ if(t==0){
+ errln("FAIL: construction: " + Data[i+0] + " Error: " + u_errorName(status));
+ errln("PreContext: " + prettify(parseError.preContext) + " PostContext: " + prettify( parseError.postContext) );
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ gotResult = Data[i+1];
+ t->transliterate(gotResult);
+ message=t->getID() + "->transliterate(UnicodeString, UnicodeString) for\n\t Source:" + prettify(Data[i+1]);
+ doTest(message, gotResult, Data[i+2]);
+
+ //doubt here
+ temp=Data[i+1];
+ t->transliterate(temp);
+ message.remove();
+ message.append(t->getID());
+ message.append("->transliterate(Replaceable) for \n\tSource:");
+ message.append(Data[i][1]);
+ doTest(message, temp, Data[i+2]);
+
+ callEverything(t, __LINE__);
+ delete t;
+ }
+}
+
+void TransliteratorAPITest::TestTransliterate2(){
+ //testing tranliterate(String text, int start, int limit, StringBuffer result)
+ UnicodeString Data2[]={
+ //ID, input string, start, limit, transliterated string
+ "Any-Hex", "hello! How are you?", "0", "5", UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F", ""), UnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F! How are you?", "") ,
+ "Any-Hex", "hello! How are you?", "7", "12", UnicodeString("\\u0048\\u006F\\u0077\\u0020\\u0061", ""), UnicodeString("hello! \\u0048\\u006F\\u0077\\u0020\\u0061re you?", ""),
+ "Hex-Any", CharsToUnicodeString("\\u0068\\u0065\\u006C\\u006C\\u006F\\u0021\\u0020"), "0", "5", "hello", "hello! " ,
+ // "Contracted-Expanded", CharsToUnicodeString("\\u00C0\\u00C1\\u0042"), "1", "2", CharsToUnicodeString("\\u0041\\u0301"), CharsToUnicodeString("\\u00C0\\u0041\\u0301\\u0042") ,
+ "Devanagari-Latin", CharsToUnicodeString("\\u092D\\u093E\\u0930\\u0924"), "0", "1", "bha", CharsToUnicodeString("bha\\u093E\\u0930\\u0924") ,
+ "Devanagari-Latin", CharsToUnicodeString("\\u092D\\u093E\\u0930\\u0924"), "1", "2", "\\u0314\\u0101", CharsToUnicodeString("\\u092D\\u0314\\u0101\\u0930\\u0924")
+
+ };
+ logln("\n Testing transliterate(String, int, int, StringBuffer)");
+ Transliterator* t;
+ UnicodeString gotResBuf;
+ UnicodeString temp;
+ int32_t start, limit;
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+
+ for(uint32_t i=0; i<sizeof(Data2)/sizeof(Data2[0]); i=i+6){
+ t=Transliterator::createInstance(Data2[i+0], UTRANS_FORWARD, parseError, status);
+ if(t==0){
+ errln("FAIL: construction: " + prettify(Data2[i+0]));
+ continue;
+ }
+ start=getInt(Data2[i+2]);
+ limit=getInt(Data2[i+3]);
+ Data2[i+1].extractBetween(start, limit, gotResBuf);
+ t->transliterate(gotResBuf);
+ // errln("FAIL: calling transliterate on " + t->getID());
+ doTest(t->getID() + ".transliterate(UnicodeString, int32_t, int32_t, UnicodeString):(" + start + "," + limit + ") for \n\t source: " + prettify(Data2[i+1]), gotResBuf, Data2[i+4]);
+
+ temp=Data2[i+1];
+ t->transliterate(temp, start, limit);
+ doTest(t->getID() + ".transliterate(Replaceable, int32_t, int32_t, ):(" + start + "," + limit + ") for \n\t source: " + prettify(Data2[i+1]), temp, Data2[i+5]);
+ status = U_ZERO_ERROR;
+ callEverything(t, __LINE__);
+ delete t;
+ t = NULL;
+ }
+
+ status = U_ZERO_ERROR;
+ logln("\n Try calling transliterate with illegal start and limit values");
+ t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
+ if(U_FAILURE(status)) {
+ errln("Error creating transliterator %s", u_errorName(status));
+ delete t;
+ return;
+ }
+ gotResBuf = temp = "try start greater than limit";
+ t->transliterate(gotResBuf, 10, 5);
+ if(gotResBuf == temp) {
+ logln("OK: start greater than limit value handled correctly");
+ } else {
+ errln("FAIL: start greater than limit value returned" + gotResBuf);
+ }
+
+ callEverything(t, __LINE__);
+ delete t;
+
+}
+void TransliteratorAPITest::TestTransliterate3(){
+ UnicodeString rs="This is the replaceable String";
+ UnicodeString Data[] = {
+ "0", "0", "This is the replaceable String",
+ "2", "3", UnicodeString("Th\\u0069s is the replaceable String", ""),
+ "21", "23", UnicodeString("Th\\u0069s is the repl\\u0061\\u0063eable String", ""),
+ "14", "17", UnicodeString("Th\\u0069s is t\\u0068\\u0065\\u0020repl\\u0061\\u0063eable String", ""),
+ };
+ int start, limit;
+ UnicodeString message;
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
+ if(U_FAILURE(status)) {
+ errln("Error creating transliterator %s", u_errorName(status));
+ delete t;
+ return;
+ }
+
+ if(t == 0)
+ errln("FAIL : construction");
+ for(uint32_t i=0; i<sizeof(Data)/sizeof(Data[0]); i=i+3){
+ start=getInt(Data[i+0]);
+ limit=getInt(Data[i+1]);
+ t->transliterate(rs, start, limit);
+ message=t->getID() + ".transliterate(ReplaceableString, start, limit):("+start+","+limit+"):";
+ doTest(message, rs, Data[i+2]);
+ }
+ delete t;
+}
+
+void TransliteratorAPITest::TestSimpleKeyboardTransliterator(){
+ logln("simple call to transliterate");
+ UErrorCode status=U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator* t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
+ if(t == 0) {
+ UnicodeString context;
+
+ if (parseError.preContext[0]) {
+ context += (UnicodeString)" at " + parseError.preContext;
+ }
+ if (parseError.postContext[0]) {
+ context += (UnicodeString)" | " + parseError.postContext;
+ }
+ errln((UnicodeString)"FAIL: can't create Any-Hex, " +
+ (UnicodeString)u_errorName(status) + context);
+ return;
+ }
+ UTransPosition index={19,20,20,20};
+ UnicodeString rs= "Transliterate this-''";
+ UnicodeString insertion="abc";
+ UnicodeString expected=UnicodeString("Transliterate this-'\\u0061\\u0062\\u0063'", "");
+ t->transliterate(rs, index, insertion, status);
+ if(U_FAILURE(status))
+ errln("FAIL: " + t->getID()+ ".translitere(Replaceable, int[], UnicodeString, UErrorCode)-->" + (UnicodeString)u_errorName(status));
+ t->finishTransliteration(rs, index);
+ UnicodeString message="transliterate";
+ doTest(message, rs, expected);
+
+ logln("try calling transliterate with invalid index values");
+ UTransPosition index1[]={
+ //START, LIMIT, CURSOR
+ {10, 10, 12, 10}, //invalid since CURSOR>LIMIT valid:-START <= CURSOR <= LIMIT
+ {17, 16, 17, 17}, //invalid since START>LIMIT valid:-0<=START<=LIMIT
+ {-1, 16, 14, 16}, //invalid since START<0
+ {3, 50, 2, 50} //invalid since LIMIT>text.length()
+ };
+ for(uint32_t i=0; i<sizeof(index1)/sizeof(index1[0]); i++){
+ status=U_ZERO_ERROR;
+ t->transliterate(rs, index1[i], insertion, status);
+ if(status == U_ILLEGAL_ARGUMENT_ERROR)
+ logln("OK: invalid index values handled correctly");
+ else
+ errln("FAIL: invalid index values didn't throw U_ILLEGAL_ARGUMENT_ERROR throw" + (UnicodeString)u_errorName(status));
+ }
+
+ delete t;
+}
+void TransliteratorAPITest::TestKeyboardTransliterator1(){
+ UnicodeString Data[]={
+ //insertion, buffer
+ "a", UnicodeString("\\u0061", "") ,
+ "bbb", UnicodeString("\\u0061\\u0062\\u0062\\u0062", "") ,
+ "ca", UnicodeString("\\u0061\\u0062\\u0062\\u0062\\u0063\\u0061", "") ,
+ " ", UnicodeString("\\u0061\\u0062\\u0062\\u0062\\u0063\\u0061\\u0020", "") ,
+ "", UnicodeString("\\u0061\\u0062\\u0062\\u0062\\u0063\\u0061\\u0020", "") ,
+
+ "a", UnicodeString("\\u0061", "") ,
+ "b", UnicodeString("\\u0061\\u0062", "") ,
+ "z", UnicodeString("\\u0061\\u0062\\u007A", "") ,
+ "", UnicodeString("\\u0061\\u0062\\u007A", "")
+
+ };
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
+ if(U_FAILURE(status)) {
+ errln("Error creating transliterator %s", u_errorName(status));
+ delete t;
+ return;
+ }
+ //keyboardAux(t, Data);
+ UTransPosition index={0, 0, 0, 0};
+ UnicodeString s;
+ uint32_t i;
+ logln("Testing transliterate(Replaceable, int32_t, UnicodeString, UErrorCode)");
+ for (i=0; i<10; i=i+2) {
+ UnicodeString log;
+ if (Data[i+0] != "") {
+ log = s + " + " + Data[i+0] + " -> ";
+ t->transliterate(s, index, Data[i+0], status);
+ if(U_FAILURE(status)){
+ errln("FAIL: " + t->getID()+ ".transliterate(Replaceable, int32_t[], UnicodeString, UErrorCode)-->" + (UnicodeString)u_errorName(status));
+ continue;
+ }
+ }else {
+ log = s + " => ";
+ t->finishTransliteration(s, index);
+ }
+ // Show the start index '{' and the cursor '|'
+ displayOutput(s, Data[i+1], log, index);
+
+ }
+
+ s="";
+ status=U_ZERO_ERROR;
+ index.contextStart = index.contextLimit = index.start = index.limit = 0;
+ logln("Testing transliterate(Replaceable, int32_t, UChar, UErrorCode)");
+ for(i=10; i<sizeof(Data)/sizeof(Data[0]); i=i+2){
+ UnicodeString log;
+ if (Data[i+0] != "") {
+ log = s + " + " + Data[i+0] + " -> ";
+ UChar c=Data[i+0].charAt(0);
+ t->transliterate(s, index, c, status);
+ if(U_FAILURE(status))
+ errln("FAIL: " + t->getID()+ ".transliterate(Replaceable, int32_t[], UChar, UErrorCode)-->" + (UnicodeString)u_errorName(status));
+ continue;
+ }else {
+ log = s + " => ";
+ t->finishTransliteration(s, index);
+ }
+ // Show the start index '{' and the cursor '|'
+ displayOutput(s, Data[i+1], log, index);
+ }
+
+ delete t;
+}
+
+void TransliteratorAPITest::TestKeyboardTransliterator2(){
+ UnicodeString Data[]={
+ //insertion, buffer, index[START], index[LIMIT], index[CURSOR]
+ //data for Any-Hex
+ "abc", UnicodeString("Initial String: add-\\u0061\\u0062\\u0063-", ""), "19", "20", "20",
+ "a", UnicodeString("In\\u0069\\u0061tial String: add-\\u0061\\u0062\\u0063-", ""), "2", "3", "2" ,
+ "b", UnicodeString("\\u0062In\\u0069\\u0061tial String: add-\\u0061\\u0062\\u0063-", ""), "0", "0", "0" ,
+ "", UnicodeString("\\u0062In\\u0069\\u0061tial String: add-\\u0061\\u0062\\u0063-", ""), "0", "0", "0" ,
+ //data for Latin-Devanagiri
+ CharsToUnicodeString("a\\u0304"), CharsToUnicodeString("Hindi -\\u0906-"), "6", "7", "6",
+ CharsToUnicodeString("ma\\u0304"), CharsToUnicodeString("Hindi -\\u0906\\u092E\\u093E-"), "7", "8", "7",
+ CharsToUnicodeString("ra\\u0304"), CharsToUnicodeString("Hi\\u0930\\u093Endi -\\u0906\\u092E\\u093E-"),"1", "2", "2",
+ CharsToUnicodeString(""), CharsToUnicodeString("Hi\\u0930\\u093Endi -\\u0906\\u092E\\u093E-"),"1", "2", "2"
+ //data for contracted-Expanded
+ // CharsToUnicodeString("\\u00C1"), CharsToUnicodeString("Ad\\u0041\\u0301d here:"), "1", "2", "1" ,
+ // CharsToUnicodeString("\\u00C0"), CharsToUnicodeString("Ad\\u0041\\u0301d here:\\u0041\\u0300"), "11", "11", "11",
+ // "", CharsToUnicodeString("Ad\\u0041\\u0301d here:\\u0041\\u0300"), "11", "11", "11",
+ };
+ Transliterator *t;
+ UnicodeString rs;
+ UnicodeString dataStr;
+ logln("Testing transliterate(Replaceable, int32_t, UnicodeString, UErrorCode)");
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ rs="Initial String: add--";
+ t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
+ if(t == 0)
+ errln("FAIL : construction");
+ else {
+ keyboardAux(t, Data, rs, 0, 20);
+ delete t;
+ }
+
+ rs="Hindi --";
+ t=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
+ if(t == 0)
+ errln("FAIL : construction");
+ else
+ keyboardAux(t, Data, rs, 20, 40);
+
+
+ // rs="Add here:";
+ // t=Transliterator::createInstance("Contracted-Expanded");
+ // keyboardAux(t, Data, rs, 35, 55);
+
+
+ delete t;
+}
+
+void TransliteratorAPITest::TestKeyboardTransliterator3(){
+ UnicodeString s="This is the main string";
+ UnicodeString Data[] = {
+ "0", "0", "0", "This is the main string",
+ "1", "3", "2", UnicodeString("Th\\u0069s is the main string", ""),
+ "20", "21", "20", UnicodeString("Th\\u0069s is the mai\\u006E string", "")
+ };
+
+ UErrorCode status=U_ZERO_ERROR;
+ UParseError parseError;
+ UTransPosition index={0, 0, 0, 0};
+ logln("Testing transliterate(Replaceable, int32_t, UErrorCode)");
+ Transliterator *t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
+ if(t == 0 || U_FAILURE(status)) {
+ errln("Error creating transliterator %s", u_errorName(status));
+ delete t;
+ return;
+ }
+ for(uint32_t i=0; i<sizeof(Data)/sizeof(Data[0]); i=i+4){
+ UnicodeString log;
+ index.contextStart=getInt(Data[i+0]);
+ index.contextLimit=index.limit=getInt(Data[i+1]);
+ index.start=getInt(Data[i+2]);
+ t->transliterate(s, index, status);
+ if(U_FAILURE(status)){
+ errln("FAIL: " + t->getID()+ ".transliterate(Replaceable, int32_t[], UErrorCode)-->" + (UnicodeString)u_errorName(status));
+ continue;
+ }
+ t->finishTransliteration(s, index);
+ log = s + " => ";
+ // Show the start index '{' and the cursor '|'
+ displayOutput(s, Data[i+3], log, index);
+ }
+
+ delete t;
+}
+void TransliteratorAPITest::TestNullTransliterator(){
+ UErrorCode status=U_ZERO_ERROR;
+ UnicodeString s("Transliterate using null transliterator");
+ Transliterator *nullTrans=Transliterator::createInstance("Any-Null", UTRANS_FORWARD, status);
+ int32_t transLimit;
+ int32_t start=0;
+ int32_t limit=s.length();
+ UnicodeString replaceable=s;
+ transLimit=nullTrans->transliterate(replaceable, start, limit);
+ if(transLimit != limit){
+ errln("ERROR: NullTransliterator->transliterate() failed");
+ }
+ doTest((UnicodeString)"nulTrans->transliterate", replaceable, s);
+ replaceable.remove();
+ replaceable.append(s);
+ UTransPosition index;
+ index.contextStart =start;
+ index.contextLimit = limit;
+ index.start = 0;
+ index.limit = limit;
+ nullTrans->finishTransliteration(replaceable, index);
+ if(index.start != limit){
+ errln("ERROR: NullTransliterator->handleTransliterate() failed");
+ }
+ doTest((UnicodeString)"NullTransliterator->handleTransliterate", replaceable, s);
+ callEverything(nullTrans, __LINE__);
+ delete nullTrans;
+
+
+}
+void TransliteratorAPITest::TestRegisterUnregister(){
+
+ UErrorCode status=U_ZERO_ERROR;
+ /* Make sure it doesn't exist */
+ if (Transliterator::createInstance("TestA-TestB", UTRANS_FORWARD, status) != NULL) {
+ errln("FAIL: TestA-TestB already registered\n");
+ return;
+ }
+ /* Check inverse too
+ if (Transliterator::createInstance("TestA-TestB",
+ (UTransDirection)UTRANS_REVERSE) != NULL) {
+ errln("FAIL: TestA-TestB inverse already registered\n");
+ return;
+ }
+ */
+ status =U_ZERO_ERROR;
+
+ /* Create it */
+ UParseError parseError;
+ Transliterator *t = Transliterator::createFromRules("TestA-TestB",
+ "a<>b",
+ UTRANS_FORWARD, parseError,
+ status);
+ /* Register it */
+ Transliterator::registerInstance(t);
+
+ /* Now check again -- should exist now*/
+ Transliterator *s = Transliterator::createInstance("TestA-TestB", UTRANS_FORWARD, status);
+ if (s == NULL) {
+ errln("FAIL: TestA-TestB not registered\n");
+ return;
+ }
+ callEverything(s, __LINE__);
+ callEverything(t, __LINE__);
+ delete s;
+
+ /* Check inverse too
+ s = Transliterator::createInstance("TestA-TestB",
+ (UTransDirection)UTRANS_REVERSE);
+ if (s == NULL) {
+ errln("FAIL: TestA-TestB inverse not registered\n");
+ return;
+ }
+ delete s;
+ */
+
+ /*unregister the instance*/
+ Transliterator::unregister("TestA-TestB");
+ /* now Make sure it doesn't exist */
+ if (Transliterator::createInstance("TestA-TestB", UTRANS_FORWARD, status) != NULL) {
+ errln("FAIL: TestA-TestB isn't unregistered\n");
+ return;
+ }
+
+}
+
+
+int gTestFilter1ClassID = 0;
+int gTestFilter2ClassID = 0;
+int gTestFilter3ClassID = 0;
+
+/**
+ * Used by TestFiltering().
+ */
+class TestFilter1 : public UnicodeFilter {
+ UClassID getDynamicClassID()const { return &gTestFilter1ClassID; }
+ virtual UnicodeFunctor* clone() const {
+ return new TestFilter1(*this);
+ }
+ virtual UBool contains(UChar32 c) const {
+ if(c==0x63 || c==0x61 || c==0x43 || c==0x41)
+ return FALSE;
+ else
+ return TRUE;
+ }
+ // Stubs
+ virtual UnicodeString& toPattern(UnicodeString& result,
+ UBool /*escapeUnprintable*/) const {
+ return result;
+ }
+ virtual UBool matchesIndexValue(uint8_t /*v*/) const {
+ return FALSE;
+ }
+ virtual void addMatchSetTo(UnicodeSet& /*toUnionTo*/) const {}
+};
+class TestFilter2 : public UnicodeFilter {
+ UClassID getDynamicClassID()const { return &gTestFilter2ClassID; }
+ virtual UnicodeFunctor* clone() const {
+ return new TestFilter2(*this);
+ }
+ virtual UBool contains(UChar32 c) const {
+ if(c==0x65 || c==0x6c)
+ return FALSE;
+ else
+ return TRUE;
+ }
+ // Stubs
+ virtual UnicodeString& toPattern(UnicodeString& result,
+ UBool /*escapeUnprintable*/) const {
+ return result;
+ }
+ virtual UBool matchesIndexValue(uint8_t /*v*/) const {
+ return FALSE;
+ }
+ virtual void addMatchSetTo(UnicodeSet& /*toUnionTo*/) const {}
+};
+class TestFilter3 : public UnicodeFilter {
+ UClassID getDynamicClassID()const { return &gTestFilter3ClassID; }
+ virtual UnicodeFunctor* clone() const {
+ return new TestFilter3(*this);
+ }
+ virtual UBool contains(UChar32 c) const {
+ if(c==0x6f || c==0x77)
+ return FALSE;
+ else
+ return TRUE;
+ }
+ // Stubs
+ virtual UnicodeString& toPattern(UnicodeString& result,
+ UBool /*escapeUnprintable*/) const {
+ return result;
+ }
+ virtual UBool matchesIndexValue(uint8_t /*v*/) const {
+ return FALSE;
+ }
+ virtual void addMatchSetTo(UnicodeSet& /*toUnionTo*/) const {}
+};
+
+
+void TransliteratorAPITest::TestGetAdoptFilter(){
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator *t=Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
+ if(t == 0 || U_FAILURE(status)) {
+ errln("Error creating transliterator %s", u_errorName(status));
+ delete t;
+ return;
+ }
+ const UnicodeFilter *u=t->getFilter();
+ if(u != NULL){
+ errln("FAIL: getFilter failed. Didn't return null when the transliterator used no filtering");
+ delete t;
+ return;
+ }
+
+ UnicodeString got, temp, message;
+ UnicodeString data="ABCabcbbCBa";
+ temp = data;
+ t->transliterate(temp);
+ t->adoptFilter(new TestFilter1);
+
+ got = data;
+ t->transliterate(got);
+ UnicodeString exp=UnicodeString("A\\u0042Ca\\u0062c\\u0062\\u0062C\\u0042a", "");
+ message="transliteration after adoptFilter(a,A,c,C) ";
+ doTest(message, got, exp);
+
+ logln("Testing round trip");
+ t->adoptFilter((UnicodeFilter*)u);
+ if(t->getFilter() == NULL)
+ logln("OK: adoptFilter and getFilter round trip worked");
+ else
+ errln("FAIL: adoptFilter or getFilter round trip failed");
+
+ got = data;
+ t->transliterate(got);
+ exp=UnicodeString("\\u0041\\u0042\\u0043\\u0061\\u0062\\u0063\\u0062\\u0062\\u0043\\u0042\\u0061", "");
+ message="transliteration after adopting null filter";
+ doTest(message, got, exp);
+ message="adoptFilter round trip";
+ doTest("adoptFilter round trip", got, temp);
+
+ t->adoptFilter(new TestFilter2);
+ callEverything(t, __LINE__);
+ data="heelloe";
+ exp=UnicodeString("\\u0068eell\\u006Fe", "");
+ got = data;
+ t->transliterate(got);
+ message="transliteration using (e,l) filter";
+ doTest("transliteration using (e,l) filter", got, exp);
+
+ data="are well";
+ exp=UnicodeString("\\u0061\\u0072e\\u0020\\u0077ell", "");
+ got = data;
+ t->transliterate(got);
+ doTest(message, got, exp);
+
+ t->adoptFilter(new TestFilter3);
+ data="ho, wow!";
+ exp=UnicodeString("\\u0068o\\u002C\\u0020wow\\u0021", "");
+ got = data;
+ t->transliterate(got);
+ message="transliteration using (o,w) filter";
+ doTest("transliteration using (o,w) filter", got, exp);
+
+ data="owl";
+ exp=UnicodeString("ow\\u006C", "");
+ got = data;
+ t->transliterate(got);
+ doTest("transliteration using (o,w) filter", got, exp);
+
+ delete t;
+
+}
+
+
+
+void TransliteratorAPITest::keyboardAux(Transliterator *t, UnicodeString DATA[], UnicodeString& s, int32_t begin, int32_t end) {
+ UTransPosition index={0, 0, 0, 0};
+ UErrorCode status=U_ZERO_ERROR;
+ for (int32_t i=begin; i<end; i=i+5) {
+ UnicodeString log;
+ if (DATA[i+0] != "") {
+ log = s + " + " + DATA[i] + " -> ";
+ index.contextStart=getInt(DATA[i+2]);
+ index.contextLimit=index.limit=getInt(DATA[i+3]);
+ index.start=getInt(DATA[i+4]);
+ t->transliterate(s, index, DATA[i+0], status);
+ if(U_FAILURE(status)){
+ errln("FAIL: " + t->getID()+ ".transliterate(Replaceable, int32_t[], UnicodeString, UErrorCode)-->" + (UnicodeString)u_errorName(status));
+ continue;
+ }
+ log = s + " => ";
+ t->finishTransliteration(s, index);
+ }
+ // Show the start index '{' and the cursor '|'
+ displayOutput(s, DATA[i+1], log, index);
+
+ }
+}
+
+void TransliteratorAPITest::displayOutput(const UnicodeString& got, const UnicodeString& expected, UnicodeString& log, UTransPosition& index){
+ // Show the start index '{' and the cursor '|'
+ UnicodeString a, b, c, d, e;
+ got.extractBetween(0, index.contextStart, a);
+ got.extractBetween(index.contextStart, index.start, b);
+ got.extractBetween(index.start, index.limit, c);
+ got.extractBetween(index.limit, index.contextLimit, d);
+ got.extractBetween(index.contextLimit, got.length(), e);
+ log.append(a).
+ append((UChar)0x7b/*{*/).
+ append(b).
+ append((UChar)0x7c/*|*/).
+ append(c).
+ append((UChar)0x7c).
+ append(d).
+ append((UChar)0x7d/*}*/).
+ append(e);
+ if (got == expected)
+ logln("OK:" + prettify(log));
+ else
+ errln("FAIL: " + prettify(log) + ", expected " + prettify(expected));
+}
+
+
+/*Internal Functions used*/
+void TransliteratorAPITest::doTest(const UnicodeString& message, const UnicodeString& result, const UnicodeString& expected){
+ if (prettify(result) == prettify(expected))
+ logln((UnicodeString)"Ok: " + prettify(message) + " passed \"" + prettify(expected) + "\"");
+ else
+ errln((UnicodeString)"FAIL:" + message + " failed Got-->" + prettify(result)+ ", Expected--> " + prettify(expected) );
+}
+
+
+//
+// callEverything call all of the const (non-destructive) methods on a
+// transliterator, just to verify that they don't fail in some
+// destructive way.
+//
+#define CEASSERT(a) {if (!(a)) { \
+errln("FAIL at line %d from line %d: %s", __LINE__, line, #a); return; }}
+
+void TransliteratorAPITest::callEverything(const Transliterator *tr, int line) {
+ Transliterator *clonedTR = tr->clone();
+ CEASSERT(clonedTR != NULL);
+
+ int32_t maxcl = tr->getMaximumContextLength();
+ CEASSERT(clonedTR->getMaximumContextLength() == maxcl);
+
+ UnicodeString id;
+ UnicodeString clonedId;
+ id = tr->getID();
+ clonedId = clonedTR->getID();
+ CEASSERT(id == clonedId);
+
+ const UnicodeFilter *filter = tr->getFilter();
+ const UnicodeFilter *clonedFilter = clonedTR->getFilter();
+ if (filter == NULL || clonedFilter == NULL) {
+ // If one filter is NULL they better both be NULL.
+ CEASSERT(filter == clonedFilter);
+ } else {
+ CEASSERT(filter != clonedFilter);
+ }
+
+ UnicodeString rules;
+ UnicodeString clonedRules;
+ rules = tr->toRules(rules, FALSE);
+ clonedRules = clonedTR->toRules(clonedRules, FALSE);
+ CEASSERT(rules == clonedRules);
+
+ UnicodeSet sourceSet;
+ UnicodeSet clonedSourceSet;
+ tr->getSourceSet(sourceSet);
+ clonedTR->getSourceSet(clonedSourceSet);
+ CEASSERT(clonedSourceSet == sourceSet);
+
+ UnicodeSet targetSet;
+ UnicodeSet clonedTargetSet;
+ tr->getTargetSet(targetSet);
+ clonedTR->getTargetSet(clonedTargetSet);
+ CEASSERT(targetSet == clonedTargetSet);
+
+ UClassID classID = tr->getDynamicClassID();
+ CEASSERT(classID == clonedTR->getDynamicClassID());
+ CEASSERT(classID != 0);
+
+ delete clonedTR;
+}
+
+static const int MyUnicodeFunctorTestClassID = 0;
+class MyUnicodeFunctorTestClass : public UnicodeFunctor {
+public:
+ virtual UnicodeFunctor* clone() const {return NULL;}
+ static UClassID getStaticClassID(void) {return (UClassID)&MyUnicodeFunctorTestClassID;}
+ virtual UClassID getDynamicClassID(void) const {return getStaticClassID();};
+ virtual void setData(const TransliterationRuleData*) {}
+};
+
+void TransliteratorAPITest::TestUnicodeFunctor() {
+ MyUnicodeFunctorTestClass myClass;
+ if (myClass.toMatcher() != NULL) {
+ errln("FAIL: UnicodeFunctor::toMatcher did not return NULL");
+ }
+ if (myClass.toReplacer() != NULL) {
+ errln("FAIL: UnicodeFunctor::toReplacer did not return NULL");
+ }
+}
+
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/transapi.h b/Build/source/libs/icu/icu-xetex/test/intltest/transapi.h
new file mode 100644
index 00000000000..5dca65efc80
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/transapi.h
@@ -0,0 +1,78 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2001-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/************************************************************************
+* Date Name Description
+* 1/03/2000 Madhu Creation.
+************************************************************************/
+
+#ifndef TRANSAPI_H
+#define TRANSAPI_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "intltest.h"
+
+/**
+ * @test
+ * @summary General test of Transliterator
+ */
+class TransliteratorAPITest : public IntlTest {
+public:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par=NULL);
+
+ /*Tests the function getDisplayName() */
+ void TestGetDisplayName(void);
+
+ void TestgetID(void);
+
+ void TestgetInverse(void);
+
+ void TestClone(void);
+
+ void TestTransliterate1(void);
+
+ void TestTransliterate2(void);
+
+ void TestTransliterate3(void);
+
+ void TestSimpleKeyboardTransliterator(void);
+
+ void TestKeyboardTransliterator1(void);
+
+ void TestKeyboardTransliterator2(void);
+
+ void TestKeyboardTransliterator3(void);
+
+ void TestGetAdoptFilter(void);
+
+ void TestNullTransliterator(void);
+
+ void TestRegisterUnregister(void);
+
+ void TestLatinDevanagari(void);
+
+ void TestDevanagariLatinRT(void);
+
+ void TestUnicodeFunctor(void);
+
+ /*Internal functions used*/
+ void doTest(const UnicodeString& , const UnicodeString& , const UnicodeString& );
+
+ void keyboardAux(Transliterator*, UnicodeString[] , UnicodeString&, int32_t, int32_t);
+
+ void displayOutput(const UnicodeString&, const UnicodeString&, UnicodeString&,
+ UTransPosition&);
+
+ void callEverything(const Transliterator *t, int line);
+
+};
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/transrt.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/transrt.cpp
new file mode 100644
index 00000000000..66afa048c90
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/transrt.cpp
@@ -0,0 +1,1708 @@
+/*
+**********************************************************************
+* Copyright (C) 2000-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/23/00 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "rbt.h"
+#include "unicode/calendar.h"
+#include "unicode/uniset.h"
+#include "unicode/uchar.h"
+#include "unicode/normlzr.h"
+#include "unicode/uchar.h"
+#include "unicode/parseerr.h"
+#include "unicode/usetiter.h"
+#include "unicode/putil.h"
+#include "unicode/uversion.h"
+#include "unicode/locid.h"
+#include "unicode/ulocdata.h"
+#include "unicode/utf8.h"
+#include "putilimp.h"
+#include "cmemory.h"
+#include "transrt.h"
+#include "testutil.h"
+#include <string.h>
+#include <stdio.h>
+
+#define CASE(id,test) case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ UDate t = uprv_getUTCtime(); \
+ test(); \
+ t = uprv_getUTCtime() - t; \
+ logln((UnicodeString)#test " took " + t/U_MILLIS_PER_DAY + " seconds"); \
+ } \
+ break
+
+#define EXHAUSTIVE(id,test) case id: \
+ if(quick==FALSE){ \
+ name = #test; \
+ if (exec){ \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ test(); \
+ } \
+ }else{ \
+ name=""; \
+ } \
+ break
+void
+TransliteratorRoundTripTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ CASE(0, TestCyrillic);
+ // CASE(0,TestKana);
+ CASE(1,TestHiragana);
+ CASE(2,TestKatakana);
+ CASE(3,TestJamo);
+ CASE(4,TestHangul);
+ CASE(5,TestGreek);
+ CASE(6,TestGreekUNGEGN);
+ CASE(7,Testel);
+ CASE(8,TestDevanagariLatin);
+ CASE(9,TestInterIndic);
+ CASE(10, TestHebrew);
+ CASE(11, TestArabic);
+ CASE(12, TestHan);
+ default: name = ""; break;
+ }
+}
+
+//--------------------------------------------------------------------
+// Time bomb - allows temporary behavior that expires at a given
+// release
+//--------------------------------------------------------------------
+static const UVersionInfo ICU_39 = {3,9,0,0};
+
+
+//--------------------------------------------------------------------
+// TransliteratorPointer
+//--------------------------------------------------------------------
+
+/**
+ * A transliterator pointer wrapper that deletes the contained
+ * pointer automatically when the wrapper goes out of scope.
+ * Sometimes called a "janitor" or "smart pointer".
+ */
+class TransliteratorPointer {
+ Transliterator* t;
+ // disallowed:
+ TransliteratorPointer(const TransliteratorPointer& rhs);
+ TransliteratorPointer& operator=(const TransliteratorPointer& rhs);
+public:
+ TransliteratorPointer(Transliterator* adopted) {
+ t = adopted;
+ }
+ ~TransliteratorPointer() {
+ delete t;
+ }
+ inline Transliterator* operator->() { return t; }
+ inline operator const Transliterator*() const { return t; }
+ inline operator Transliterator*() { return t; }
+};
+
+//--------------------------------------------------------------------
+// Legal
+//--------------------------------------------------------------------
+
+class Legal {
+public:
+ Legal() {}
+ virtual ~Legal() {}
+ virtual UBool is(const UnicodeString& /*sourceString*/) const {return TRUE;}
+};
+
+class LegalJamo : public Legal {
+ // any initial must be followed by a medial (or initial)
+ // any medial must follow an initial (or medial)
+ // any final must follow a medial (or final)
+public:
+ LegalJamo() {}
+ virtual ~LegalJamo() {}
+ virtual UBool is(const UnicodeString& sourceString) const;
+ int getType(UChar c) const;
+};
+
+UBool LegalJamo::is(const UnicodeString& sourceString) const {
+ int t;
+ UnicodeString decomp;
+ UErrorCode ec = U_ZERO_ERROR;
+ Normalizer::decompose(sourceString, FALSE, 0, decomp, ec);
+ if (U_FAILURE(ec)) {
+ return FALSE;
+ }
+ for (int i = 0; i < decomp.length(); ++i) { // don't worry about surrogates
+ switch (getType(decomp.charAt(i))) {
+ case 0: t = getType(decomp.charAt(i+1));
+ if (t != 0 && t != 1) { return FALSE; }
+ break;
+ case 1: t = getType(decomp.charAt(i-1));
+ if (t != 0 && t != 1) { return FALSE; }
+ break;
+ case 2: t = getType(decomp.charAt(i-1));
+ if (t != 1 && t != 2) { return FALSE; }
+ break;
+ }
+ }
+ return TRUE;
+}
+
+int LegalJamo::getType(UChar c) const {
+ if (0x1100 <= c && c <= 0x1112)
+ return 0;
+ else if (0x1161 <= c && c <= 0x1175)
+ return 1;
+ else if (0x11A8 <= c && c <= 0x11C2)
+ return 2;
+ return -1; // other
+}
+
+class LegalGreek : public Legal {
+ UBool full;
+public:
+ LegalGreek(UBool _full) { full = _full; }
+ virtual ~LegalGreek() {}
+
+ virtual UBool is(const UnicodeString& sourceString) const;
+
+ static UBool isVowel(UChar c);
+
+ static UBool isRho(UChar c);
+};
+
+UBool LegalGreek::is(const UnicodeString& sourceString) const {
+ UnicodeString decomp;
+ UErrorCode ec = U_ZERO_ERROR;
+ Normalizer::decompose(sourceString, FALSE, 0, decomp, ec);
+
+ // modern is simpler: don't care about anything but a grave
+ if (full == FALSE) {
+ // A special case which is legal but should be
+ // excluded from round trip
+ // if (sourceString == UnicodeString("\\u039C\\u03C0", "")) {
+ // return FALSE;
+ // }
+ for (int32_t i = 0; i < decomp.length(); ++i) {
+ UChar c = decomp.charAt(i);
+ // exclude all the accents
+ if (c == 0x0313 || c == 0x0314 || c == 0x0300 || c == 0x0302
+ || c == 0x0342 || c == 0x0345
+ ) return FALSE;
+ }
+ return TRUE;
+ }
+
+ // Legal greek has breathing marks IFF there is a vowel or RHO at the start
+ // IF it has them, it has exactly one.
+ // IF it starts with a RHO, then the breathing mark must come before the second letter.
+ // Since there are no surrogates in greek, don't worry about them
+ UBool firstIsVowel = FALSE;
+ UBool firstIsRho = FALSE;
+ UBool noLetterYet = TRUE;
+ int32_t breathingCount = 0;
+ int32_t letterCount = 0;
+ for (int32_t i = 0; i < decomp.length(); ++i) {
+ UChar c = decomp.charAt(i);
+ if (u_isalpha(c)) {
+ ++letterCount;
+ if (noLetterYet) {
+ noLetterYet = FALSE;
+ firstIsVowel = isVowel(c);
+ firstIsRho = isRho(c);
+ }
+ if (firstIsRho && letterCount == 2 && breathingCount == 0) {
+ return FALSE;
+ }
+ }
+ if (c == 0x0313 || c == 0x0314) {
+ ++breathingCount;
+ }
+ }
+
+ if (firstIsVowel || firstIsRho) return breathingCount == 1;
+ return breathingCount == 0;
+}
+
+UBool LegalGreek::isVowel(UChar c) {
+ switch (c) {
+ case 0x03B1:
+ case 0x03B5:
+ case 0x03B7:
+ case 0x03B9:
+ case 0x03BF:
+ case 0x03C5:
+ case 0x03C9:
+ case 0x0391:
+ case 0x0395:
+ case 0x0397:
+ case 0x0399:
+ case 0x039F:
+ case 0x03A5:
+ case 0x03A9:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool LegalGreek::isRho(UChar c) {
+ switch (c) {
+ case 0x03C1:
+ case 0x03A1:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// AbbreviatedUnicodeSetIterator Interface ---------------------------------------------
+//
+// Iterate over a UnicodeSet, only returning a sampling of the contained code points.
+// density is the approximate total number of code points to returned for the entire set.
+//
+
+class AbbreviatedUnicodeSetIterator : public UnicodeSetIterator {
+public :
+
+ AbbreviatedUnicodeSetIterator();
+ virtual ~AbbreviatedUnicodeSetIterator();
+ void reset(UnicodeSet& set, UBool abb = FALSE, int32_t density = 100);
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ */
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ */
+ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+
+private :
+ UBool abbreviated;
+ int32_t perRange; // The maximum number of code points to be returned from each range
+ virtual void loadRange(int32_t range);
+
+ /**
+ * The address of this static class variable serves as this class's ID
+ * for ICU "poor man's RTTI".
+ */
+ static const char fgClassID;
+};
+
+// AbbreviatedUnicodeSetIterator Implementation ---------------------------------------
+
+const char AbbreviatedUnicodeSetIterator::fgClassID=0;
+
+AbbreviatedUnicodeSetIterator::AbbreviatedUnicodeSetIterator() :
+ UnicodeSetIterator(), abbreviated(FALSE) {
+}
+
+AbbreviatedUnicodeSetIterator::~AbbreviatedUnicodeSetIterator() {
+}
+
+void AbbreviatedUnicodeSetIterator::reset(UnicodeSet& newSet, UBool abb, int32_t density) {
+ UnicodeSetIterator::reset(newSet);
+ abbreviated = abb;
+ perRange = newSet.getRangeCount();
+ if (perRange != 0) {
+ perRange = density / perRange;
+ }
+}
+
+void AbbreviatedUnicodeSetIterator::loadRange(int32_t myRange) {
+ UnicodeSetIterator::loadRange(myRange);
+ if (abbreviated && (endElement > nextElement + perRange)) {
+ endElement = nextElement + perRange;
+ }
+}
+
+//--------------------------------------------------------------------
+// RTTest Interface
+//--------------------------------------------------------------------
+
+class RTTest : public IntlTest {
+
+ // PrintWriter out;
+
+ UnicodeString transliteratorID;
+ int32_t errorLimit;
+ int32_t errorCount;
+ int32_t pairLimit;
+ UnicodeSet sourceRange;
+ UnicodeSet targetRange;
+ UnicodeSet toSource;
+ UnicodeSet toTarget;
+ UnicodeSet roundtripExclusionsSet;
+ IntlTest* parent;
+ Legal* legalSource; // NOT owned
+ UnicodeSet badCharacters;
+
+public:
+
+ /*
+ * create a test for the given script transliterator.
+ */
+ RTTest(const UnicodeString& transliteratorIDStr);
+
+ virtual ~RTTest();
+
+ void setErrorLimit(int32_t limit);
+
+ void setPairLimit(int32_t limit);
+
+ void test(const UnicodeString& sourceRange,
+ const UnicodeString& targetRange,
+ const char* roundtripExclusions,
+ IntlTest* parent,
+ UBool quick,
+ Legal* adoptedLegal,
+ int32_t density = 100);
+
+private:
+
+ // Added to do better equality check.
+
+ static UBool isSame(const UnicodeString& a, const UnicodeString& b);
+
+ static UBool isCamel(const UnicodeString& a);
+
+ UBool checkIrrelevants(Transliterator *t, const UnicodeString& irrelevants);
+
+ void test2(UBool quick, int32_t density);
+
+ void logWrongScript(const UnicodeString& label,
+ const UnicodeString& from,
+ const UnicodeString& to);
+
+ void logNotCanonical(const UnicodeString& label,
+ const UnicodeString& from,
+ const UnicodeString& to,
+ const UnicodeString& fromCan,
+ const UnicodeString& toCan);
+
+ void logFails(const UnicodeString& label);
+
+ void logToRulesFails(const UnicodeString& label,
+ const UnicodeString& from,
+ const UnicodeString& to,
+ const UnicodeString& toCan);
+
+ void logRoundTripFailure(const UnicodeString& from,
+ const UnicodeString& toID,
+ const UnicodeString& to,
+ const UnicodeString& backID,
+ const UnicodeString& back);
+};
+
+//--------------------------------------------------------------------
+// RTTest Implementation
+//--------------------------------------------------------------------
+
+/*
+ * create a test for the given script transliterator.
+ */
+RTTest::RTTest(const UnicodeString& transliteratorIDStr) {
+ transliteratorID = transliteratorIDStr;
+ errorLimit = 500;
+ errorCount = 0;
+ pairLimit = 0x10000;
+}
+
+RTTest::~RTTest() {
+}
+
+void RTTest::setErrorLimit(int32_t limit) {
+ errorLimit = limit;
+}
+
+void RTTest::setPairLimit(int32_t limit) {
+ pairLimit = limit;
+}
+
+UBool RTTest::isSame(const UnicodeString& a, const UnicodeString& b) {
+ if (a == b) return TRUE;
+ if (a.caseCompare(b, U_FOLD_CASE_DEFAULT)==0 && isCamel(a)) return TRUE;
+ UnicodeString aa, bb;
+ UErrorCode ec = U_ZERO_ERROR;
+ Normalizer::decompose(a, FALSE, 0, aa, ec);
+ Normalizer::decompose(b, FALSE, 0, bb, ec);
+ if (aa == bb) return TRUE;
+ if (aa.caseCompare(bb, U_FOLD_CASE_DEFAULT)==0 && isCamel(aa)) return TRUE;
+ return FALSE;
+}
+
+UBool RTTest::isCamel(const UnicodeString& a) {
+ // see if string is of the form aB; e.g. lower, then upper or title
+ UChar32 cp;
+ UBool haveLower = FALSE;
+ for (int32_t i = 0; i < a.length(); i += UTF_CHAR_LENGTH(cp)) {
+ cp = a.char32At(i);
+ int8_t t = u_charType(cp);
+ switch (t) {
+ case U_UPPERCASE_LETTER:
+ if (haveLower) return TRUE;
+ break;
+ case U_TITLECASE_LETTER:
+ if (haveLower) return TRUE;
+ // drop through, since second letter is lower.
+ case U_LOWERCASE_LETTER:
+ haveLower = TRUE;
+ break;
+ }
+ }
+ return FALSE;
+}
+
+void RTTest::test(const UnicodeString& sourceRangeVal,
+ const UnicodeString& targetRangeVal,
+ const char* roundtripExclusions,
+ IntlTest* logVal, UBool quickRt,
+ Legal* adoptedLegal,
+ int32_t density)
+{
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ this->parent = logVal;
+ this->legalSource = adoptedLegal;
+
+ UnicodeSet neverOk("[:Other:]", status);
+ UnicodeSet okAnyway("[^[:Letter:]]", status);
+
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: Initializing UnicodeSet with [:Other:] or [^[:Letter:]]");
+ return;
+ }
+
+ this->sourceRange.clear();
+ this->sourceRange.applyPattern(sourceRangeVal, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: UnicodeSet::applyPattern(" +
+ sourceRangeVal + ")");
+ return;
+ }
+ this->sourceRange.removeAll(neverOk);
+
+ this->targetRange.clear();
+ this->targetRange.applyPattern(targetRangeVal, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: UnicodeSet::applyPattern(" +
+ targetRangeVal + ")");
+ return;
+ }
+ this->targetRange.removeAll(neverOk);
+
+ this->toSource.clear();
+ this->toSource.applyPattern(sourceRangeVal, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: UnicodeSet::applyPattern(" +
+ sourceRangeVal + ")");
+ return;
+ }
+ this->toSource.addAll(okAnyway);
+
+ this->toTarget.clear();
+ this->toTarget.applyPattern(targetRangeVal, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: UnicodeSet::applyPattern(" +
+ targetRangeVal + ")");
+ return;
+ }
+ this->toTarget.addAll(okAnyway);
+
+ this->roundtripExclusionsSet.clear();
+ if (roundtripExclusions != NULL && strlen(roundtripExclusions) > 0) {
+ this->roundtripExclusionsSet.applyPattern(roundtripExclusions, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: UnicodeSet::applyPattern(%s)", roundtripExclusions);
+ return;
+ }
+ }
+
+ badCharacters.clear();
+ badCharacters.applyPattern("[:Other:]", status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: UnicodeSet::applyPattern([:Other:])");
+ return;
+ }
+
+ test2(quickRt, density);
+
+ if (errorCount > 0) {
+ char str[100];
+ int32_t length = transliteratorID.extract(str, 100, NULL, status);
+ str[length] = 0;
+ parent->errln("FAIL: %s errors: %d %s", str, errorCount, (errorCount > errorLimit ? " (at least!)" : " ")); // + ", see " + logFileName);
+ } else {
+ char str[100];
+ int32_t length = transliteratorID.extract(str, 100, NULL, status);
+ str[length] = 0;
+ parent->logln("%s ok", str);
+ }
+}
+
+UBool RTTest::checkIrrelevants(Transliterator *t,
+ const UnicodeString& irrelevants) {
+ for (int i = 0; i < irrelevants.length(); ++i) {
+ UChar c = irrelevants.charAt(i);
+ UnicodeString srcStr(c);
+ UnicodeString targ = srcStr;
+ t->transliterate(targ);
+ if (srcStr == targ) return TRUE;
+ }
+ return FALSE;
+}
+
+void RTTest::test2(UBool quickRt, int32_t density) {
+
+ UnicodeString srcStr, targ, reverse;
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError ;
+ TransliteratorPointer sourceToTarget(
+ Transliterator::createInstance(transliteratorID, UTRANS_FORWARD, parseError,
+ status));
+ if ((Transliterator *)sourceToTarget == NULL) {
+ parent->errln("FAIL: createInstance(" + transliteratorID +
+ ") returned NULL. Error: " + u_errorName(status)
+ + "\n\tpreContext : " + prettify(parseError.preContext)
+ + "\n\tpostContext : " + prettify(parseError.postContext));
+
+ return;
+ }
+ TransliteratorPointer targetToSource(sourceToTarget->createInverse(status));
+ if ((Transliterator *)targetToSource == NULL) {
+ parent->errln("FAIL: " + transliteratorID +
+ ".createInverse() returned NULL. Error:" + u_errorName(status)
+ + "\n\tpreContext : " + prettify(parseError.preContext)
+ + "\n\tpostContext : " + prettify(parseError.postContext));
+ return;
+ }
+
+ AbbreviatedUnicodeSetIterator usi;
+ AbbreviatedUnicodeSetIterator usi2;
+
+ parent->logln("Checking that at least one irrelevant character is not NFC'ed");
+ // string is from NFC_NO in the UCD
+ UnicodeString irrelevants = CharsToUnicodeString("\\u2000\\u2001\\u2126\\u212A\\u212B\\u2329");
+
+ if (checkIrrelevants(sourceToTarget, irrelevants) == FALSE) {
+ logFails("Source-Target, irrelevants");
+ }
+ if (checkIrrelevants(targetToSource, irrelevants) == FALSE) {
+ logFails("Target-Source, irrelevants");
+ }
+
+ if (!quickRt){
+ parent->logln("Checking that toRules works");
+ UnicodeString rules = "";
+
+ UParseError parseError;
+ rules = sourceToTarget->toRules(rules, TRUE);
+ // parent->logln((UnicodeString)"toRules => " + rules);
+ TransliteratorPointer sourceToTarget2(Transliterator::createFromRules(
+ "s2t2", rules,
+ UTRANS_FORWARD,
+ parseError, status));
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: createFromRules %s\n", u_errorName(status));
+ return;
+ }
+
+ rules = targetToSource->toRules(rules, FALSE);
+ TransliteratorPointer targetToSource2(Transliterator::createFromRules(
+ "t2s2", rules,
+ UTRANS_FORWARD,
+ parseError, status));
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: createFromRules %s\n", u_errorName(status));
+ return;
+ }
+
+ usi.reset(sourceRange);
+ for (;;) {
+ if (!usi.next() || usi.isString()) break;
+ UChar32 c = usi.getCodepoint();
+
+ UnicodeString srcStr((UChar32)c);
+ UnicodeString targ = srcStr;
+ sourceToTarget->transliterate(targ);
+ UnicodeString targ2 = srcStr;
+ sourceToTarget2->transliterate(targ2);
+ if (targ != targ2) {
+ logToRulesFails("Source-Target, toRules", srcStr, targ, targ2);
+ }
+ }
+
+ usi.reset(targetRange);
+ for (;;) {
+ if (!usi.next() || usi.isString()) break;
+ UChar32 c = usi.getCodepoint();
+
+ UnicodeString srcStr((UChar32)c);
+ UnicodeString targ = srcStr;
+ targetToSource->transliterate(targ);
+ UnicodeString targ2 = srcStr;
+ targetToSource2->transliterate(targ2);
+ if (targ != targ2) {
+ logToRulesFails("Target-Source, toRules", srcStr, targ, targ2);
+ }
+ }
+ }
+
+ parent->logln("Checking that all source characters convert to target - Singles");
+
+ UnicodeSet failSourceTarg;
+ usi.reset(sourceRange);
+ for (;;) {
+ if (!usi.next() || usi.isString()) break;
+ UChar32 c = usi.getCodepoint();
+
+ UnicodeString srcStr((UChar32)c);
+ UnicodeString targ = srcStr;
+ sourceToTarget->transliterate(targ);
+ if (toTarget.containsAll(targ) == FALSE
+ || badCharacters.containsSome(targ) == TRUE) {
+ UnicodeString targD;
+ Normalizer::decompose(targ, FALSE, 0, targD, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: Internal error during decomposition %s\n", u_errorName(status));
+ return;
+ }
+ if (toTarget.containsAll(targD) == FALSE ||
+ badCharacters.containsSome(targD) == TRUE) {
+ logWrongScript("Source-Target", srcStr, targ);
+ failSourceTarg.add(c);
+ continue;
+ }
+ }
+
+ UnicodeString cs2;
+ Normalizer::decompose(srcStr, FALSE, 0, cs2, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: Internal error during decomposition %s\n", u_errorName(status));
+ return;
+ }
+ UnicodeString targ2 = cs2;
+ sourceToTarget->transliterate(targ2);
+ if (targ != targ2) {
+ logNotCanonical("Source-Target", srcStr, targ,cs2, targ2);
+ }
+ }
+
+ parent->logln("Checking that all source characters convert to target - Doubles");
+
+ UnicodeSet sourceRangeMinusFailures(sourceRange);
+ sourceRangeMinusFailures.removeAll(failSourceTarg);
+
+ usi.reset(sourceRangeMinusFailures, quickRt, density);
+ for (;;) {
+ if (!usi.next() || usi.isString()) break;
+ UChar32 c = usi.getCodepoint();
+
+ usi2.reset(sourceRangeMinusFailures, quickRt, density);
+ for (;;) {
+ if (!usi2.next() || usi2.isString()) break;
+ UChar32 d = usi2.getCodepoint();
+
+ UnicodeString srcStr;
+ srcStr += (UChar32)c;
+ srcStr += (UChar32)d;
+ UnicodeString targ = srcStr;
+ sourceToTarget->transliterate(targ);
+ if (toTarget.containsAll(targ) == FALSE ||
+ badCharacters.containsSome(targ) == TRUE)
+ {
+ UnicodeString targD;
+ Normalizer::decompose(targ, FALSE, 0, targD, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: Internal error during decomposition %s\n", u_errorName(status));
+ return;
+ }
+ if (toTarget.containsAll(targD) == FALSE ||
+ badCharacters.containsSome(targD) == TRUE) {
+ logWrongScript("Source-Target", srcStr, targ);
+ continue;
+ }
+ }
+ UnicodeString cs2;
+ Normalizer::decompose(srcStr, FALSE, 0, cs2, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: Internal error during decomposition %s\n", u_errorName(status));
+ return;
+ }
+ UnicodeString targ2 = cs2;
+ sourceToTarget->transliterate(targ2);
+ if (targ != targ2) {
+ logNotCanonical("Source-Target", srcStr, targ, cs2,targ2);
+ }
+ }
+ }
+
+ parent->logln("Checking that target characters convert to source and back - Singles");
+
+ UnicodeSet failTargSource;
+ UnicodeSet failRound;
+
+ usi.reset(targetRange);
+ for (;;) {
+ if (!usi.next()) break;
+
+ if(usi.isString()){
+ srcStr = usi.getString();
+ }else{
+ srcStr = (UnicodeString)usi.getCodepoint();
+ }
+
+ UChar32 c = srcStr.char32At(0);
+
+ targ = srcStr;
+ targetToSource->transliterate(targ);
+ reverse = targ;
+ sourceToTarget->transliterate(reverse);
+
+ if (toSource.containsAll(targ) == FALSE ||
+ badCharacters.containsSome(targ) == TRUE) {
+ UnicodeString targD;
+ Normalizer::decompose(targ, FALSE, 0, targD, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: Internal error during decomposition%s\n", u_errorName(status));
+ return;
+ }
+ if (toSource.containsAll(targD) == FALSE) {
+ logWrongScript("Target-Source", srcStr, targ);
+ failTargSource.add(c);
+ continue;
+ }
+ if (badCharacters.containsSome(targD) == TRUE) {
+ logWrongScript("Target-Source*", srcStr, targ);
+ failTargSource.add(c);
+ continue;
+ }
+ }
+ if (isSame(srcStr, reverse) == FALSE &&
+ roundtripExclusionsSet.contains(c) == FALSE
+ && roundtripExclusionsSet.contains(srcStr)==FALSE) {
+ logRoundTripFailure(srcStr,targetToSource->getID(), targ,sourceToTarget->getID(), reverse);
+ failRound.add(c);
+ continue;
+ }
+
+ UnicodeString targ2;
+ Normalizer::decompose(targ, FALSE, 0, targ2, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: Internal error during decomposition%s\n", u_errorName(status));
+ return;
+ }
+ UnicodeString reverse2 = targ2;
+ sourceToTarget->transliterate(reverse2);
+ if (reverse != reverse2) {
+ logNotCanonical("Target-Source", targ, reverse, targ2, reverse2);
+ }
+ }
+
+ parent->logln("Checking that target characters convert to source and back - Doubles");
+ int32_t count = 0;
+
+ UnicodeSet targetRangeMinusFailures(targetRange);
+ targetRangeMinusFailures.removeAll(failTargSource);
+ targetRangeMinusFailures.removeAll(failRound);
+
+ usi.reset(targetRangeMinusFailures, quickRt, density);
+ UnicodeString targ2;
+ UnicodeString reverse2;
+ UnicodeString targD;
+ for (;;) {
+ if (!usi.next() || usi.isString()) break;
+ UChar32 c = usi.getCodepoint();
+ if (++count > pairLimit) {
+ //throw new TestTruncated("Test truncated at " + pairLimit + " x 64k pairs");
+ parent->logln("");
+ parent->logln((UnicodeString)"Test truncated at " + pairLimit + " x 64k pairs");
+ return;
+ }
+
+ usi2.reset(targetRangeMinusFailures, quickRt, density);
+ for (;;) {
+ if (!usi2.next() || usi2.isString())
+ break;
+ UChar32 d = usi2.getCodepoint();
+ srcStr.truncate(0); // empty the variable without construction/destruction
+ srcStr += c;
+ srcStr += d;
+
+ targ = srcStr;
+ targetToSource->transliterate(targ);
+ reverse = targ;
+ sourceToTarget->transliterate(reverse);
+
+ if (toSource.containsAll(targ) == FALSE ||
+ badCharacters.containsSome(targ) == TRUE)
+ {
+ targD.truncate(0); // empty the variable without construction/destruction
+ Normalizer::decompose(targ, FALSE, 0, targD, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: Internal error during decomposition%s\n",
+ u_errorName(status));
+ return;
+ }
+ if (toSource.containsAll(targD) == FALSE
+ || badCharacters.containsSome(targD) == TRUE)
+ {
+ logWrongScript("Target-Source", srcStr, targ);
+ continue;
+ }
+ }
+ if (isSame(srcStr, reverse) == FALSE &&
+ roundtripExclusionsSet.contains(c) == FALSE&&
+ roundtripExclusionsSet.contains(d) == FALSE &&
+ roundtripExclusionsSet.contains(srcStr)== FALSE)
+ {
+ logRoundTripFailure(srcStr,targetToSource->getID(), targ, sourceToTarget->getID(),reverse);
+ continue;
+ }
+
+ targ2.truncate(0); // empty the variable without construction/destruction
+ Normalizer::decompose(targ, FALSE, 0, targ2, status);
+ if (U_FAILURE(status)) {
+ parent->errln("FAIL: Internal error during decomposition%s\n", u_errorName(status));
+ return;
+ }
+ reverse2 = targ2;
+ sourceToTarget->transliterate(reverse2);
+ if (reverse != reverse2) {
+ logNotCanonical("Target-Source", targ,reverse, targ2, reverse2);
+ }
+ }
+ }
+ parent->logln("");
+}
+
+void RTTest::logWrongScript(const UnicodeString& label,
+ const UnicodeString& from,
+ const UnicodeString& to) {
+ parent->errln((UnicodeString)"FAIL " +
+ label + ": " +
+ from + "(" + TestUtility::hex(from) + ") => " +
+ to + "(" + TestUtility::hex(to) + ")");
+ ++errorCount;
+}
+
+void RTTest::logNotCanonical(const UnicodeString& label,
+ const UnicodeString& from,
+ const UnicodeString& to,
+ const UnicodeString& fromCan,
+ const UnicodeString& toCan) {
+ parent->errln((UnicodeString)"FAIL (can.equiv)" +
+ label + ": " +
+ from + "(" + TestUtility::hex(from) + ") => " +
+ to + "(" + TestUtility::hex(to) + ")" +
+ fromCan + "(" + TestUtility::hex(fromCan) + ") => " +
+ toCan + " (" +
+ TestUtility::hex(toCan) + ")"
+ );
+ ++errorCount;
+}
+
+void RTTest::logFails(const UnicodeString& label) {
+ parent->errln((UnicodeString)"<br>FAIL " + label);
+ ++errorCount;
+}
+
+void RTTest::logToRulesFails(const UnicodeString& label,
+ const UnicodeString& from,
+ const UnicodeString& to,
+ const UnicodeString& otherTo)
+{
+ parent->errln((UnicodeString)"FAIL: " +
+ label + ": " +
+ from + "(" + TestUtility::hex(from) + ") => " +
+ to + "(" + TestUtility::hex(to) + ")" +
+ "!=" +
+ otherTo + " (" +
+ TestUtility::hex(otherTo) + ")"
+ );
+ ++errorCount;
+}
+
+
+void RTTest::logRoundTripFailure(const UnicodeString& from,
+ const UnicodeString& toID,
+ const UnicodeString& to,
+ const UnicodeString& backID,
+ const UnicodeString& back) {
+ if (legalSource->is(from) == FALSE) return; // skip illegals
+
+ parent->errln((UnicodeString)"FAIL Roundtrip: " +
+ from + "(" + TestUtility::hex(from) + ") => " +
+ to + "(" + TestUtility::hex(to) + ") "+toID+" => " +
+ back + "(" + TestUtility::hex(back) + ") "+backID+" => ");
+ ++errorCount;
+}
+
+//--------------------------------------------------------------------
+// Specific Tests
+//--------------------------------------------------------------------
+
+ /*
+ Note: Unicode 3.2 added new Hiragana/Katakana characters:
+
+3095..3096 ; 3.2 # [2] HIRAGANA LETTER SMALL KA..HIRAGANA LETTER SMALL KE
+309F..30A0 ; 3.2 # [2] HIRAGANA DIGRAPH YORI..KATAKANA-HIRAGANA DOUBLE HYPHEN
+30FF ; 3.2 # KATAKANA DIGRAPH KOTO
+31F0..31FF ; 3.2 # [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO
+
+ We will not add them to the rules until they are more supported (e.g. in fonts on Windows)
+ A bug has been filed to remind us to do this: #1979.
+ */
+
+static const char KATAKANA[] = "[[[:katakana:][\\u30A1-\\u30FA\\u30FC]]-[\\u30FF\\u31F0-\\u31FF]]";
+static const char HIRAGANA[] = "[[[:hiragana:][\\u3040-\\u3094]]-[\\u3095-\\u3096\\u309F-\\u30A0]]";
+static const char LENGTH[] = "[\\u30FC]";
+static const char HALFWIDTH_KATAKANA[] = "[\\uFF65-\\uFF9D]";
+static const char KATAKANA_ITERATION[] = "[\\u30FD\\u30FE]";
+static const char HIRAGANA_ITERATION[] = "[\\u309D\\u309E]";
+static const int32_t TEMP_MAX=256;
+
+void TransliteratorRoundTripTest::TestKana() {
+ RTTest test("Katakana-Hiragana");
+ Legal *legal = new Legal();
+ char temp[TEMP_MAX];
+ strcpy(temp, "[");
+ strcat(temp, HALFWIDTH_KATAKANA);
+ strcat(temp, LENGTH);
+ strcat(temp, "]");
+ test.test(KATAKANA, UnicodeString("[") + HIRAGANA + LENGTH + UnicodeString("]"),
+ temp,
+ this, quick, legal);
+ delete legal;
+}
+
+void TransliteratorRoundTripTest::TestHiragana() {
+ RTTest test("Latin-Hiragana");
+ Legal *legal = new Legal();
+ test.test(UnicodeString("[a-zA-Z]", ""),
+ HIRAGANA,
+ HIRAGANA_ITERATION, this, quick, legal);
+ delete legal;
+}
+
+void TransliteratorRoundTripTest::TestKatakana() {
+ RTTest test("Latin-Katakana");
+ Legal *legal = new Legal();
+ char temp[TEMP_MAX];
+ strcpy(temp, "[");
+ strcat(temp, KATAKANA_ITERATION);
+ strcat(temp, HALFWIDTH_KATAKANA);
+ strcat(temp, "]");
+ test.test(UnicodeString("[a-zA-Z]", ""),
+ KATAKANA,
+ temp,
+ this, quick, legal);
+ delete legal;
+}
+
+void TransliteratorRoundTripTest::TestJamo() {
+ RTTest t("Latin-Jamo");
+ Legal *legal = new LegalJamo();
+ t.test(UnicodeString("[a-zA-Z]", ""),
+ UnicodeString("[\\u1100-\\u1112 \\u1161-\\u1175 \\u11A8-\\u11C2]",
+ ""),
+ NULL, this, quick, legal);
+ delete legal;
+}
+
+void TransliteratorRoundTripTest::TestHangul() {
+ RTTest t("Latin-Hangul");
+ Legal *legal = new Legal();
+ if (quick) t.setPairLimit(1000);
+ t.test(UnicodeString("[a-zA-Z]", ""),
+ UnicodeString("[\\uAC00-\\uD7A4]", ""),
+ NULL, this, quick, legal, 1);
+ delete legal;
+}
+
+
+#define ASSERT_SUCCESS(status) {if (U_FAILURE(status)) { \
+ errln("error at file %s, line %d, status = %s", __FILE__, __LINE__, \
+ u_errorName(status)); \
+ return;}}
+
+
+static void writeStringInU8(FILE *out, const UnicodeString &s) {
+ int i;
+ for (i=0; i<s.length(); i=s.moveIndex32(i, 1)) {
+ UChar32 c = s.char32At(i);
+ uint8_t bufForOneChar[10];
+ UBool isError = FALSE;
+ int32_t destIdx = 0;
+ U8_APPEND(bufForOneChar, destIdx, (int32_t)sizeof(bufForOneChar), c, isError);
+ fwrite(bufForOneChar, 1, destIdx, out);
+ }
+}
+
+
+
+
+void TransliteratorRoundTripTest::TestHan() {
+ UErrorCode status = U_ZERO_ERROR;
+
+ // TODO: getExemplars() exists only as a C API, taking a USet.
+ // The set API we need to use exists only on UnicodeSet, not on USet.
+ // Do a hacky cast, knowing that a USet is really a UnicodeSet in
+ // the implementation. Once USet gets the missing API, switch back
+ // to using that.
+ USet *USetExemplars = NULL;
+ ULocaleData *uld = ulocdata_open("zh",&status);
+ USetExemplars = uset_open(0, 0);
+ USetExemplars = ulocdata_getExemplarSet(uld, USetExemplars, 0, ULOCDATA_ES_STANDARD, &status);
+ ASSERT_SUCCESS(status);
+ ulocdata_close(uld);
+
+ UnicodeString source;
+ UChar32 c;
+ int i;
+ for (i=0; ;i++) {
+ // Add all of the Chinese exemplar chars to the string "source".
+ c = uset_charAt(USetExemplars, i);
+ if (c == (UChar32)-1) {
+ break;
+ }
+ source.append(c);
+ }
+
+ // transform with Han translit
+ Transliterator *hanTL = Transliterator::createInstance("Han-Latin", UTRANS_FORWARD, status);
+ ASSERT_SUCCESS(status);
+ UnicodeString target=source;
+ hanTL->transliterate(target);
+ // now verify that there are no Han characters left
+ UnicodeSet allHan("[:han:]", status);
+ ASSERT_SUCCESS(status);
+ if (allHan.containsSome(target)) {
+ errln("file %s, line %d, No Han must be left after Han-Latin transliteration",
+ __FILE__, __LINE__);
+ }
+
+ // check the pinyin translit
+ Transliterator *pn = Transliterator::createInstance("Latin-NumericPinyin", UTRANS_FORWARD, status);
+ ASSERT_SUCCESS(status);
+ UnicodeString target2 = target;
+ pn->transliterate(target2);
+
+ // verify that there are no marks
+ Transliterator *nfd = Transliterator::createInstance("nfd", UTRANS_FORWARD, status);
+ ASSERT_SUCCESS(status);
+
+ UnicodeString nfded = target2;
+ nfd->transliterate(nfded);
+ UnicodeSet allMarks("[\\u0304\\u0301\\u030C\\u0300\\u0306]", status); // look only for Pinyin tone marks, not all marks (there are some others in there)
+ ASSERT_SUCCESS(status);
+ assertFalse("NumericPinyin must contain no marks", allMarks.containsSome(nfded));
+
+ // verify roundtrip
+ Transliterator *np = pn->createInverse(status);
+ ASSERT_SUCCESS(status);
+ UnicodeString target3 = target2;
+ np->transliterate(target3);
+ UBool roundtripOK = (target3.compare(target) == 0);
+ assertTrue("NumericPinyin must roundtrip", roundtripOK);
+ if (!roundtripOK) {
+ const char *filename = "numeric-pinyin.log.txt";
+ FILE *out = fopen(filename, "w");
+ errln("Creating log file %s\n", filename);
+ fprintf(out, "Pinyin: ");
+ writeStringInU8(out, target);
+ fprintf(out, "\nPinyin-Numeric-Pinyin: ");
+ writeStringInU8(out, target2);
+ fprintf(out, "\nNumeric-Pinyin-Pinyin: ");
+ writeStringInU8(out, target3);
+ fprintf(out, "\n");
+ fclose(out);
+ }
+
+ delete hanTL;
+ delete pn;
+ delete nfd;
+ delete np;
+ uset_close(USetExemplars);
+}
+
+
+void TransliteratorRoundTripTest::TestGreek() {
+
+ if (isICUVersionAtLeast(ICU_39)) {
+ // We temporarily filter against Unicode 4.1, but we only do this
+ // before version 3.4.
+ errln("FAIL: TestGreek needs to be updated to remove delete the [:Age=4.0:] filter ");
+ return;
+ } else {
+ logln("Warning: TestGreek needs to be updated to remove delete the section marked [:Age=4.0:] filter");
+ }
+
+ RTTest test("Latin-Greek");
+ LegalGreek *legal = new LegalGreek(TRUE);
+
+ test.test(UnicodeString("[a-zA-Z]", ""),
+ UnicodeString("[\\u003B\\u00B7[[:Greek:]&[:Letter:]]-["
+ "\\u1D26-\\u1D2A" // L& [5] GREEK LETTER SMALL CAPITAL GAMMA..GREEK LETTER SMALL CAPITAL PSI
+ "\\u1D5D-\\u1D61" // Lm [5] MODIFIER LETTER SMALL BETA..MODIFIER LETTER SMALL CHI
+ "\\u1D66-\\u1D6A" // L& [5] GREEK SUBSCRIPT SMALL LETTER BETA..GREEK SUBSCRIPT SMALL LETTER CHI
+ "\\u03D7-\\u03EF" // \N{GREEK KAI SYMBOL}..\N{COPTIC SMALL LETTER DEI}
+ "] & [:Age=4.0:]]",
+
+ //UnicodeString("[[\\u003B\\u00B7[:Greek:]-[\\u0374\\u0385\\u1fcd\\u1fce\\u1fdd\\u1fde\\u1fed-\\u1fef\\u1ffd\\u03D7-\\u03EF]]&[:Age=3.2:]]",
+ ""),
+ "[\\u00B5\\u037A\\u03D0-\\u03F5\\u03f9]", /* exclusions */
+ this, quick, legal, 50);
+
+
+ delete legal;
+}
+
+
+void TransliteratorRoundTripTest::TestGreekUNGEGN() {
+
+ if (isICUVersionAtLeast(ICU_39)) {
+ // We temporarily filter against Unicode 4.1, but we only do this
+ // before version 3.4.
+ errln("FAIL: TestGreek needs to be updated to remove delete the [:Age=4.0:] filter ");
+ return;
+ } else {
+ logln("Warning: TestGreek needs to be updated to remove delete the section marked [:Age=4.0:] filter");
+ }
+
+ RTTest test("Latin-Greek/UNGEGN");
+ LegalGreek *legal = new LegalGreek(FALSE);
+
+ test.test(UnicodeString("[a-zA-Z]", ""),
+ UnicodeString("[\\u003B\\u00B7[[:Greek:]&[:Letter:]]-["
+ "\\u1D26-\\u1D2A" // L& [5] GREEK LETTER SMALL CAPITAL GAMMA..GREEK LETTER SMALL CAPITAL PSI
+ "\\u1D5D-\\u1D61" // Lm [5] MODIFIER LETTER SMALL BETA..MODIFIER LETTER SMALL CHI
+ "\\u1D66-\\u1D6A" // L& [5] GREEK SUBSCRIPT SMALL LETTER BETA..GREEK SUBSCRIPT SMALL LETTER CHI
+ "\\u03D7-\\u03EF" // \N{GREEK KAI SYMBOL}..\N{COPTIC SMALL LETTER DEI}
+ "] & [:Age=4.0:]]",
+ //UnicodeString("[[\\u003B\\u00B7[:Greek:]-[\\u0374\\u0385\\u1fce\\u1fde\\u03D7-\\u03EF]]&[:Age=3.2:]]",
+ ""),
+ "[\\u0385\\u00B5\\u037A\\u03D0-\\uFFFF {\\u039C\\u03C0}]", /* roundtrip exclusions */
+ this, quick, legal);
+
+ delete legal;
+}
+
+void TransliteratorRoundTripTest::Testel() {
+
+ if (isICUVersionAtLeast(ICU_39)) {
+ // We temporarily filter against Unicode 4.1, but we only do this
+ // before version 3.4.
+ errln("FAIL: TestGreek needs to be updated to remove delete the [:Age=4.0:] filter ");
+ return;
+ } else {
+ logln("Warning: TestGreek needs to be updated to remove delete the section marked [:Age=4.0:] filter");
+ }
+
+ RTTest test("Latin-el");
+ LegalGreek *legal = new LegalGreek(FALSE);
+
+ test.test(UnicodeString("[a-zA-Z]", ""),
+ UnicodeString("[\\u003B\\u00B7[[:Greek:]&[:Letter:]]-["
+ "\\u1D26-\\u1D2A" // L& [5] GREEK LETTER SMALL CAPITAL GAMMA..GREEK LETTER SMALL CAPITAL PSI
+ "\\u1D5D-\\u1D61" // Lm [5] MODIFIER LETTER SMALL BETA..MODIFIER LETTER SMALL CHI
+ "\\u1D66-\\u1D6A" // L& [5] GREEK SUBSCRIPT SMALL LETTER BETA..GREEK SUBSCRIPT SMALL LETTER CHI
+ "\\u03D7-\\u03EF" // \N{GREEK KAI SYMBOL}..\N{COPTIC SMALL LETTER DEI}
+ "] & [:Age=4.0:]]",
+ //UnicodeString("[[\\u003B\\u00B7[:Greek:]-[\\u0374\\u0385\\u1fce\\u1fde\\u03D7-\\u03EF]]&[:Age=3.2:]]",
+ ""),
+ "[\\u00B5\\u037A\\u03D0-\\uFFFF {\\u039C\\u03C0}]", /* exclusions */
+ this, quick, legal);
+
+
+ delete legal;
+}
+
+
+void TransliteratorRoundTripTest::TestArabic() {
+ UnicodeString ARABIC("[\\u060C\\u061B\\u061F\\u0621\\u0627-\\u063A\\u0641-\\u0655\\u0660-\\u066C\\u067E\\u0686\\u0698\\u06A4\\u06AD\\u06AF\\u06CB-\\u06CC\\u06F0-\\u06F9]");
+ Legal *legal = new Legal();
+ RTTest test("Latin-Arabic");
+ test.test("[a-zA-Z\\u02BE\\u02BF\\u207F]", ARABIC, "[a-zA-Z\\u02BE\\u02BF\\u207F]",this, quick, legal); //
+ delete legal;
+}
+class LegalHebrew : public Legal {
+private:
+ UnicodeSet FINAL;
+ UnicodeSet NON_FINAL;
+ UnicodeSet LETTER;
+public:
+ LegalHebrew(UErrorCode& error);
+ virtual ~LegalHebrew() {}
+ virtual UBool is(const UnicodeString& sourceString) const;
+};
+
+LegalHebrew::LegalHebrew(UErrorCode& error){
+ FINAL.applyPattern("[\\u05DA\\u05DD\\u05DF\\u05E3\\u05E5]", error);
+ NON_FINAL.applyPattern("[\\u05DB\\u05DE\\u05E0\\u05E4\\u05E6]", error);
+ LETTER.applyPattern("[:letter:]", error);
+}
+UBool LegalHebrew::is(const UnicodeString& sourceString)const{
+
+ if (sourceString.length() == 0) return TRUE;
+ // don't worry about surrogates.
+ for (int i = 0; i < sourceString.length(); ++i) {
+ UChar ch = sourceString.charAt(i);
+ UChar next = i+1 == sourceString.length() ? 0x0000 : sourceString.charAt(i);
+ if (FINAL.contains(ch)) {
+ if (LETTER.contains(next)) return FALSE;
+ } else if (NON_FINAL.contains(ch)) {
+ if (!LETTER.contains(next)) return FALSE;
+ }
+ }
+ return TRUE;
+}
+void TransliteratorRoundTripTest::TestHebrew() {
+ if (isICUVersionAtLeast(ICU_39)) {
+ // We temporarily filter against Unicode 4.1, but we only do this
+ // before version 3.4.
+ errln("FAIL: TestHebrew needs to be updated to remove delete the [:Age=4.0:] filter ");
+ return;
+ } else {
+ logln("Warning: TestHebrew needs to be updated to remove delete the section marked [:Age=4.0:] filter");
+ }
+ //long start = System.currentTimeMillis();
+ UErrorCode error = U_ZERO_ERROR;
+ LegalHebrew* legal = new LegalHebrew(error);
+ if(U_FAILURE(error)){
+ errln("Could not construct LegalHebrew object. Error: %s", u_errorName(error));
+ return;
+ }
+ RTTest test("Latin-Hebrew");
+ test.test("[a-zA-Z\\u02BC\\u02BB]", "[[[:hebrew:]-[\\u05BD\\uFB00-\\uFBFF]]&[:Age=4.0:]]", "[\\u05F0\\u05F1\\u05F2]", this, quick, legal);
+
+ //showElapsed(start, "TestHebrew");
+ delete legal;
+}
+void TransliteratorRoundTripTest::TestCyrillic() {
+ RTTest test("Latin-Cyrillic");
+ Legal *legal = new Legal();
+
+ test.test(UnicodeString("[a-zA-Z\\u0110\\u0111\\u02BA\\u02B9]", ""),
+ UnicodeString("[[\\u0400-\\u045F] & [:Age=3.2:]]", ""), NULL, this, quick,
+ legal);
+
+ delete legal;
+}
+
+
+// Inter-Indic Tests ----------------------------------
+class LegalIndic :public Legal{
+ UnicodeSet vowelSignSet;
+ UnicodeSet avagraha;
+ UnicodeSet nukta;
+ UnicodeSet virama;
+ UnicodeSet sanskritStressSigns;
+ UnicodeSet chandrabindu;
+
+public:
+ LegalIndic();
+ virtual UBool is(const UnicodeString& sourceString) const;
+ virtual ~LegalIndic() {};
+};
+UBool LegalIndic::is(const UnicodeString& sourceString) const{
+ int cp=sourceString.charAt(0);
+
+ // A vowel sign cannot be the first char
+ if(vowelSignSet.contains(cp)){
+ return FALSE;
+ }else if(avagraha.contains(cp)){
+ return FALSE;
+ }else if(virama.contains(cp)){
+ return FALSE;
+ }else if(nukta.contains(cp)){
+ return FALSE;
+ }else if(sanskritStressSigns.contains(cp)){
+ return FALSE;
+ }else if(chandrabindu.contains(cp) &&
+ ((sourceString.length()>1) &&
+ vowelSignSet.contains(sourceString.charAt(1)))){
+ return FALSE;
+ }
+ return TRUE;
+}
+LegalIndic::LegalIndic(){
+ UErrorCode status = U_ZERO_ERROR;
+ vowelSignSet.addAll( UnicodeSet("[\\u0902\\u0903\\u0904\\u093e-\\u094c\\u0962\\u0963]",status));/* Devanagari */
+ vowelSignSet.addAll( UnicodeSet("[\\u0982\\u0983\\u09be-\\u09cc\\u09e2\\u09e3\\u09D7]",status));/* Bengali */
+ vowelSignSet.addAll( UnicodeSet("[\\u0a02\\u0a03\\u0a3e-\\u0a4c\\u0a62\\u0a63\\u0a70\\u0a71]",status));/* Gurmukhi */
+ vowelSignSet.addAll( UnicodeSet("[\\u0a82\\u0a83\\u0abe-\\u0acc\\u0ae2\\u0ae3]",status));/* Gujarati */
+ vowelSignSet.addAll( UnicodeSet("[\\u0b02\\u0b03\\u0b3e-\\u0b4c\\u0b62\\u0b63\\u0b56\\u0b57]",status));/* Oriya */
+ vowelSignSet.addAll( UnicodeSet("[\\u0b82\\u0b83\\u0bbe-\\u0bcc\\u0be2\\u0be3\\u0bd7]",status));/* Tamil */
+ vowelSignSet.addAll( UnicodeSet("[\\u0c02\\u0c03\\u0c3e-\\u0c4c\\u0c62\\u0c63\\u0c55\\u0c56]",status));/* Telugu */
+ vowelSignSet.addAll( UnicodeSet("[\\u0c82\\u0c83\\u0cbe-\\u0ccc\\u0ce2\\u0ce3\\u0cd5\\u0cd6]",status));/* Kannada */
+ vowelSignSet.addAll( UnicodeSet("[\\u0d02\\u0d03\\u0d3e-\\u0d4c\\u0d62\\u0d63\\u0d57]",status));/* Malayalam */
+
+ avagraha.addAll(UnicodeSet("[\\u093d\\u09bd\\u0abd\\u0b3d\\u0cbd]",status));
+ nukta.addAll(UnicodeSet("[\\u093c\\u09bc\\u0a3c\\u0abc\\u0b3c\\u0cbc]",status));
+ virama.addAll(UnicodeSet("[\\u094d\\u09cd\\u0a4d\\u0acd\\u0b4d\\u0bcd\\u0c4d\\u0ccd\\u0d4d]",status));
+ sanskritStressSigns.addAll(UnicodeSet("[\\u0951\\u0952\\u0953\\u0954\\u097d]",status));
+ chandrabindu.addAll(UnicodeSet("[\\u0901\\u0981\\u0A81\\u0b01\\u0c01]",status));
+
+ }
+
+static const char latinForIndic[] = "[['.0-9A-Za-z~\\u00C0-\\u00C5\\u00C7-\\u00CF\\u00D1-\\u00D6\\u00D9-\\u00DD"
+ "\\u00E0-\\u00E5\\u00E7-\\u00EF\\u00F1-\\u00F6\\u00F9-\\u00FD\\u00FF-\\u010F"
+ "\\u0112-\\u0125\\u0128-\\u0130\\u0134-\\u0137\\u0139-\\u013E\\u0143-\\u0148"
+ "\\u014C-\\u0151\\u0154-\\u0165\\u0168-\\u017E\\u01A0-\\u01A1\\u01AF-\\u01B0"
+ "\\u01CD-\\u01DC\\u01DE-\\u01E3\\u01E6-\\u01ED\\u01F0\\u01F4-\\u01F5\\u01F8-\\u01FB"
+ "\\u0200-\\u021B\\u021E-\\u021F\\u0226-\\u0233\\u0294\\u0303-\\u0304\\u0306\\u0314-\\u0315"
+ "\\u0325\\u040E\\u0419\\u0439\\u045E\\u04C1-\\u04C2\\u04D0-\\u04D1\\u04D6-\\u04D7"
+ "\\u04E2-\\u04E3\\u04EE-\\u04EF\\u1E00-\\u1E99\\u1EA0-\\u1EF9\\u1F01\\u1F03\\u1F05"
+ "\\u1F07\\u1F09\\u1F0B\\u1F0D\\u1F0F\\u1F11\\u1F13\\u1F15\\u1F19\\u1F1B\\u1F1D\\u1F21"
+ "\\u1F23\\u1F25\\u1F27\\u1F29\\u1F2B\\u1F2D\\u1F2F\\u1F31\\u1F33\\u1F35\\u1F37\\u1F39"
+ "\\u1F3B\\u1F3D\\u1F3F\\u1F41\\u1F43\\u1F45\\u1F49\\u1F4B\\u1F4D\\u1F51\\u1F53\\u1F55"
+ "\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F\\u1F61\\u1F63\\u1F65\\u1F67\\u1F69\\u1F6B\\u1F6D"
+ "\\u1F6F\\u1F81\\u1F83\\u1F85\\u1F87\\u1F89\\u1F8B\\u1F8D\\u1F8F\\u1F91\\u1F93\\u1F95"
+ "\\u1F97\\u1F99\\u1F9B\\u1F9D\\u1F9F\\u1FA1\\u1FA3\\u1FA5\\u1FA7\\u1FA9\\u1FAB\\u1FAD"
+ "\\u1FAF-\\u1FB1\\u1FB8-\\u1FB9\\u1FD0-\\u1FD1\\u1FD8-\\u1FD9\\u1FE0-\\u1FE1\\u1FE5"
+ "\\u1FE8-\\u1FE9\\u1FEC\\u212A-\\u212B\\uE04D\\uE064]"
+ "-[\\uE000-\\uE080 \\u01E2\\u01E3]& [[:latin:][:mark:]]]";
+
+void TransliteratorRoundTripTest::TestDevanagariLatin() {
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ TransliteratorPointer t1(Transliterator::createInstance("[\\u0964-\\u0965\\u0981-\\u0983\\u0985-\\u098C\\u098F-\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BC\\u09BE-\\u09C4\\u09C7-\\u09C8\\u09CB-\\u09CD\\u09D7\\u09DC-\\u09DD\\u09DF-\\u09E3\\u09E6-\\u09FA];NFD;Bengali-InterIndic;InterIndic-Gujarati;NFC;",UTRANS_FORWARD, parseError, status));
+ if((Transliterator *)t1 != NULL){
+ TransliteratorPointer t2(t1->createInverse(status));
+ if(U_FAILURE(status)){
+ errln("FAIL: could not create the Inverse:-( \n");
+ }
+ }else {
+ errln("FAIL: could not create the transliterator. Error: %s\n", u_errorName(status));
+ }
+
+ }
+ RTTest test("Latin-Devanagari");
+ Legal *legal = new LegalIndic();
+ if (isICUVersionAtLeast(ICU_39)) {
+ // We temporarily filter against Unicode 4.1, but we only do this
+ // before version 3.4.
+ errln("FAIL: TestDevanagariLatin needs to be updated to remove delete the [:Age=4.1:] filter ");
+ return;
+ } else {
+ logln("Warning: TestDevanagariLatin needs to be updated to remove delete the section marked [:Age=4.1:] filter");
+ }
+ test.test(UnicodeString(latinForIndic, ""),
+ UnicodeString("[[[:Devanagari:][\\u094d][\\u0964\\u0965]]&[:Age=4.1:]]", ""), "[\\u0965\\u0904]", this, quick,
+ legal, 50);
+
+ delete legal;
+}
+
+/* Defined this way for HP/UX11CC :-( */
+static const int32_t INTER_INDIC_ARRAY_WIDTH = 4;
+static const char * const interIndicArray[] = {
+
+ "BENGALI-DEVANAGARI", "[:BENGALI:]", "[:Devanagari:]",
+ "[\\u0904\\u0951-\\u0954\\u0943-\\u0949\\u094a\\u0962\\u0963\\u090D\\u090e\\u0911\\u0912\\u0929\\u0933\\u0934\\u0935\\u093d\\u0950\\u0958\\u0959\\u095a\\u095b\\u095e\\u097d]", /*roundtrip exclusions*/
+
+ "DEVANAGARI-BENGALI", "[:Devanagari:]", "[:BENGALI:]",
+ "[\\u0951-\\u0954\\u0951-\\u0954\\u09D7\\u090D\\u090e\\u0911\\u0912\\u0929\\u0933\\u0934\\u0935\\u093d\\u0950\\u0958\\u0959\\u095a\\u095b\\u095e\\u09f0\\u09f1\\u09f2-\\u09fa\\u09ce]", /*roundtrip exclusions*/
+
+ "GURMUKHI-DEVANAGARI", "[:GURMUKHI:]", "[:Devanagari:]",
+ "[\\u0904\\u0901\\u0902\\u0936\\u0933\\u0951-\\u0954\\u0902\\u0903\\u0943-\\u0949\\u094a\\u0962\\u0963\\u090B\\u090C\\u090D\\u090e\\u0911\\u0912\\u0934\\u0937\\u093D\\u0950\\u0960\\u0961\\u097d]", /*roundtrip exclusions*/
+
+ "DEVANAGARI-GURMUKHI", "[:Devanagari:]", "[:GURMUKHI:]",
+ "[\\u0904\\u0A02\\u0946\\u0A5C\\u0951-\\u0954\\u0A70\\u0A71\\u090B\\u090C\\u090D\\u090e\\u0911\\u0912\\u0934\\u0937\\u093D\\u0950\\u0960\\u0961\\u0a72\\u0a73\\u0a74]", /*roundtrip exclusions*/
+
+ "GUJARATI-DEVANAGARI", "[:GUJARATI:]", "[:Devanagari:]",
+ "[\\u0946\\u094A\\u0962\\u0963\\u0951-\\u0954\\u0961\\u090c\\u090e\\u0912\\u097d]", /*roundtrip exclusions*/
+
+ "DEVANAGARI-GUJARATI", "[:Devanagari:]", "[:GUJARATI:]",
+ "[\\u0951-\\u0954\\u0961\\u090c\\u090e\\u0912]", /*roundtrip exclusions*/
+
+ "ORIYA-DEVANAGARI", "[:ORIYA:]", "[:Devanagari:]",
+ "[\\u0904\\u0943-\\u094a\\u0962\\u0963\\u0951-\\u0954\\u0950\\u090D\\u090e\\u0912\\u0911\\u0931\\u0935\\u097d]", /*roundtrip exclusions*/
+
+ "DEVANAGARI-ORIYA", "[:Devanagari:]", "[:ORIYA:]",
+ "[\\u0b5f\\u0b56\\u0b57\\u0b70\\u0b71\\u0950\\u090D\\u090e\\u0912\\u0911\\u0931]", /*roundtrip exclusions*/
+
+ "Tamil-DEVANAGARI", "[:tamil:]", "[:Devanagari:]",
+ "[\\u0901\\u0904\\u093c\\u0943-\\u094a\\u0951-\\u0954\\u0962\\u0963\\u090B\\u090C\\u090D\\u0911\\u0916\\u0917\\u0918\\u091B\\u091D\\u0920\\u0921\\u0922\\u0925\\u0926\\u0927\\u092B\\u092C\\u092D\\u0936\\u093d\\u0950[\\u0958-\\u0961]\\u097d]", /*roundtrip exclusions*/
+
+ "DEVANAGARI-Tamil", "[:Devanagari:]", "[:tamil:]",
+ "[\\u0bd7\\u0BF0\\u0BF1\\u0BF2]", /*roundtrip exclusions*/
+
+ "Telugu-DEVANAGARI", "[:telugu:]", "[:Devanagari:]",
+ "[\\u0904\\u093c\\u0950\\u0945\\u0949\\u0951-\\u0954\\u0962\\u0963\\u090D\\u0911\\u093d\\u0929\\u0934[\\u0958-\\u095f]\\u097d]", /*roundtrip exclusions*/
+
+ "DEVANAGARI-TELUGU", "[:Devanagari:]", "[:TELUGU:]",
+ "[\\u0c55\\u0c56\\u0950\\u090D\\u0911\\u093d\\u0929\\u0934[\\u0958-\\u095f]]", /*roundtrip exclusions*/
+
+ "KANNADA-DEVANAGARI", "[:KANNADA:]", "[:Devanagari:]",
+ "[\\u0901\\u0904\\u0946\\u093c\\u0950\\u0945\\u0949\\u0951-\\u0954\\u0962\\u0963\\u0950\\u090D\\u0911\\u093d\\u0929\\u0934[\\u0958-\\u095f]\\u097d]", /*roundtrip exclusions*/
+
+ "DEVANAGARI-KANNADA", "[:Devanagari:]", "[:KANNADA:]",
+ "[{\\u0cb0\\u0cbc}{\\u0cb3\\u0cbc}\\u0cde\\u0cd5\\u0cd6\\u0950\\u090D\\u0911\\u093d\\u0929\\u0934[\\u0958-\\u095f]]", /*roundtrip exclusions*/
+
+ "MALAYALAM-DEVANAGARI", "[:MALAYALAM:]", "[:Devanagari:]",
+ "[\\u0901\\u0904\\u094a\\u094b\\u094c\\u093c\\u0950\\u0944\\u0945\\u0949\\u0951-\\u0954\\u0962\\u0963\\u090D\\u0911\\u093d\\u0929\\u0934[\\u0958-\\u095f]\\u097d]", /*roundtrip exclusions*/
+
+ "DEVANAGARI-MALAYALAM", "[:Devanagari:]", "[:MALAYALAM:]",
+ "[\\u0d4c\\u0d57\\u0950\\u090D\\u0911\\u093d\\u0929\\u0934[\\u0958-\\u095f]]", /*roundtrip exclusions*/
+
+ "GURMUKHI-BENGALI", "[:GURMUKHI:]", "[:BENGALI:]",
+ "[\\u0981\\u0982\\u09b6\\u09e2\\u09e3\\u09c3\\u09c4\\u09d7\\u098B\\u098C\\u09B7\\u09E0\\u09E1\\u09F0\\u09F1\\u09f2-\\u09fa\\u09ce]", /*roundtrip exclusions*/
+
+ "BENGALI-GURMUKHI", "[:BENGALI:]", "[:GURMUKHI:]",
+ "[\\u0A02\\u0a5c\\u0a47\\u0a70\\u0a71\\u0A33\\u0A35\\u0A59\\u0A5A\\u0A5B\\u0A5E\\u0A72\\u0A73\\u0A74]", /*roundtrip exclusions*/
+
+ "GUJARATI-BENGALI", "[:GUJARATI:]", "[:BENGALI:]",
+ "[\\u09d7\\u09e2\\u09e3\\u098c\\u09e1\\u09f0\\u09f1\\u09f2-\\u09fa\\u09ce]", /*roundtrip exclusions*/
+
+ "BENGALI-GUJARATI", "[:BENGALI:]", "[:GUJARATI:]",
+ "[\\u0A82\\u0a83\\u0Ac9\\u0Ac5\\u0ac7\\u0A8D\\u0A91\\u0AB3\\u0AB5\\u0ABD\\u0AD0]", /*roundtrip exclusions*/
+
+ "ORIYA-BENGALI", "[:ORIYA:]", "[:BENGALI:]",
+ "[\\u09c4\\u09e2\\u09e3\\u09f0\\u09f1\\u09f2-\\u09fa\\u09ce]", /*roundtrip exclusions*/
+
+ "BENGALI-ORIYA", "[:BENGALI:]", "[:ORIYA:]",
+ "[\\u0b35\\u0b71\\u0b5f\\u0b56\\u0b33\\u0b3d]", /*roundtrip exclusions*/
+
+ "Tamil-BENGALI", "[:tamil:]", "[:BENGALI:]",
+ "[\\u0981\\u09bc\\u09c3\\u09c4\\u09e2\\u09e3\\u09f0\\u09f1\\u098B\\u098C\\u0996\\u0997\\u0998\\u099B\\u099D\\u09A0\\u09A1\\u09A2\\u09A5\\u09A6\\u09A7\\u09AB\\u09AC\\u09AD\\u09B6\\u09DC\\u09DD\\u09DF\\u09E0\\u09E1\\u09f2-\\u09fa\\u09ce]", /*roundtrip exclusions*/
+
+ "BENGALI-Tamil", "[:BENGALI:]", "[:tamil:]",
+ "[\\u0bc6\\u0bc7\\u0bca\\u0B8E\\u0B92\\u0BA9\\u0BB1\\u0BB3\\u0BB4\\u0BB5\\u0BF0\\u0BF1\\u0BF2]", /*roundtrip exclusions*/
+
+ "Telugu-BENGALI", "[:telugu:]", "[:BENGALI:]",
+ "[\\u09e2\\u09e3\\u09bc\\u09d7\\u09f0\\u09f1\\u09dc\\u09dd\\u09df\\u09f2-\\u09fa\\u09ce]", /*roundtrip exclusions*/
+
+ "BENGALI-TELUGU", "[:BENGALI:]", "[:TELUGU:]",
+ "[\\u0c55\\u0c56\\u0c47\\u0c46\\u0c4a\\u0C0E\\u0C12\\u0C31\\u0C33\\u0C35]", /*roundtrip exclusions*/
+
+ "KANNADA-BENGALI", "[:KANNADA:]", "[:BENGALI:]",
+ "[\\u0981\\u09e2\\u09e3\\u09bc\\u09d7\\u09dc\\u09dd\\u09df\\u09f0\\u09f1\\u09f2-\\u09fa\\u09ce]", /*roundtrip exclusions*/
+
+ "BENGALI-KANNADA", "[:BENGALI:]", "[:KANNADA:]",
+ "[{\\u0cb0\\u0cbc}{\\u0cb3\\u0cbc}\\u0cc6\\u0cca\\u0cd5\\u0cd6\\u0cc7\\u0C8E\\u0C92\\u0CB1\\u0cb3\\u0cb5\\u0cde]", /*roundtrip exclusions*/
+
+ "MALAYALAM-BENGALI", "[:MALAYALAM:]", "[:BENGALI:]",
+ "[\\u0981\\u09e2\\u09e3\\u09bc\\u09c4\\u09f0\\u09f1\\u09dc\\u09dd\\u09df\\u09dc\\u09dd\\u09df\\u09f2-\\u09fa\\u09ce]", /*roundtrip exclusions*/
+
+ "BENGALI-MALAYALAM", "[:BENGALI:]", "[:MALAYALAM:]",
+ "[\\u0d46\\u0d4a\\u0d47\\u0d31-\\u0d35\\u0d0e\\u0d12]", /*roundtrip exclusions*/
+
+ "GUJARATI-GURMUKHI", "[:GUJARATI:]", "[:GURMUKHI:]",
+ "[\\u0A02\\u0ab3\\u0ab6\\u0A70\\u0a71\\u0a82\\u0a83\\u0ac3\\u0ac4\\u0ac5\\u0ac9\\u0a5c\\u0a72\\u0a73\\u0a74\\u0a8b\\u0a8d\\u0a91\\u0abd]", /*roundtrip exclusions*/
+
+ "GURMUKHI-GUJARATI", "[:GURMUKHI:]", "[:GUJARATI:]",
+ "[\\u0a5c\\u0A70\\u0a71\\u0a72\\u0a73\\u0a74\\u0a82\\u0a83\\u0a8b\\u0a8c\\u0a8d\\u0a91\\u0ab3\\u0ab6\\u0ab7\\u0abd\\u0ac3\\u0ac4\\u0ac5\\u0ac9\\u0ad0\\u0ae0\\u0ae1]", /*roundtrip exclusions*/
+
+ "ORIYA-GURMUKHI", "[:ORIYA:]", "[:GURMUKHI:]",
+ "[\\u0A01\\u0A02\\u0a5c\\u0a21\\u0a47\\u0a71\\u0b02\\u0b03\\u0b33\\u0b36\\u0b43\\u0b56\\u0b57\\u0B0B\\u0B0C\\u0B37\\u0B3D\\u0B5F\\u0B60\\u0B61\\u0a35\\u0a72\\u0a73\\u0a74]", /*roundtrip exclusions*/
+
+ "GURMUKHI-ORIYA", "[:GURMUKHI:]", "[:ORIYA:]",
+ "[\\u0b01\\u0b02\\u0b03\\u0b33\\u0b36\\u0b43\\u0b56\\u0b57\\u0B0B\\u0B0C\\u0B37\\u0B3D\\u0B5F\\u0B60\\u0B61\\u0b70\\u0b71]", /*roundtrip exclusions*/
+
+ "TAMIL-GURMUKHI", "[:TAMIL:]", "[:GURMUKHI:]",
+ "[\\u0A01\\u0A02\\u0a33\\u0a36\\u0a3c\\u0a70\\u0a71\\u0a47\\u0A16\\u0A17\\u0A18\\u0A1B\\u0A1D\\u0A20\\u0A21\\u0A22\\u0A25\\u0A26\\u0A27\\u0A2B\\u0A2C\\u0A2D\\u0A59\\u0A5A\\u0A5B\\u0A5C\\u0A5E\\u0A72\\u0A73\\u0A74]", /*roundtrip exclusions*/
+
+ "GURMUKHI-TAMIL", "[:GURMUKHI:]", "[:TAMIL:]",
+ "[\\u0b82\\u0bc6\\u0bca\\u0bd7\\u0bb7\\u0bb3\\u0b83\\u0B8E\\u0B92\\u0BA9\\u0BB1\\u0BB4\\u0bb6\\u0BF0\\u0BF1\\u0BF2]", /*roundtrip exclusions*/
+
+ "TELUGU-GURMUKHI", "[:TELUGU:]", "[:GURMUKHI:]",
+ "[\\u0A02\\u0a33\\u0a36\\u0a3c\\u0a70\\u0a71\\u0A59\\u0A5A\\u0A5B\\u0A5C\\u0A5E\\u0A72\\u0A73\\u0A74]", /*roundtrip exclusions*/
+
+ "GURMUKHI-TELUGU", "[:GURMUKHI:]", "[:TELUGU:]",
+ "[\\u0c01\\u0c02\\u0c03\\u0c33\\u0c36\\u0c44\\u0c43\\u0c46\\u0c4a\\u0c56\\u0c55\\u0C0B\\u0C0C\\u0C0E\\u0C12\\u0C31\\u0C37\\u0C60\\u0C61]", /*roundtrip exclusions*/
+
+ "KANNADA-GURMUKHI", "[:KANNADA:]", "[:GURMUKHI:]",
+ "[\\u0A01\\u0A02\\u0a33\\u0a36\\u0a3c\\u0a70\\u0a71\\u0A59\\u0A5A\\u0A5B\\u0A5C\\u0A5E\\u0A72\\u0A73\\u0A74]", /*roundtrip exclusions*/
+
+ "GURMUKHI-KANNADA", "[:GURMUKHI:]", "[:KANNADA:]",
+ "[{\\u0cb0\\u0cbc}{\\u0cb3\\u0cbc}\\u0c82\\u0c83\\u0cb3\\u0cb6\\u0cc4\\u0cc3\\u0cc6\\u0cca\\u0cd5\\u0cd6\\u0C8B\\u0C8C\\u0C8E\\u0C92\\u0CB1\\u0CB7\\u0cbd\\u0CE0\\u0CE1\\u0cde]", /*roundtrip exclusions*/
+
+ "MALAYALAM-GURMUKHI", "[:MALAYALAM:]", "[:GURMUKHI:]",
+ "[\\u0A01\\u0A02\\u0a4b\\u0a4c\\u0a33\\u0a36\\u0a3c\\u0a70\\u0a71\\u0A59\\u0A5A\\u0A5B\\u0A5C\\u0A5E\\u0A72\\u0A73\\u0A74]", /*roundtrip exclusions*/
+
+ "GURMUKHI-MALAYALAM", "[:GURMUKHI:]", "[:MALAYALAM:]",
+ "[\\u0d02\\u0d03\\u0d33\\u0d36\\u0d43\\u0d46\\u0d4a\\u0d4c\\u0d57\\u0D0B\\u0D0C\\u0D0E\\u0D12\\u0D31\\u0D34\\u0D37\\u0D60\\u0D61]", /*roundtrip exclusions*/
+
+ "GUJARATI-ORIYA", "[:GUJARATI:]", "[:ORIYA:]",
+ "[\\u0b56\\u0b57\\u0B0C\\u0B5F\\u0B61\\u0b70\\u0b71]", /*roundtrip exclusions*/
+
+ "ORIYA-GUJARATI", "[:ORIYA:]", "[:GUJARATI:]",
+ "[\\u0Ac4\\u0Ac5\\u0Ac9\\u0Ac7\\u0A8D\\u0A91\\u0AB5\\u0Ad0]", /*roundtrip exclusions*/
+
+ "TAMIL-GUJARATI", "[:TAMIL:]", "[:GUJARATI:]",
+ "[\\u0A81\\u0a8c\\u0abc\\u0ac3\\u0Ac4\\u0Ac5\\u0Ac9\\u0Ac7\\u0A8B\\u0A8D\\u0A91\\u0A96\\u0A97\\u0A98\\u0A9B\\u0A9D\\u0AA0\\u0AA1\\u0AA2\\u0AA5\\u0AA6\\u0AA7\\u0AAB\\u0AAC\\u0AAD\\u0AB6\\u0ABD\\u0AD0\\u0AE0\\u0AE1]", /*roundtrip exclusions*/
+
+ "GUJARATI-TAMIL", "[:GUJARATI:]", "[:TAMIL:]",
+ "[\\u0Bc6\\u0Bca\\u0Bd7\\u0B8E\\u0B92\\u0BA9\\u0BB1\\u0BB4\\u0BF0\\u0BF1\\u0BF2]", /*roundtrip exclusions*/
+
+ "TELUGU-GUJARATI", "[:TELUGU:]", "[:GUJARATI:]",
+ "[\\u0abc\\u0Ac5\\u0Ac9\\u0A8D\\u0A91\\u0ABD\\u0Ad0]", /*roundtrip exclusions*/
+
+ "GUJARATI-TELUGU", "[:GUJARATI:]", "[:TELUGU:]",
+ "[\\u0c46\\u0c4a\\u0c55\\u0c56\\u0C0C\\u0C0E\\u0C12\\u0C31\\u0C61]", /*roundtrip exclusions*/
+
+ "KANNADA-GUJARATI", "[:KANNADA:]", "[:GUJARATI:]",
+ "[\\u0A81\\u0abc\\u0Ac5\\u0Ac9\\u0A8D\\u0A91\\u0ABD\\u0Ad0]", /*roundtrip exclusions*/
+
+ "GUJARATI-KANNADA", "[:GUJARATI:]", "[:KANNADA:]",
+ "[{\\u0cb0\\u0cbc}{\\u0cb3\\u0cbc}\\u0cc6\\u0cca\\u0cd5\\u0cd6\\u0C8C\\u0C8E\\u0C92\\u0CB1\\u0CDE\\u0CE1]", /*roundtrip exclusions*/
+
+ "MALAYALAM-GUJARATI", "[:MALAYALAM:]", "[:GUJARATI:]",
+ "[\\u0A81\\u0ac4\\u0acb\\u0acc\\u0abc\\u0Ac5\\u0Ac9\\u0A8D\\u0A91\\u0ABD\\u0Ad0]", /*roundtrip exclusions*/
+
+ "GUJARATI-MALAYALAM", "[:GUJARATI:]", "[:MALAYALAM:]",
+ "[\\u0d46\\u0d4a\\u0d4c\\u0d55\\u0d57\\u0D0C\\u0D0E\\u0D12\\u0D31\\u0D34\\u0D61]", /*roundtrip exclusions*/
+
+ "TAMIL-ORIYA", "[:TAMIL:]", "[:ORIYA:]",
+ "[\\u0B01\\u0b3c\\u0b43\\u0b56\\u0B0B\\u0B0C\\u0B16\\u0B17\\u0B18\\u0B1B\\u0B1D\\u0B20\\u0B21\\u0B22\\u0B25\\u0B26\\u0B27\\u0B2B\\u0B2C\\u0B2D\\u0B36\\u0B3D\\u0B5C\\u0B5D\\u0B5F\\u0B60\\u0B61\\u0b70\\u0b71]", /*roundtrip exclusions*/
+
+ "ORIYA-TAMIL", "[:ORIYA:]", "[:TAMIL:]",
+ "[\\u0bc6\\u0bca\\u0bc7\\u0B8E\\u0B92\\u0BA9\\u0BB1\\u0BB4\\u0BB5\\u0BF0\\u0BF1\\u0BF2]", /*roundtrip exclusions*/
+
+ "TELUGU-ORIYA", "[:TELUGU:]", "[:ORIYA:]",
+ "[\\u0b3c\\u0b57\\u0b56\\u0B3D\\u0B5C\\u0B5D\\u0B5F\\u0b70\\u0b71]", /*roundtrip exclusions*/
+
+ "ORIYA-TELUGU", "[:ORIYA:]", "[:TELUGU:]",
+ "[\\u0c44\\u0c46\\u0c4a\\u0c55\\u0c47\\u0C0E\\u0C12\\u0C31\\u0C35]", /*roundtrip exclusions*/
+
+ "KANNADA-ORIYA", "[:KANNADA:]", "[:ORIYA:]",
+ "[\\u0B01\\u0b3c\\u0b57\\u0B3D\\u0B5C\\u0B5D\\u0B5F\\u0b70\\u0b71]", /*roundtrip exclusions*/
+
+ "ORIYA-KANNADA", "[:ORIYA:]", "[:KANNADA:]",
+ "[{\\u0cb0\\u0cbc}{\\u0cb3\\u0cbc}\\u0cc4\\u0cc6\\u0cca\\u0cd5\\u0cc7\\u0C8E\\u0C92\\u0CB1\\u0CB5\\u0CDE]", /*roundtrip exclusions*/
+
+ "MALAYALAM-ORIYA", "[:MALAYALAM:]", "[:ORIYA:]",
+ "[\\u0B01\\u0b3c\\u0b56\\u0B3D\\u0B5C\\u0B5D\\u0B5F\\u0b70\\u0b71]", /*roundtrip exclusions*/
+
+ "ORIYA-MALAYALAM", "[:ORIYA:]", "[:MALAYALAM:]",
+ "[\\u0D47\\u0D46\\u0D4a\\u0D0E\\u0D12\\u0D31\\u0D34\\u0D35]", /*roundtrip exclusions*/
+
+ "TELUGU-TAMIL", "[:TELUGU:]", "[:TAMIL:]",
+ "[\\u0bd7\\u0ba9\\u0bb4\\u0BF0\\u0BF1\\u0BF2]", /*roundtrip exclusions*/
+
+ "TAMIL-TELUGU", "[:TAMIL:]", "[:TELUGU:]",
+ "[\\u0C01\\u0c43\\u0c44\\u0c46\\u0c47\\u0c55\\u0c56\\u0c66\\u0C0B\\u0C0C\\u0C16\\u0C17\\u0C18\\u0C1B\\u0C1D\\u0C20\\u0C21\\u0C22\\u0C25\\u0C26\\u0C27\\u0C2B\\u0C2C\\u0C2D\\u0C36\\u0C60\\u0C61]", /*roundtrip exclusions*/
+
+ "KANNADA-TAMIL", "[:KANNADA:]", "[:TAMIL:]",
+ "[\\u0bd7\\u0bc6\\u0ba9\\u0bb4\\u0BF0\\u0BF1\\u0BF2]", /*roundtrip exclusions*/
+
+ "TAMIL-KANNADA", "[:TAMIL:]", "[:KANNADA:]",
+ "[\\u0cc3\\u0cc4\\u0cc6\\u0cc7\\u0cd5\\u0cd6\\u0C8B\\u0C8C\\u0C96\\u0C97\\u0C98\\u0C9B\\u0C9D\\u0CA0\\u0CA1\\u0CA2\\u0CA5\\u0CA6\\u0CA7\\u0CAB\\u0CAC\\u0CAD\\u0CB6\\u0cbc\\u0cbd\\u0CDE\\u0CE0\\u0CE1]", /*roundtrip exclusions*/
+
+ "MALAYALAM-TAMIL", "[:MALAYALAM:]", "[:TAMIL:]",
+ "[\\u0ba9\\u0BF0\\u0BF1\\u0BF2]", /*roundtrip exclusions*/
+
+ "TAMIL-MALAYALAM", "[:TAMIL:]", "[:MALAYALAM:]",
+ "[\\u0d43\\u0d12\\u0D0B\\u0D0C\\u0D16\\u0D17\\u0D18\\u0D1B\\u0D1D\\u0D20\\u0D21\\u0D22\\u0D25\\u0D26\\u0D27\\u0D2B\\u0D2C\\u0D2D\\u0D36\\u0D60\\u0D61]", /*roundtrip exclusions*/
+
+ "KANNADA-TELUGU", "[:KANNADA:]", "[:TELUGU:]",
+ "[\\u0C01\\u0c3f\\u0c46\\u0c48\\u0c4a]", /*roundtrip exclusions*/
+
+ "TELUGU-KANNADA", "[:TELUGU:]", "[:KANNADA:]",
+ "[\\u0cc8\\u0cd5\\u0cd6\\u0cbc\\u0cbd\\u0CDE]", /*roundtrip exclusions*/
+
+ "MALAYALAM-TELUGU", "[:MALAYALAM:]", "[:TELUGU:]",
+ "[\\u0C01\\u0c44\\u0c4a\\u0c4c\\u0c4b\\u0c55\\u0c56]", /*roundtrip exclusions*/
+
+ "TELUGU-MALAYALAM", "[:TELUGU:]", "[:MALAYALAM:]",
+ "[\\u0d4c\\u0d57\\u0D34]", /*roundtrip exclusions*/
+
+ "MALAYALAM-KANNADA", "[:MALAYALAM:]", "[:KANNADA:]",
+ "[\\u0cbc\\u0cbd\\u0cc4\\u0cc6\\u0cca\\u0ccc\\u0ccb\\u0cd5\\u0cd6\\u0cDe]", /*roundtrip exclusions*/
+
+ "KANNADA-MALAYALAM", "[:KANNADA:]", "[:MALAYALAM:]",
+ "[\\u0d4c\\u0d57\\u0d46\\u0D34]", /*roundtrip exclusions*/
+
+ "Latin-Bengali",latinForIndic, "[[:Bengali:][\\u0964\\u0965]]",
+ "[\\u0965\\u09f0-\\u09fa\\u09ce]" /*roundtrip exclusions*/ ,
+
+ "Latin-Gurmukhi", latinForIndic, "[[:Gurmukhi:][\\u0964\\u0965]]",
+ "[\\u0a01\\u0965\\u0a02\\u0a72\\u0a73\\u0a74]" /*roundtrip exclusions*/,
+
+ "Latin-Gujarati",latinForIndic, "[[:Gujarati:][\\u0964\\u0965]]",
+ "[\\u0965]" /*roundtrip exclusions*/,
+
+ "Latin-Oriya",latinForIndic, "[[:Oriya:][\\u0964\\u0965]]",
+ "[\\u0965\\u0b70]" /*roundtrip exclusions*/,
+
+ "Latin-Tamil",latinForIndic, "[:Tamil:]",
+ "[\\u0BF0\\u0BF1\\u0BF2]" /*roundtrip exclusions*/,
+
+ "Latin-Telugu",latinForIndic, "[:Telugu:]",
+ NULL /*roundtrip exclusions*/,
+
+ "Latin-Kannada",latinForIndic, "[:Kannada:]",
+ NULL /*roundtrip exclusions*/,
+
+ "Latin-Malayalam",latinForIndic, "[:Malayalam:]",
+ NULL /*roundtrip exclusions*/
+};
+
+void TransliteratorRoundTripTest::TestDebug(const char* name,const char fromSet[],
+ const char* toSet,const char* exclusions){
+
+ RTTest test(name);
+ Legal *legal = new LegalIndic();
+ test.test(UnicodeString(fromSet,""),UnicodeString(toSet,""),exclusions,this,quick,legal);
+}
+
+void TransliteratorRoundTripTest::TestInterIndic() {
+ //TestDebug("Latin-Gurmukhi", latinForIndic, "[:Gurmukhi:]","[\\u0965\\u0a02\\u0a72\\u0a73\\u0a74]",TRUE);
+ int32_t num = (int32_t)(sizeof(interIndicArray)/(INTER_INDIC_ARRAY_WIDTH*sizeof(char*)));
+ if(quick){
+ logln("Testing only 5 of %i. Skipping rest (use -e for exhaustive)",num);
+ num = 5;
+ }
+ if (isICUVersionAtLeast(ICU_39)) {
+ // We temporarily filter against Unicode 4.1, but we only do this
+ // before version 3.4.
+ errln("FAIL: TestInterIndic needs to be updated to remove delete the [:Age=4.1:] filter ");
+ return;
+ } else {
+ logln("Warning: TestInterIndic needs to be updated to remove delete the section marked [:Age=4.1:] filter");
+ }
+ for(int i = 0; i < num;i++){
+ RTTest test(interIndicArray[i*INTER_INDIC_ARRAY_WIDTH + 0]);
+ Legal *legal = new LegalIndic();
+ logln(UnicodeString("Stress testing ") + interIndicArray[i*INTER_INDIC_ARRAY_WIDTH + 0]);
+ /* Uncomment lines below when transliterator is fixed */
+ /*
+ test.test( interIndicArray[i*INTER_INDIC_ARRAY_WIDTH + 1],
+ interIndicArray[i*INTER_INDIC_ARRAY_WIDTH + 2],
+ interIndicArray[i*INTER_INDIC_ARRAY_WIDTH + 3], // roundtrip exclusions
+ this, quick, legal, 50);
+ */
+ /* comment lines below when transliterator is fixed */
+ // start
+ UnicodeString source("[");
+ source.append(interIndicArray[i*INTER_INDIC_ARRAY_WIDTH + 1]);
+ source.append(" & [:Age=4.1:]]");
+ UnicodeString target("[");
+ target.append(interIndicArray[i*INTER_INDIC_ARRAY_WIDTH + 2]);
+ target.append(" & [:Age=4.1:]]");
+ test.test( source,
+ target,
+ interIndicArray[i*INTER_INDIC_ARRAY_WIDTH + 3], // roundtrip exclusions
+ this, quick, legal, 50);
+ // end
+ delete legal;
+ }
+}
+
+// end indic tests ----------------------------------------------------------
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/transrt.h b/Build/source/libs/icu/icu-xetex/test/intltest/transrt.h
new file mode 100644
index 00000000000..196ad7d97b1
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/transrt.h
@@ -0,0 +1,49 @@
+/*
+**********************************************************************
+* Copyright (C) 2001-2004, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 05/23/00 aliu Creation.
+**********************************************************************
+*/
+#ifndef TRANSRT_H
+#define TRANSRT_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "intltest.h"
+
+/**
+ * @test
+ * @summary Round trip test of Transliterator
+ */
+class TransliteratorRoundTripTest : public IntlTest {
+
+ void runIndexedTest(int32_t index, UBool exec, const char* &name,
+ char* par=NULL);
+
+ void TestKana(void);
+ void TestHiragana(void);
+ void TestKatakana(void);
+ void TestJamo(void);
+ void TestHangul(void);
+ void TestHan(void);
+ void TestGreek(void);
+ void TestGreekUNGEGN(void);
+ void Testel(void);
+ void TestCyrillic(void);
+ void TestDevanagariLatin(void);
+ void TestInterIndic(void);
+ void TestHebrew(void);
+ void TestArabic(void);
+ void TestDebug(const char* name,const char fromSet[],
+ const char* toSet,const char* exclusions);
+};
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/transtst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/transtst.cpp
new file mode 100644
index 00000000000..9b9ef81a6b0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/transtst.cpp
@@ -0,0 +1,4652 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/10/99 aliu Creation.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "transtst.h"
+#include "unicode/locid.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/normlzr.h"
+#include "unicode/translit.h"
+#include "unicode/uchar.h"
+#include "unicode/unifilt.h"
+#include "unicode/uniset.h"
+#include "unicode/ustring.h"
+#include "unicode/usetiter.h"
+#include "unicode/uscript.h"
+#include "cpdtrans.h"
+#include "nultrans.h"
+#include "rbt.h"
+#include "rbt_pars.h"
+#include "anytrans.h"
+#include "esctrn.h"
+#include "name2uni.h"
+#include "nortrans.h"
+#include "remtrans.h"
+#include "titletrn.h"
+#include "tolowtrn.h"
+#include "toupptrn.h"
+#include "unesctrn.h"
+#include "uni2name.h"
+#include "cstring.h"
+#include "cmemory.h"
+#include <stdio.h>
+
+/***********************************************************************
+
+ HOW TO USE THIS TEST FILE
+ -or-
+ How I developed on two platforms
+ without losing (too much of) my mind
+
+
+1. Add new tests by copying/pasting/changing existing tests. On Java,
+ any public void method named Test...() taking no parameters becomes
+ a test. On C++, you need to modify the header and add a line to
+ the runIndexedTest() dispatch method.
+
+2. Make liberal use of the expect() method; it is your friend.
+
+3. The tests in this file exactly match those in a sister file on the
+ other side. The two files are:
+
+ icu4j: src/com/ibm/test/translit/TransliteratorTest.java
+ icu4c: source/test/intltest/transtst.cpp
+
+ ==> THIS IS THE IMPORTANT PART <==
+
+ When you add a test in this file, add it in TransliteratorTest.java
+ too. Give it the same name and put it in the same relative place.
+ This makes maintenance a lot simpler for any poor soul who ends up
+ trying to synchronize the tests between icu4j and icu4c.
+
+4. If you MUST enter a test that is NOT paralleled in the sister file,
+ then add it in the special non-mirrored section. These are
+ labeled
+
+ "icu4j ONLY"
+
+ or
+
+ "icu4c ONLY"
+
+ Make sure you document the reason the test is here and not there.
+
+
+Thank you.
+The Management
+***********************************************************************/
+
+// Define character constants thusly to be EBCDIC-friendly
+enum {
+ LEFT_BRACE=((UChar)0x007B), /*{*/
+ PIPE =((UChar)0x007C), /*|*/
+ ZERO =((UChar)0x0030), /*0*/
+ UPPER_A =((UChar)0x0041) /*A*/
+};
+
+TransliteratorTest::TransliteratorTest()
+: DESERET_DEE((UChar32)0x10414),
+ DESERET_dee((UChar32)0x1043C)
+{
+}
+
+TransliteratorTest::~TransliteratorTest() {}
+
+void
+TransliteratorTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ TESTCASE(0,TestInstantiation);
+ TESTCASE(1,TestSimpleRules);
+ TESTCASE(2,TestRuleBasedInverse);
+ TESTCASE(3,TestKeyboard);
+ TESTCASE(4,TestKeyboard2);
+ TESTCASE(5,TestKeyboard3);
+ TESTCASE(6,TestArabic);
+ TESTCASE(7,TestCompoundKana);
+ TESTCASE(8,TestCompoundHex);
+ TESTCASE(9,TestFiltering);
+ TESTCASE(10,TestInlineSet);
+ TESTCASE(11,TestPatternQuoting);
+ TESTCASE(12,TestJ277);
+ TESTCASE(13,TestJ243);
+ TESTCASE(14,TestJ329);
+ TESTCASE(15,TestSegments);
+ TESTCASE(16,TestCursorOffset);
+ TESTCASE(17,TestArbitraryVariableValues);
+ TESTCASE(18,TestPositionHandling);
+ TESTCASE(19,TestHiraganaKatakana);
+ TESTCASE(20,TestCopyJ476);
+ TESTCASE(21,TestAnchors);
+ TESTCASE(22,TestInterIndic);
+ TESTCASE(23,TestFilterIDs);
+ TESTCASE(24,TestCaseMap);
+ TESTCASE(25,TestNameMap);
+ TESTCASE(26,TestLiberalizedID);
+ TESTCASE(27,TestCreateInstance);
+ TESTCASE(28,TestNormalizationTransliterator);
+ TESTCASE(29,TestCompoundRBT);
+ TESTCASE(30,TestCompoundFilter);
+ TESTCASE(31,TestRemove);
+ TESTCASE(32,TestToRules);
+ TESTCASE(33,TestContext);
+ TESTCASE(34,TestSupplemental);
+ TESTCASE(35,TestQuantifier);
+ TESTCASE(36,TestSTV);
+ TESTCASE(37,TestCompoundInverse);
+ TESTCASE(38,TestNFDChainRBT);
+ TESTCASE(39,TestNullInverse);
+ TESTCASE(40,TestAliasInverseID);
+ TESTCASE(41,TestCompoundInverseID);
+ TESTCASE(42,TestUndefinedVariable);
+ TESTCASE(43,TestEmptyContext);
+ TESTCASE(44,TestCompoundFilterID);
+ TESTCASE(45,TestPropertySet);
+ TESTCASE(46,TestNewEngine);
+ TESTCASE(47,TestQuantifiedSegment);
+ TESTCASE(48,TestDevanagariLatinRT);
+ TESTCASE(49,TestTeluguLatinRT);
+ TESTCASE(50,TestCompoundLatinRT);
+ TESTCASE(51,TestSanskritLatinRT);
+ TESTCASE(52,TestLocaleInstantiation);
+ TESTCASE(53,TestTitleAccents);
+ TESTCASE(54,TestLocaleResource);
+ TESTCASE(55,TestParseError);
+ TESTCASE(56,TestOutputSet);
+ TESTCASE(57,TestVariableRange);
+ TESTCASE(58,TestInvalidPostContext);
+ TESTCASE(59,TestIDForms);
+ TESTCASE(60,TestToRulesMark);
+ TESTCASE(61,TestEscape);
+ TESTCASE(62,TestAnchorMasking);
+ TESTCASE(63,TestDisplayName);
+ TESTCASE(64,TestSpecialCases);
+ TESTCASE(65,TestIncrementalProgress);
+ TESTCASE(66,TestSurrogateCasing);
+ TESTCASE(67,TestFunction);
+ TESTCASE(68,TestInvalidBackRef);
+ TESTCASE(69,TestMulticharStringSet);
+ TESTCASE(70,TestUserFunction);
+ TESTCASE(71,TestAnyX);
+ TESTCASE(72,TestSourceTargetSet);
+ TESTCASE(73,TestGurmukhiDevanagari);
+ TESTCASE(74,TestRuleWhitespace);
+ TESTCASE(75,TestAllCodepoints);
+ TESTCASE(76,TestBoilerplate);
+ TESTCASE(77,TestAlternateSyntax);
+ TESTCASE(78,TestBeginEnd);
+ TESTCASE(79,TestBeginEndToRules);
+ TESTCASE(80,TestRegisterAlias);
+ TESTCASE(81,TestRuleStripping);
+ default: name = ""; break;
+ }
+}
+
+static const UVersionInfo ICU_39 = {3,9,0,0};
+/**
+ * Make sure every system transliterator can be instantiated.
+ *
+ * ALSO test that the result of toRules() for each rule is a valid
+ * rule. Do this here so we don't have to have another test that
+ * instantiates everything as well.
+ */
+void TransliteratorTest::TestInstantiation() {
+ UErrorCode ec = U_ZERO_ERROR;
+ StringEnumeration* avail = Transliterator::getAvailableIDs(ec);
+ assertSuccess("getAvailableIDs()", ec);
+ assertTrue("getAvailableIDs()!=NULL", avail!=NULL);
+ int32_t n = Transliterator::countAvailableIDs();
+ assertTrue("getAvailableIDs().count()==countAvailableIDs()",
+ avail->count(ec) == n);
+ assertSuccess("count()", ec);
+ UnicodeString name;
+ for (int32_t i=0; i<n; ++i) {
+ const UnicodeString& id = *avail->snext(ec);
+ if (!assertSuccess("snext()", ec) ||
+ !assertTrue("snext()!=NULL", (&id)!=NULL, TRUE)) {
+ break;
+ }
+ UnicodeString id2 = Transliterator::getAvailableID(i);
+ if (id.length() < 1) {
+ errln(UnicodeString("FAIL: getAvailableID(") +
+ i + ") returned empty string");
+ continue;
+ }
+ if (id != id2) {
+ errln(UnicodeString("FAIL: getAvailableID(") +
+ i + ") != getAvailableIDs().snext()");
+ continue;
+ }
+ if(id2.indexOf("Thai")>-1 && !isICUVersionAtLeast(ICU_39)){
+ /* The Thai-Latin transliterator doesn't exist in ICU4C yet */
+ continue;
+ }
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* t = Transliterator::createInstance(id,
+ UTRANS_FORWARD, parseError,status);
+ name.truncate(0);
+ Transliterator::getDisplayName(id, name);
+ if (t == 0) {
+ errln(UnicodeString("FAIL: Couldn't create ") + id +
+ /*", parse error " + parseError.code +*/
+ ", line " + parseError.line +
+ ", offset " + parseError.offset +
+ ", pre-context " + prettify(parseError.preContext, TRUE) +
+ ", post-context " +prettify(parseError.postContext,TRUE) +
+ ", Error: " + u_errorName(status));
+ // When createInstance fails, it deletes the failing
+ // entry from the available ID list. We detect this
+ // here by looking for a change in countAvailableIDs.
+ int32_t nn = Transliterator::countAvailableIDs();
+ if (nn == (n - 1)) {
+ n = nn;
+ --i; // Compensate for deleted entry
+ }
+ } else {
+ logln(UnicodeString("OK: ") + name + " (" + id + ")");
+
+ // Now test toRules
+ UnicodeString rules;
+ t->toRules(rules, TRUE);
+ Transliterator *u = Transliterator::createFromRules("x",
+ rules, UTRANS_FORWARD, parseError,status);
+ if (u == 0) {
+ errln(UnicodeString("FAIL: ") + id +
+ ".createFromRules() => bad rules" +
+ /*", parse error " + parseError.code +*/
+ ", line " + parseError.line +
+ ", offset " + parseError.offset +
+ ", context " + prettify(parseError.preContext, TRUE) +
+ ", rules: " + prettify(rules, TRUE));
+ } else {
+ delete u;
+ }
+ delete t;
+ }
+ }
+ assertTrue("snext()==NULL", avail->snext(ec)==NULL);
+ assertSuccess("snext()", ec);
+ delete avail;
+
+ // Now test the failure path
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString id("<Not a valid Transliterator ID>");
+ Transliterator* t = Transliterator::createInstance(id, UTRANS_FORWARD, parseError, status);
+ if (t != 0) {
+ errln("FAIL: " + id + " returned a transliterator");
+ delete t;
+ } else {
+ logln("OK: Bogus ID handled properly");
+ }
+}
+
+void TransliteratorTest::TestSimpleRules(void) {
+ /* Example: rules 1. ab>x|y
+ * 2. yc>z
+ *
+ * []|eabcd start - no match, copy e to tranlated buffer
+ * [e]|abcd match rule 1 - copy output & adjust cursor
+ * [ex|y]cd match rule 2 - copy output & adjust cursor
+ * [exz]|d no match, copy d to transliterated buffer
+ * [exzd]| done
+ */
+ expect(UnicodeString("ab>x|y;", "") +
+ "yc>z",
+ "eabcd", "exzd");
+
+ /* Another set of rules:
+ * 1. ab>x|yzacw
+ * 2. za>q
+ * 3. qc>r
+ * 4. cw>n
+ *
+ * []|ab Rule 1
+ * [x|yzacw] No match
+ * [xy|zacw] Rule 2
+ * [xyq|cw] Rule 4
+ * [xyqn]| Done
+ */
+ expect(UnicodeString("ab>x|yzacw;") +
+ "za>q;" +
+ "qc>r;" +
+ "cw>n",
+ "ab", "xyqn");
+
+ /* Test categories
+ */
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator *t = Transliterator::createFromRules(
+ "<ID>",
+ UnicodeString("$dummy=").append((UChar)0xE100) +
+ UnicodeString(";"
+ "$vowel=[aeiouAEIOU];"
+ "$lu=[:Lu:];"
+ "$vowel } $lu > '!';"
+ "$vowel > '&';"
+ "'!' { $lu > '^';"
+ "$lu > '*';"
+ "a > ERROR", ""),
+ UTRANS_FORWARD, parseError,
+ status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: RBT constructor failed");
+ return;
+ }
+ expect(*t, "abcdefgABCDEFGU", "&bcd&fg!^**!^*&");
+ delete t;
+}
+
+/**
+ * Test inline set syntax and set variable syntax.
+ */
+void TransliteratorTest::TestInlineSet(void) {
+ expect("{ [:Ll:] } x > y; [:Ll:] > z;", "aAbxq", "zAyzz");
+ expect("a[0-9]b > qrs", "1a7b9", "1qrs9");
+
+ expect(UnicodeString(
+ "$digit = [0-9];"
+ "$alpha = [a-zA-Z];"
+ "$alphanumeric = [$digit $alpha];" // ***
+ "$special = [^$alphanumeric];" // ***
+ "$alphanumeric > '-';"
+ "$special > '*';", ""),
+
+ "thx-1138", "---*----");
+}
+
+/**
+ * Create some inverses and confirm that they work. We have to be
+ * careful how we do this, since the inverses will not be true
+ * inverses -- we can't throw any random string at the composition
+ * of the transliterators and expect the identity function. F x
+ * F' != I. However, if we are careful about the input, we will
+ * get the expected results.
+ */
+void TransliteratorTest::TestRuleBasedInverse(void) {
+ UnicodeString RULES =
+ UnicodeString("abc>zyx;") +
+ "ab>yz;" +
+ "bc>zx;" +
+ "ca>xy;" +
+ "a>x;" +
+ "b>y;" +
+ "c>z;" +
+
+ "abc<zyx;" +
+ "ab<yz;" +
+ "bc<zx;" +
+ "ca<xy;" +
+ "a<x;" +
+ "b<y;" +
+ "c<z;" +
+
+ "";
+
+ const char* DATA[] = {
+ // Careful here -- random strings will not work. If we keep
+ // the left side to the domain and the right side to the range
+ // we will be okay though (left, abc; right xyz).
+ "a", "x",
+ "abcacab", "zyxxxyy",
+ "caccb", "xyzzy",
+ };
+
+ int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator *fwd = Transliterator::createFromRules("<ID>", RULES,
+ UTRANS_FORWARD, parseError, status);
+ Transliterator *rev = Transliterator::createFromRules("<ID>", RULES,
+ UTRANS_REVERSE, parseError, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: RBT constructor failed");
+ return;
+ }
+ for (int32_t i=0; i<DATA_length; i+=2) {
+ expect(*fwd, DATA[i], DATA[i+1]);
+ expect(*rev, DATA[i+1], DATA[i]);
+ }
+ delete fwd;
+ delete rev;
+}
+
+/**
+ * Basic test of keyboard.
+ */
+void TransliteratorTest::TestKeyboard(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("<ID>",
+ UnicodeString("psch>Y;")
+ +"ps>y;"
+ +"ch>x;"
+ +"a>A;",
+ UTRANS_FORWARD, parseError,
+ status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: RBT constructor failed");
+ return;
+ }
+ const char* DATA[] = {
+ // insertion, buffer
+ "a", "A",
+ "p", "Ap",
+ "s", "Aps",
+ "c", "Apsc",
+ "a", "AycA",
+ "psch", "AycAY",
+ 0, "AycAY", // null means finishKeyboardTransliteration
+ };
+
+ keyboardAux(*t, DATA, (int32_t)(sizeof(DATA)/sizeof(DATA[0])));
+ delete t;
+}
+
+/**
+ * Basic test of keyboard with cursor.
+ */
+void TransliteratorTest::TestKeyboard2(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("<ID>",
+ UnicodeString("ych>Y;")
+ +"ps>|y;"
+ +"ch>x;"
+ +"a>A;",
+ UTRANS_FORWARD, parseError,
+ status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: RBT constructor failed");
+ return;
+ }
+ const char* DATA[] = {
+ // insertion, buffer
+ "a", "A",
+ "p", "Ap",
+ "s", "Aps", // modified for rollback - "Ay",
+ "c", "Apsc", // modified for rollback - "Ayc",
+ "a", "AycA",
+ "p", "AycAp",
+ "s", "AycAps", // modified for rollback - "AycAy",
+ "c", "AycApsc", // modified for rollback - "AycAyc",
+ "h", "AycAY",
+ 0, "AycAY", // null means finishKeyboardTransliteration
+ };
+
+ keyboardAux(*t, DATA, (int32_t)(sizeof(DATA)/sizeof(DATA[0])));
+ delete t;
+}
+
+/**
+ * Test keyboard transliteration with back-replacement.
+ */
+void TransliteratorTest::TestKeyboard3(void) {
+ // We want th>z but t>y. Furthermore, during keyboard
+ // transliteration we want t>y then yh>z if t, then h are
+ // typed.
+ UnicodeString RULES("t>|y;"
+ "yh>z;");
+
+ const char* DATA[] = {
+ // Column 1: characters to add to buffer (as if typed)
+ // Column 2: expected appearance of buffer after
+ // keyboard xliteration.
+ "a", "a",
+ "b", "ab",
+ "t", "abt", // modified for rollback - "aby",
+ "c", "abyc",
+ "t", "abyct", // modified for rollback - "abycy",
+ "h", "abycz",
+ 0, "abycz", // null means finishKeyboardTransliteration
+ };
+
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("<ID>", RULES, UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: RBT constructor failed");
+ return;
+ }
+ keyboardAux(*t, DATA, (int32_t)(sizeof(DATA)/sizeof(DATA[0])));
+ delete t;
+}
+
+void TransliteratorTest::keyboardAux(const Transliterator& t,
+ const char* DATA[], int32_t DATA_length) {
+ UErrorCode status = U_ZERO_ERROR;
+ UTransPosition index={0, 0, 0, 0};
+ UnicodeString s;
+ for (int32_t i=0; i<DATA_length; i+=2) {
+ UnicodeString log;
+ if (DATA[i] != 0) {
+ log = s + " + "
+ + DATA[i]
+ + " -> ";
+ t.transliterate(s, index, DATA[i], status);
+ } else {
+ log = s + " => ";
+ t.finishTransliteration(s, index);
+ }
+ // Show the start index '{' and the cursor '|'
+ UnicodeString a, b, c;
+ s.extractBetween(0, index.contextStart, a);
+ s.extractBetween(index.contextStart, index.start, b);
+ s.extractBetween(index.start, s.length(), c);
+ log.append(a).
+ append((UChar)LEFT_BRACE).
+ append(b).
+ append((UChar)PIPE).
+ append(c);
+ if (s == DATA[i+1] && U_SUCCESS(status)) {
+ logln(log);
+ } else {
+ errln(UnicodeString("FAIL: ") + log + ", expected " + DATA[i+1]);
+ }
+ }
+}
+
+void TransliteratorTest::TestArabic(void) {
+// Test disabled for 2.0 until new Arabic transliterator can be written.
+// /*
+// const char* DATA[] = {
+// "Arabic", "\u062a\u062a\u0645\u062a\u0639\u0020"+
+// "\u0627\u0644\u0644\u063a\u0629\u0020"+
+// "\u0627\u0644\u0639\u0631\u0628\u0628\u064a\u0629\u0020"+
+// "\u0628\u0628\u0646\u0638\u0645\u0020"+
+// "\u0643\u062a\u0627\u0628\u0628\u064a\u0629\u0020"+
+// "\u062c\u0645\u064a\u0644\u0629",
+// };
+// */
+//
+// UChar ar_raw[] = {
+// 0x062a, 0x062a, 0x0645, 0x062a, 0x0639, 0x0020, 0x0627,
+// 0x0644, 0x0644, 0x063a, 0x0629, 0x0020, 0x0627, 0x0644,
+// 0x0639, 0x0631, 0x0628, 0x0628, 0x064a, 0x0629, 0x0020,
+// 0x0628, 0x0628, 0x0646, 0x0638, 0x0645, 0x0020, 0x0643,
+// 0x062a, 0x0627, 0x0628, 0x0628, 0x064a, 0x0629, 0x0020,
+// 0x062c, 0x0645, 0x064a, 0x0644, 0x0629, 0
+// };
+// UnicodeString ar(ar_raw);
+// UErrorCode status=U_ZERO_ERROR;
+// UParseError parseError;
+// Transliterator *t = Transliterator::createInstance("Latin-Arabic", UTRANS_FORWARD, parseError, status);
+// if (t == 0) {
+// errln("FAIL: createInstance failed");
+// return;
+// }
+// expect(*t, "Arabic", ar);
+// delete t;
+}
+
+/**
+ * Compose the Kana transliterator forward and reverse and try
+ * some strings that should come out unchanged.
+ */
+void TransliteratorTest::TestCompoundKana(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* t = Transliterator::createInstance("Latin-Hiragana;Hiragana-Latin", UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln("FAIL: construction of Latin-Hiragana;Hiragana-Latin failed");
+ } else {
+ expect(*t, "aaaaa", "aaaaa");
+ delete t;
+ }
+}
+
+/**
+ * Compose the hex transliterators forward and reverse.
+ */
+void TransliteratorTest::TestCompoundHex(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* a = Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
+ Transliterator* b = Transliterator::createInstance("Hex-Any", UTRANS_FORWARD, parseError, status);
+ Transliterator* transab[] = { a, b };
+ Transliterator* transba[] = { b, a };
+ if (a == 0 || b == 0) {
+ errln("FAIL: construction failed");
+ delete a;
+ delete b;
+ return;
+ }
+ // Do some basic tests of a
+ expect(*a, "01", UnicodeString("\\u0030\\u0031", ""));
+ // Do some basic tests of b
+ expect(*b, UnicodeString("\\u0030\\u0031", ""), "01");
+
+ Transliterator* ab = new CompoundTransliterator(transab, 2);
+ UnicodeString s("abcde", "");
+ expect(*ab, s, s);
+
+ UnicodeString str(s);
+ a->transliterate(str);
+ Transliterator* ba = new CompoundTransliterator(transba, 2);
+ expect(*ba, str, str);
+
+ delete ab;
+ delete ba;
+ delete a;
+ delete b;
+}
+
+int gTestFilterClassID = 0;
+/**
+ * Used by TestFiltering().
+ */
+class TestFilter : public UnicodeFilter {
+ virtual UnicodeFunctor* clone() const {
+ return new TestFilter(*this);
+ }
+ virtual UBool contains(UChar32 c) const {
+ return c != (UChar)0x0063 /*c*/;
+ }
+ // Stubs
+ virtual UnicodeString& toPattern(UnicodeString& result,
+ UBool /*escapeUnprintable*/) const {
+ return result;
+ }
+ virtual UBool matchesIndexValue(uint8_t /*v*/) const {
+ return FALSE;
+ }
+ virtual void addMatchSetTo(UnicodeSet& /*toUnionTo*/) const {}
+public:
+ UClassID getDynamicClassID() const { return (UClassID)&gTestFilterClassID; }
+};
+
+/**
+ * Do some basic tests of filtering.
+ */
+void TransliteratorTest::TestFiltering(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* hex = Transliterator::createInstance("Any-Hex", UTRANS_FORWARD, parseError, status);
+ if (hex == 0) {
+ errln("FAIL: createInstance(Any-Hex) failed");
+ return;
+ }
+ hex->adoptFilter(new TestFilter());
+ UnicodeString s("abcde");
+ hex->transliterate(s);
+ UnicodeString exp("\\u0061\\u0062c\\u0064\\u0065", "");
+ if (s == exp) {
+ logln(UnicodeString("Ok: \"") + exp + "\"");
+ } else {
+ logln(UnicodeString("FAIL: \"") + s + "\", wanted \"" + exp + "\"");
+ }
+
+ // ICU4C ONLY. Do not find Transliterator.orphanFilter() in ICU4J.
+ UnicodeFilter *f = hex->orphanFilter();
+ if (f == NULL){
+ errln("FAIL: orphanFilter() should get a UnicodeFilter");
+ } else {
+ delete f;
+ }
+ delete hex;
+}
+
+/**
+ * Test anchors
+ */
+void TransliteratorTest::TestAnchors(void) {
+ expect(UnicodeString("^a > 0; a$ > 2 ; a > 1;", ""),
+ "aaa",
+ "012");
+ expect(UnicodeString("$s=[z$]; $s{a>0; a}$s>2; a>1;", ""),
+ "aaa",
+ "012");
+ expect(UnicodeString("^ab > 01 ;"
+ " ab > |8 ;"
+ " b > k ;"
+ " 8x$ > 45 ;"
+ " 8x > 77 ;", ""),
+
+ "ababbabxabx",
+ "018k7745");
+ expect(UnicodeString("$s = [z$] ;"
+ "$s{ab > 01 ;"
+ " ab > |8 ;"
+ " b > k ;"
+ " 8x}$s > 45 ;"
+ " 8x > 77 ;", ""),
+
+ "abzababbabxzabxabx",
+ "01z018k45z01x45");
+}
+
+/**
+ * Test pattern quoting and escape mechanisms.
+ */
+void TransliteratorTest::TestPatternQuoting(void) {
+ // Array of 3n items
+ // Each item is <rules>, <input>, <expected output>
+ const UnicodeString DATA[] = {
+ UnicodeString(UChar(0x4E01)) + ">'[male adult]'",
+ UnicodeString(UChar(0x4E01)),
+ "[male adult]"
+ };
+
+ for (int32_t i=0; i<3; i+=3) {
+ logln(UnicodeString("Pattern: ") + prettify(DATA[i]));
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("<ID>", DATA[i], UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ errln("RBT constructor failed");
+ } else {
+ expect(*t, DATA[i+1], DATA[i+2]);
+ }
+ delete t;
+ }
+}
+
+/**
+ * Regression test for bugs found in Greek transliteration.
+ */
+void TransliteratorTest::TestJ277(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator *gl = Transliterator::createInstance("Greek-Latin; NFD; [:M:]Remove; NFC", UTRANS_FORWARD, parseError, status);
+ if (gl == NULL) {
+ errln("FAIL: createInstance(Greek-Latin) returned NULL");
+ return;
+ }
+
+ UChar sigma = 0x3C3;
+ UChar upsilon = 0x3C5;
+ UChar nu = 0x3BD;
+// UChar PHI = 0x3A6;
+ UChar alpha = 0x3B1;
+// UChar omega = 0x3C9;
+// UChar omicron = 0x3BF;
+// UChar epsilon = 0x3B5;
+
+ // sigma upsilon nu -> syn
+ UnicodeString syn;
+ syn.append(sigma).append(upsilon).append(nu);
+ expect(*gl, syn, "syn");
+
+ // sigma alpha upsilon nu -> saun
+ UnicodeString sayn;
+ sayn.append(sigma).append(alpha).append(upsilon).append(nu);
+ expect(*gl, sayn, "saun");
+
+ // Again, using a smaller rule set
+ UnicodeString rules(
+ "$alpha = \\u03B1;"
+ "$nu = \\u03BD;"
+ "$sigma = \\u03C3;"
+ "$ypsilon = \\u03C5;"
+ "$vowel = [aeiouAEIOU$alpha$ypsilon];"
+ "s <> $sigma;"
+ "a <> $alpha;"
+ "u <> $vowel { $ypsilon;"
+ "y <> $ypsilon;"
+ "n <> $nu;",
+ "");
+ Transliterator *mini = Transliterator::createFromRules("mini", rules, UTRANS_REVERSE, parseError, status);
+ if (U_FAILURE(status)) { errln("FAIL: Transliterator constructor failed"); return; }
+ expect(*mini, syn, "syn");
+ expect(*mini, sayn, "saun");
+ delete mini;
+ mini = NULL;
+
+#if !UCONFIG_NO_FORMATTING
+ // Transliterate the Greek locale data
+ Locale el("el");
+ DateFormatSymbols syms(el, status);
+ if (U_FAILURE(status)) { errln("FAIL: Transliterator constructor failed"); return; }
+ int32_t i, count;
+ const UnicodeString* data = syms.getMonths(count);
+ for (i=0; i<count; ++i) {
+ if (data[i].length() == 0) {
+ continue;
+ }
+ UnicodeString out(data[i]);
+ gl->transliterate(out);
+ UBool ok = TRUE;
+ if (data[i].length() >= 2 && out.length() >= 2 &&
+ u_isupper(data[i].charAt(0)) && u_islower(data[i].charAt(1))) {
+ if (!(u_isupper(out.charAt(0)) && u_islower(out.charAt(1)))) {
+ ok = FALSE;
+ }
+ }
+ if (ok) {
+ logln(prettify(data[i] + " -> " + out));
+ } else {
+ errln(UnicodeString("FAIL: ") + prettify(data[i] + " -> " + out));
+ }
+ }
+#endif
+
+ delete gl;
+}
+
+/**
+ * Prefix, suffix support in hex transliterators
+ */
+void TransliteratorTest::TestJ243(void) {
+ UErrorCode ec = U_ZERO_ERROR;
+
+ // Test default Hex-Any, which should handle
+ // \u, \U, u+, and U+
+ Transliterator *hex =
+ Transliterator::createInstance("Hex-Any", UTRANS_FORWARD, ec);
+ if (assertSuccess("getInstance", ec)) {
+ expect(*hex, UnicodeString("\\u0041+\\U00000042,U+0043uU+0044z", ""), "A+B,CuDz");
+ }
+ delete hex;
+
+// // Try a custom Hex-Unicode
+// // \uXXXX and &#xXXXX;
+// ec = U_ZERO_ERROR;
+// HexToUnicodeTransliterator hex2(UnicodeString("\\\\u###0;&\\#x###0\\;", ""), ec);
+// expect(hex2, UnicodeString("\\u61\\u062\\u0063\\u00645\\u66x&#x30;&#x031;&#x0032;&#x00033;", ""),
+// "abcd5fx012&#x00033;");
+// // Try custom Any-Hex (default is tested elsewhere)
+// ec = U_ZERO_ERROR;
+// UnicodeToHexTransliterator hex3(UnicodeString("&\\#x###0;", ""), ec);
+// expect(hex3, "012", "&#x30;&#x31;&#x32;");
+}
+
+/**
+ * Parsers need better syntax error messages.
+ */
+void TransliteratorTest::TestJ329(void) {
+
+ struct { UBool containsErrors; const char* rule; } DATA[] = {
+ { FALSE, "a > b; c > d" },
+ { TRUE, "a > b; no operator; c > d" },
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+
+ for (int32_t i=0; i<DATA_length; ++i) {
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator *rbt = Transliterator::createFromRules("<ID>",
+ DATA[i].rule,
+ UTRANS_FORWARD,
+ parseError,
+ status);
+ UBool gotError = U_FAILURE(status);
+ UnicodeString desc(DATA[i].rule);
+ desc.append(gotError ? " -> error" : " -> no error");
+ if (gotError) {
+ desc = desc + ", ParseError code=" + u_errorName(status) +
+ " line=" + parseError.line +
+ " offset=" + parseError.offset +
+ " context=" + parseError.preContext;
+ }
+ if (gotError == DATA[i].containsErrors) {
+ logln(UnicodeString("Ok: ") + desc);
+ } else {
+ errln(UnicodeString("FAIL: ") + desc);
+ }
+ delete rbt;
+ }
+}
+
+/**
+ * Test segments and segment references.
+ */
+void TransliteratorTest::TestSegments(void) {
+ // Array of 3n items
+ // Each item is <rules>, <input>, <expected output>
+ UnicodeString DATA[] = {
+ "([a-z]) '.' ([0-9]) > $2 '-' $1",
+ "abc.123.xyz.456",
+ "ab1-c23.xy4-z56",
+
+ // nested
+ "(([a-z])([0-9])) > $1 '.' $2 '.' $3;",
+ "a1 b2",
+ "a1.a.1 b2.b.2",
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA)/sizeof(*DATA));
+
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ logln("Pattern: " + prettify(DATA[i]));
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("ID", DATA[i], UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: RBT constructor");
+ } else {
+ expect(*t, DATA[i+1], DATA[i+2]);
+ }
+ delete t;
+ }
+}
+
+/**
+ * Test cursor positioning outside of the key
+ */
+void TransliteratorTest::TestCursorOffset(void) {
+ // Array of 3n items
+ // Each item is <rules>, <input>, <expected output>
+ UnicodeString DATA[] = {
+ "pre {alpha} post > | @ ALPHA ;"
+ "eALPHA > beta ;"
+ "pre {beta} post > BETA @@ | ;"
+ "post > xyz",
+
+ "prealphapost prebetapost",
+
+ "prbetaxyz preBETApost",
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA)/sizeof(*DATA));
+
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ logln("Pattern: " + prettify(DATA[i]));
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("<ID>", DATA[i], UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: RBT constructor");
+ } else {
+ expect(*t, DATA[i+1], DATA[i+2]);
+ }
+ delete t;
+ }
+}
+
+/**
+ * Test zero length and > 1 char length variable values. Test
+ * use of variable refs in UnicodeSets.
+ */
+void TransliteratorTest::TestArbitraryVariableValues(void) {
+ // Array of 3n items
+ // Each item is <rules>, <input>, <expected output>
+ UnicodeString DATA[] = {
+ "$abe = ab;"
+ "$pat = x[yY]z;"
+ "$ll = 'a-z';"
+ "$llZ = [$ll];"
+ "$llY = [$ll$pat];"
+ "$emp = ;"
+
+ "$abe > ABE;"
+ "$pat > END;"
+ "$llZ > 1;"
+ "$llY > 2;"
+ "7$emp 8 > 9;"
+ "",
+
+ "ab xYzxyz stY78",
+ "ABE ENDEND 1129",
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA)/sizeof(*DATA));
+
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ logln("Pattern: " + prettify(DATA[i]));
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("<ID>", DATA[i], UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: RBT constructor");
+ } else {
+ expect(*t, DATA[i+1], DATA[i+2]);
+ }
+ delete t;
+ }
+}
+
+/**
+ * Confirm that the contextStart, contextLimit, start, and limit
+ * behave correctly. J474.
+ */
+void TransliteratorTest::TestPositionHandling(void) {
+ // Array of 3n items
+ // Each item is <rules>, <input>, <expected output>
+ const char* DATA[] = {
+ "a{t} > SS ; {t}b > UU ; {t} > TT ;",
+ "xtat txtb", // pos 0,9,0,9
+ "xTTaSS TTxUUb",
+
+ "a{t} > SS ; {t}b > UU ; {t} > TT ; a > A ; b > B ;",
+ "xtat txtb", // pos 2,9,3,8
+ "xtaSS TTxUUb",
+
+ "a{t} > SS ; {t}b > UU ; {t} > TT ; a > A ; b > B ;",
+ "xtat txtb", // pos 3,8,3,8
+ "xtaTT TTxTTb",
+ };
+
+ // Array of 4n positions -- these go with the DATA array
+ // They are: contextStart, contextLimit, start, limit
+ int32_t POS[] = {
+ 0, 9, 0, 9,
+ 2, 9, 3, 8,
+ 3, 8, 3, 8,
+ };
+
+ int32_t n = (int32_t)(sizeof(DATA) / sizeof(DATA[0])) / 3;
+ for (int32_t i=0; i<n; i++) {
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator *t = Transliterator::createFromRules("<ID>",
+ DATA[3*i], UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ delete t;
+ errln("FAIL: RBT constructor");
+ return;
+ }
+ UTransPosition pos;
+ pos.contextStart= POS[4*i];
+ pos.contextLimit = POS[4*i+1];
+ pos.start = POS[4*i+2];
+ pos.limit = POS[4*i+3];
+ UnicodeString rsource(DATA[3*i+1]);
+ t->transliterate(rsource, pos, status);
+ if (U_FAILURE(status)) {
+ delete t;
+ errln("FAIL: transliterate");
+ return;
+ }
+ t->finishTransliteration(rsource, pos);
+ expectAux(DATA[3*i],
+ DATA[3*i+1],
+ rsource,
+ DATA[3*i+2]);
+ delete t;
+ }
+}
+
+/**
+ * Test the Hiragana-Katakana transliterator.
+ */
+void TransliteratorTest::TestHiraganaKatakana(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* hk = Transliterator::createInstance("Hiragana-Katakana", UTRANS_FORWARD, parseError, status);
+ Transliterator* kh = Transliterator::createInstance("Katakana-Hiragana", UTRANS_FORWARD, parseError, status);
+ if (hk == 0 || kh == 0) {
+ errln("FAIL: createInstance failed");
+ delete hk;
+ delete kh;
+ return;
+ }
+
+ // Array of 3n items
+ // Each item is "hk"|"kh"|"both", <Hiragana>, <Katakana>
+ const char* DATA[] = {
+ "both",
+ "\\u3042\\u3090\\u3099\\u3092\\u3050",
+ "\\u30A2\\u30F8\\u30F2\\u30B0",
+
+ "kh",
+ "\\u307C\\u3051\\u3060\\u3042\\u3093\\u30FC",
+ "\\u30DC\\u30F6\\u30C0\\u30FC\\u30F3\\u30FC",
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ UnicodeString h = CharsToUnicodeString(DATA[i+1]);
+ UnicodeString k = CharsToUnicodeString(DATA[i+2]);
+ switch (*DATA[i]) {
+ case 0x68: //'h': // Hiragana-Katakana
+ expect(*hk, h, k);
+ break;
+ case 0x6B: //'k': // Katakana-Hiragana
+ expect(*kh, k, h);
+ break;
+ case 0x62: //'b': // both
+ expect(*hk, h, k);
+ expect(*kh, k, h);
+ break;
+ }
+ }
+ delete hk;
+ delete kh;
+}
+
+/**
+ * Test cloning / copy constructor of RBT.
+ */
+void TransliteratorTest::TestCopyJ476(void) {
+ // The real test here is what happens when the destructors are
+ // called. So we let one object get destructed, and check to
+ // see that its copy still works.
+ Transliterator *t2 = 0;
+ {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t1 = Transliterator::createFromRules("t1",
+ "a>A;b>B;'foo'+>'bar'", UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: RBT constructor");
+ return;
+ }
+ t2 = t1->clone(); // Call copy constructor under the covers.
+ expect(*t1, "abcfoofoo", "ABcbar");
+ delete t1;
+ }
+ expect(*t2, "abcfoofoo", "ABcbar");
+ delete t2;
+}
+
+/**
+ * Test inter-Indic transliterators. These are composed.
+ * ICU4C Jitterbug 483.
+ */
+void TransliteratorTest::TestInterIndic(void) {
+ UnicodeString ID("Devanagari-Gujarati", "");
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator* dg = Transliterator::createInstance(ID, UTRANS_FORWARD, parseError, status);
+ if (dg == 0) {
+ errln("FAIL: createInstance(" + ID + ") returned NULL");
+ return;
+ }
+ UnicodeString id = dg->getID();
+ if (id != ID) {
+ errln("FAIL: createInstance(" + ID + ")->getID() => " + id);
+ }
+ UnicodeString dev = CharsToUnicodeString("\\u0901\\u090B\\u0925");
+ UnicodeString guj = CharsToUnicodeString("\\u0A81\\u0A8B\\u0AA5");
+ expect(*dg, dev, guj);
+ delete dg;
+}
+
+/**
+ * Test filter syntax in IDs. (J918)
+ */
+void TransliteratorTest::TestFilterIDs(void) {
+ // Array of 3n strings:
+ // <id>, <inverse id>, <input>, <expected output>
+ const char* DATA[] = {
+ "[aeiou]Any-Hex", // ID
+ "[aeiou]Hex-Any", // expected inverse ID
+ "quizzical", // src
+ "q\\u0075\\u0069zz\\u0069c\\u0061l", // expected ID.translit(src)
+
+ "[aeiou]Any-Hex;[^5]Hex-Any",
+ "[^5]Any-Hex;[aeiou]Hex-Any",
+ "quizzical",
+ "q\\u0075izzical",
+
+ "[abc]Null",
+ "[abc]Null",
+ "xyz",
+ "xyz",
+ };
+ enum { DATA_length = sizeof(DATA) / sizeof(DATA[0]) };
+
+ for (int i=0; i<DATA_length; i+=4) {
+ UnicodeString ID(DATA[i], "");
+ UnicodeString uID(DATA[i+1], "");
+ UnicodeString data2(DATA[i+2], "");
+ UnicodeString data3(DATA[i+3], "");
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance(ID, UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln("FAIL: createInstance(" + ID + ") returned NULL");
+ return;
+ }
+ expect(*t, data2, data3);
+
+ // Check the ID
+ if (ID != t->getID()) {
+ errln("FAIL: createInstance(" + ID + ").getID() => " +
+ t->getID());
+ }
+
+ // Check the inverse
+ Transliterator *u = t->createInverse(status);
+ if (u == 0) {
+ errln("FAIL: " + ID + ".createInverse() returned NULL");
+ } else if (u->getID() != uID) {
+ errln("FAIL: " + ID + ".createInverse().getID() => " +
+ u->getID() + ", expected " + uID);
+ }
+
+ delete t;
+ delete u;
+ }
+}
+
+/**
+ * Test the case mapping transliterators.
+ */
+void TransliteratorTest::TestCaseMap(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* toUpper =
+ Transliterator::createInstance("Any-Upper[^xyzXYZ]", UTRANS_FORWARD, parseError, status);
+ Transliterator* toLower =
+ Transliterator::createInstance("Any-Lower[^xyzXYZ]", UTRANS_FORWARD, parseError, status);
+ Transliterator* toTitle =
+ Transliterator::createInstance("Any-Title[^xyzXYZ]", UTRANS_FORWARD, parseError, status);
+ if (toUpper==0 || toLower==0 || toTitle==0) {
+ errln("FAIL: createInstance returned NULL");
+ delete toUpper;
+ delete toLower;
+ delete toTitle;
+ return;
+ }
+
+ expect(*toUpper, "The quick brown fox jumped over the lazy dogs.",
+ "THE QUICK BROWN FOx JUMPED OVER THE LAzy DOGS.");
+ expect(*toLower, "The quIck brown fOX jUMPED OVER THE LAzY dogs.",
+ "the quick brown foX jumped over the lazY dogs.");
+ expect(*toTitle, "the quick brown foX can't jump over the laZy dogs.",
+ "The Quick Brown FoX Can't Jump Over The LaZy Dogs.");
+
+ delete toUpper;
+ delete toLower;
+ delete toTitle;
+}
+
+/**
+ * Test the name mapping transliterators.
+ */
+void TransliteratorTest::TestNameMap(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* uni2name =
+ Transliterator::createInstance("Any-Name[^abc]", UTRANS_FORWARD, parseError, status);
+ Transliterator* name2uni =
+ Transliterator::createInstance("Name-Any", UTRANS_FORWARD, parseError, status);
+ if (uni2name==0 || name2uni==0) {
+ errln("FAIL: createInstance returned NULL");
+ delete uni2name;
+ delete name2uni;
+ return;
+ }
+
+ // Careful: CharsToUS will convert "\\N" => "N"; use "\\\\N" for \N
+ expect(*uni2name, CharsToUnicodeString("\\u00A0abc\\u4E01\\u00B5\\u0A81\\uFFFD\\u0004\\u0009\\u0081\\uFFFF"),
+ CharsToUnicodeString("\\\\N{NO-BREAK SPACE}abc\\\\N{CJK UNIFIED IDEOGRAPH-4E01}\\\\N{MICRO SIGN}\\\\N{GUJARATI SIGN CANDRABINDU}\\\\N{REPLACEMENT CHARACTER}\\\\N{END OF TRANSMISSION}\\\\N{CHARACTER TABULATION}\\\\N{<control-0081>}\\\\N{<noncharacter-FFFF>}"));
+ expect(*name2uni, "{\\N { NO-BREAK SPACE}abc\\N{ CJK UNIFIED IDEOGRAPH-4E01 }\\N{x\\N{MICRO SIGN}\\N{GUJARATI SIGN CANDRABINDU}\\N{REPLACEMENT CHARACTER}\\N{END OF TRANSMISSION}\\N{CHARACTER TABULATION}\\N{<control-0081>}\\N{<noncharacter-FFFF>}\\N{<control-0004>}\\N{",
+ CharsToUnicodeString("{\\u00A0abc\\u4E01\\\\N{x\\u00B5\\u0A81\\uFFFD\\u0004\\u0009\\u0081\\uFFFF\\u0004\\\\N{"));
+
+ delete uni2name;
+ delete name2uni;
+
+ // round trip
+ Transliterator* t =
+ Transliterator::createInstance("Any-Name;Name-Any", UTRANS_FORWARD, parseError, status);
+ if (t==0) {
+ errln("FAIL: createInstance returned NULL");
+ delete t;
+ return;
+ }
+
+ // Careful: CharsToUS will convert "\\N" => "N"; use "\\\\N" for \N
+ UnicodeString s = CharsToUnicodeString("{\\u00A0abc\\u4E01\\\\N{x\\u00B5\\u0A81\\uFFFD\\u0004\\u0009\\u0081\\uFFFF\\u0004\\\\N{");
+ expect(*t, s, s);
+ delete t;
+}
+
+/**
+ * Test liberalized ID syntax. 1006c
+ */
+void TransliteratorTest::TestLiberalizedID(void) {
+ // Some test cases have an expected getID() value of NULL. This
+ // means I have disabled the test case for now. This stuff is
+ // still under development, and I haven't decided whether to make
+ // getID() return canonical case yet. It will all get rewritten
+ // with the move to Source-Target/Variant IDs anyway. [aliu]
+ const char* DATA[] = {
+ "latin-greek", NULL /*"Latin-Greek"*/, "case insensitivity",
+ " Null ", "Null", "whitespace",
+ " Latin[a-z]-Greek ", "[a-z]Latin-Greek", "inline filter",
+ " null ; latin-greek ", NULL /*"Null;Latin-Greek"*/, "compound whitespace",
+ };
+ const int32_t DATA_length = sizeof(DATA)/sizeof(DATA[0]);
+ UParseError parseError;
+ UErrorCode status= U_ZERO_ERROR;
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ Transliterator *t = Transliterator::createInstance(DATA[i], UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln(UnicodeString("FAIL: ") + DATA[i+2] +
+ " cannot create ID \"" + DATA[i] + "\"");
+ } else {
+ UnicodeString exp;
+ if (DATA[i+1]) {
+ exp = UnicodeString(DATA[i+1], "");
+ }
+ // Don't worry about getID() if the expected char*
+ // is NULL -- see above.
+ if (exp.length() == 0 || exp == t->getID()) {
+ logln(UnicodeString("Ok: ") + DATA[i+2] +
+ " create ID \"" + DATA[i] + "\" => \"" +
+ exp + "\"");
+ } else {
+ errln(UnicodeString("FAIL: ") + DATA[i+2] +
+ " create ID \"" + DATA[i] + "\" => \"" +
+ t->getID() + "\", exp \"" + exp + "\"");
+ }
+ delete t;
+ }
+ }
+}
+
+/* test for Jitterbug 912 */
+void TransliteratorTest::TestCreateInstance(){
+ const char* FORWARD = "F";
+ const char* REVERSE = "R";
+ const char* DATA[] = {
+ // Column 1: id
+ // Column 2: direction
+ // Column 3: expected ID, or "" if expect failure
+ "Latin-Hangul", REVERSE, "Hangul-Latin", // JB#912
+
+ // JB#2689: bad compound causes crash
+ "InvalidSource-InvalidTarget", FORWARD, "",
+ "InvalidSource-InvalidTarget", REVERSE, "",
+ "Hex-Any;InvalidSource-InvalidTarget", FORWARD, "",
+ "Hex-Any;InvalidSource-InvalidTarget", REVERSE, "",
+ "InvalidSource-InvalidTarget;Hex-Any", FORWARD, "",
+ "InvalidSource-InvalidTarget;Hex-Any", REVERSE, "",
+
+ NULL
+ };
+
+ for (int32_t i=0; DATA[i]; i+=3) {
+ UParseError err;
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString id(DATA[i]);
+ UTransDirection dir = (DATA[i+1]==FORWARD)?
+ UTRANS_FORWARD:UTRANS_REVERSE;
+ UnicodeString expID(DATA[i+2]);
+ Transliterator* t =
+ Transliterator::createInstance(id,dir,err,ec);
+ UnicodeString newID;
+ if (t) {
+ newID = t->getID();
+ }
+ UBool ok = (newID == expID);
+ if (!t) {
+ newID = u_errorName(ec);
+ }
+ if (ok) {
+ logln((UnicodeString)"Ok: createInstance(" +
+ id + "," + DATA[i+1] + ") => " + newID);
+ } else {
+ errln((UnicodeString)"FAIL: createInstance(" +
+ id + "," + DATA[i+1] + ") => " + newID +
+ ", expected " + expID);
+ }
+ delete t;
+ }
+}
+
+/**
+ * Test the normalization transliterator.
+ */
+void TransliteratorTest::TestNormalizationTransliterator() {
+ // THE FOLLOWING TWO TABLES ARE COPIED FROM com.ibm.test.normalizer.BasicTest
+ // PLEASE KEEP THEM IN SYNC WITH BasicTest.
+ const char* CANON[] = {
+ // Input Decomposed Composed
+ "cat", "cat", "cat" ,
+ "\\u00e0ardvark", "a\\u0300ardvark", "\\u00e0ardvark" ,
+
+ "\\u1e0a", "D\\u0307", "\\u1e0a" , // D-dot_above
+ "D\\u0307", "D\\u0307", "\\u1e0a" , // D dot_above
+
+ "\\u1e0c\\u0307", "D\\u0323\\u0307", "\\u1e0c\\u0307" , // D-dot_below dot_above
+ "\\u1e0a\\u0323", "D\\u0323\\u0307", "\\u1e0c\\u0307" , // D-dot_above dot_below
+ "D\\u0307\\u0323", "D\\u0323\\u0307", "\\u1e0c\\u0307" , // D dot_below dot_above
+
+ "\\u1e10\\u0307\\u0323", "D\\u0327\\u0323\\u0307","\\u1e10\\u0323\\u0307", // D dot_below cedilla dot_above
+ "D\\u0307\\u0328\\u0323","D\\u0328\\u0323\\u0307","\\u1e0c\\u0328\\u0307", // D dot_above ogonek dot_below
+
+ "\\u1E14", "E\\u0304\\u0300", "\\u1E14" , // E-macron-grave
+ "\\u0112\\u0300", "E\\u0304\\u0300", "\\u1E14" , // E-macron + grave
+ "\\u00c8\\u0304", "E\\u0300\\u0304", "\\u00c8\\u0304" , // E-grave + macron
+
+ "\\u212b", "A\\u030a", "\\u00c5" , // angstrom_sign
+ "\\u00c5", "A\\u030a", "\\u00c5" , // A-ring
+
+ "\\u00fdffin", "y\\u0301ffin", "\\u00fdffin" , //updated with 3.0
+ "\\u00fd\\uFB03n", "y\\u0301\\uFB03n", "\\u00fd\\uFB03n" , //updated with 3.0
+
+ "Henry IV", "Henry IV", "Henry IV" ,
+ "Henry \\u2163", "Henry \\u2163", "Henry \\u2163" ,
+
+ "\\u30AC", "\\u30AB\\u3099", "\\u30AC" , // ga (Katakana)
+ "\\u30AB\\u3099", "\\u30AB\\u3099", "\\u30AC" , // ka + ten
+ "\\uFF76\\uFF9E", "\\uFF76\\uFF9E", "\\uFF76\\uFF9E" , // hw_ka + hw_ten
+ "\\u30AB\\uFF9E", "\\u30AB\\uFF9E", "\\u30AB\\uFF9E" , // ka + hw_ten
+ "\\uFF76\\u3099", "\\uFF76\\u3099", "\\uFF76\\u3099" , // hw_ka + ten
+
+ "A\\u0300\\u0316", "A\\u0316\\u0300", "\\u00C0\\u0316" ,
+ 0 // end
+ };
+
+ const char* COMPAT[] = {
+ // Input Decomposed Composed
+ "\\uFB4f", "\\u05D0\\u05DC", "\\u05D0\\u05DC" , // Alef-Lamed vs. Alef, Lamed
+
+ "\\u00fdffin", "y\\u0301ffin", "\\u00fdffin" , //updated for 3.0
+ "\\u00fd\\uFB03n", "y\\u0301ffin", "\\u00fdffin" , // ffi ligature -> f + f + i
+
+ "Henry IV", "Henry IV", "Henry IV" ,
+ "Henry \\u2163", "Henry IV", "Henry IV" ,
+
+ "\\u30AC", "\\u30AB\\u3099", "\\u30AC" , // ga (Katakana)
+ "\\u30AB\\u3099", "\\u30AB\\u3099", "\\u30AC" , // ka + ten
+
+ "\\uFF76\\u3099", "\\u30AB\\u3099", "\\u30AC" , // hw_ka + ten
+ 0 // end
+ };
+
+ int32_t i;
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* NFD = Transliterator::createInstance("NFD", UTRANS_FORWARD, parseError, status);
+ Transliterator* NFC = Transliterator::createInstance("NFC", UTRANS_FORWARD, parseError, status);
+ if (!NFD || !NFC) {
+ errln("FAIL: createInstance failed");
+ delete NFD;
+ delete NFC;
+ return;
+ }
+ for (i=0; CANON[i]; i+=3) {
+ UnicodeString in = CharsToUnicodeString(CANON[i]);
+ UnicodeString expd = CharsToUnicodeString(CANON[i+1]);
+ UnicodeString expc = CharsToUnicodeString(CANON[i+2]);
+ expect(*NFD, in, expd);
+ expect(*NFC, in, expc);
+ }
+ delete NFD;
+ delete NFC;
+
+ Transliterator* NFKD = Transliterator::createInstance("NFKD", UTRANS_FORWARD, parseError, status);
+ Transliterator* NFKC = Transliterator::createInstance("NFKC", UTRANS_FORWARD, parseError, status);
+ if (!NFKD || !NFKC) {
+ errln("FAIL: createInstance failed");
+ delete NFKD;
+ delete NFKC;
+ return;
+ }
+ for (i=0; COMPAT[i]; i+=3) {
+ UnicodeString in = CharsToUnicodeString(COMPAT[i]);
+ UnicodeString expkd = CharsToUnicodeString(COMPAT[i+1]);
+ UnicodeString expkc = CharsToUnicodeString(COMPAT[i+2]);
+ expect(*NFKD, in, expkd);
+ expect(*NFKC, in, expkc);
+ }
+ delete NFKD;
+ delete NFKC;
+
+ UParseError pe;
+ status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance("NFD; [x]Remove",
+ UTRANS_FORWARD,
+ pe, status);
+ if (t == 0) {
+ errln("FAIL: createInstance failed");
+ }
+ expect(*t, CharsToUnicodeString("\\u010dx"),
+ CharsToUnicodeString("c\\u030C"));
+ delete t;
+}
+
+/**
+ * Test compound RBT rules.
+ */
+void TransliteratorTest::TestCompoundRBT(void) {
+ // Careful with spacing and ';' here: Phrase this exactly
+ // as toRules() is going to return it. If toRules() changes
+ // with regard to spacing or ';', then adjust this string.
+ UnicodeString rule("::Hex-Any;\n"
+ "::Any-Lower;\n"
+ "a > '.A.';\n"
+ "b > '.B.';\n"
+ "::[^t]Any-Upper;", "");
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("Test", rule, UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln("FAIL: createFromRules failed");
+ return;
+ }
+ expect(*t, "\\u0043at in the hat, bat on the mat",
+ "C.A.t IN tHE H.A.t, .B..A.t ON tHE M.A.t");
+ UnicodeString r;
+ t->toRules(r, TRUE);
+ if (r == rule) {
+ logln((UnicodeString)"OK: toRules() => " + r);
+ } else {
+ errln((UnicodeString)"FAIL: toRules() => " + r +
+ ", expected " + rule);
+ }
+ delete t;
+
+ // Now test toRules
+ t = Transliterator::createInstance("Greek-Latin; Latin-Cyrillic", UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ UnicodeString exp("::Greek-Latin;\n::Latin-Cyrillic;");
+ t->toRules(r, TRUE);
+ if (r != exp) {
+ errln((UnicodeString)"FAIL: toRules() => " + r +
+ ", expected " + exp);
+ } else {
+ logln((UnicodeString)"OK: toRules() => " + r);
+ }
+ delete t;
+
+ // Round trip the result of toRules
+ t = Transliterator::createFromRules("Test", r, UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln("FAIL: createFromRules #2 failed");
+ return;
+ } else {
+ logln((UnicodeString)"OK: createFromRules(" + r + ") succeeded");
+ }
+
+ // Test toRules again
+ t->toRules(r, TRUE);
+ if (r != exp) {
+ errln((UnicodeString)"FAIL: toRules() => " + r +
+ ", expected " + exp);
+ } else {
+ logln((UnicodeString)"OK: toRules() => " + r);
+ }
+
+ delete t;
+
+ // Test Foo(Bar) IDs. Careful with spacing in id; make it conform
+ // to what the regenerated ID will look like.
+ UnicodeString id("Upper(Lower);(NFKC)", "");
+ t = Transliterator::createInstance(id, UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln("FAIL: createInstance #2 failed");
+ return;
+ }
+ if (t->getID() == id) {
+ logln((UnicodeString)"OK: created " + id);
+ } else {
+ errln((UnicodeString)"FAIL: createInstance(" + id +
+ ").getID() => " + t->getID());
+ }
+
+ Transliterator *u = t->createInverse(status);
+ if (u == 0) {
+ errln("FAIL: createInverse failed");
+ delete t;
+ return;
+ }
+ exp = "NFKC();Lower(Upper)";
+ if (u->getID() == exp) {
+ logln((UnicodeString)"OK: createInverse(" + id + ") => " +
+ u->getID());
+ } else {
+ errln((UnicodeString)"FAIL: createInverse(" + id + ") => " +
+ u->getID());
+ }
+ delete t;
+ delete u;
+}
+
+/**
+ * Compound filter semantics were orginially not implemented
+ * correctly. Originally, each component filter f(i) is replaced by
+ * f'(i) = f(i) && g, where g is the filter for the compound
+ * transliterator.
+ *
+ * From Mark:
+ *
+ * Suppose and I have a transliterator X. Internally X is
+ * "Greek-Latin; Latin-Cyrillic; Any-Lower". I use a filter [^A].
+ *
+ * The compound should convert all greek characters (through latin) to
+ * cyrillic, then lowercase the result. The filter should say "don't
+ * touch 'A' in the original". But because an intermediate result
+ * happens to go through "A", the Greek Alpha gets hung up.
+ */
+void TransliteratorTest::TestCompoundFilter(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance
+ ("Greek-Latin; Latin-Greek; Lower", UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+ t->adoptFilter(new UnicodeSet("[^A]", status));
+ if (U_FAILURE(status)) {
+ errln("FAIL: UnicodeSet ct failed");
+ delete t;
+ return;
+ }
+
+ // Only the 'A' at index 1 should remain unchanged
+ expect(*t,
+ CharsToUnicodeString("BA\\u039A\\u0391"),
+ CharsToUnicodeString("\\u03b2A\\u03ba\\u03b1"));
+ delete t;
+}
+
+void TransliteratorTest::TestRemove(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance("Remove[abc]", UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln("FAIL: createInstance failed");
+ return;
+ }
+
+ expect(*t, "Able bodied baker's cats", "Ale odied ker's ts");
+
+ // extra test for RemoveTransliterator::clone(), which at one point wasn't
+ // duplicating the filter
+ Transliterator* t2 = t->clone();
+ expect(*t2, "Able bodied baker's cats", "Ale odied ker's ts");
+
+ delete t;
+ delete t2;
+}
+
+void TransliteratorTest::TestToRules(void) {
+ const char* RBT = "rbt";
+ const char* SET = "set";
+ static const char* DATA[] = {
+ RBT,
+ "$a=\\u4E61; [$a] > A;",
+ "[\\u4E61] > A;",
+
+ RBT,
+ "$white=[[:Zs:][:Zl:]]; $white{a} > A;",
+ "[[:Zs:][:Zl:]]{a} > A;",
+
+ SET,
+ "[[:Zs:][:Zl:]]",
+ "[[:Zs:][:Zl:]]",
+
+ SET,
+ "[:Ps:]",
+ "[:Ps:]",
+
+ SET,
+ "[:L:]",
+ "[:L:]",
+
+ SET,
+ "[[:L:]-[A]]",
+ "[[:L:]-[A]]",
+
+ SET,
+ "[~[:Lu:][:Ll:]]",
+ "[~[:Lu:][:Ll:]]",
+
+ SET,
+ "[~[a-z]]",
+ "[~[a-z]]",
+
+ RBT,
+ "$white=[:Zs:]; $black=[^$white]; $black{a} > A;",
+ "[^[:Zs:]]{a} > A;",
+
+ RBT,
+ "$a=[:Zs:]; $b=[[a-z]-$a]; $b{a} > A;",
+ "[[a-z]-[:Zs:]]{a} > A;",
+
+ RBT,
+ "$a=[:Zs:]; $b=[$a&[a-z]]; $b{a} > A;",
+ "[[:Zs:]&[a-z]]{a} > A;",
+
+ RBT,
+ "$a=[:Zs:]; $b=[x$a]; $b{a} > A;",
+ "[x[:Zs:]]{a} > A;",
+
+ RBT,
+ "$accentMinus = [ [\\u0300-\\u0345] & [:M:] - [\\u0338]] ;"
+ "$macron = \\u0304 ;"
+ "$evowel = [aeiouyAEIOUY] ;"
+ "$iotasub = \\u0345 ;"
+ "($evowel $macron $accentMinus *) i > | $1 $iotasub ;",
+ "([AEIOUYaeiouy]\\u0304[[\\u0300-\\u0345]&[:M:]-[\\u0338]]*)i > | $1 \\u0345;",
+
+ RBT,
+ "([AEIOUYaeiouy]\\u0304[[:M:]-[\\u0304\\u0345]]*)i > | $1 \\u0345;",
+ "([AEIOUYaeiouy]\\u0304[[:M:]-[\\u0304\\u0345]]*)i > | $1 \\u0345;",
+ };
+ static const int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+
+ for (int32_t d=0; d < DATA_length; d+=3) {
+ if (DATA[d] == RBT) {
+ // Transliterator test
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("ID",
+ DATA[d+1], UTRANS_FORWARD, parseError, status);
+ if (t == 0) {
+ errln("FAIL: createFromRules failed");
+ return;
+ }
+ UnicodeString rules, escapedRules;
+ t->toRules(rules, FALSE);
+ t->toRules(escapedRules, TRUE);
+ UnicodeString expRules = CharsToUnicodeString(DATA[d+2]);
+ UnicodeString expEscapedRules(DATA[d+2]);
+ if (rules == expRules) {
+ logln((UnicodeString)"Ok: " + DATA[d+1] +
+ " => " + rules);
+ } else {
+ errln((UnicodeString)"FAIL: " + DATA[d+1] +
+ " => " + rules + ", exp " + expRules);
+ }
+ if (escapedRules == expEscapedRules) {
+ logln((UnicodeString)"Ok: " + DATA[d+1] +
+ " => " + escapedRules);
+ } else {
+ errln((UnicodeString)"FAIL: " + DATA[d+1] +
+ " => " + escapedRules + ", exp " + expEscapedRules);
+ }
+ delete t;
+
+ } else {
+ // UnicodeSet test
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pat(DATA[d+1]);
+ UnicodeString expToPat(DATA[d+2]);
+ UnicodeSet set(pat, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: UnicodeSet ct failed");
+ return;
+ }
+ // Adjust spacing etc. as necessary.
+ UnicodeString toPat;
+ set.toPattern(toPat);
+ if (expToPat == toPat) {
+ logln((UnicodeString)"Ok: " + pat +
+ " => " + toPat);
+ } else {
+ errln((UnicodeString)"FAIL: " + pat +
+ " => " + prettify(toPat, TRUE) +
+ ", exp " + prettify(pat, TRUE));
+ }
+ }
+ }
+}
+
+void TransliteratorTest::TestContext() {
+ UTransPosition pos = {0, 2, 0, 1}; // cs cl s l
+ expect("de > x; {d}e > y;",
+ "de",
+ "ye",
+ &pos);
+
+ expect("ab{c} > z;",
+ "xadabdabcy",
+ "xadabdabzy");
+}
+
+void TransliteratorTest::TestSupplemental() {
+
+ expect(CharsToUnicodeString("$a=\\U00010300; $s=[\\U00010300-\\U00010323];"
+ "a > $a; $s > i;"),
+ CharsToUnicodeString("ab\\U0001030Fx"),
+ CharsToUnicodeString("\\U00010300bix"));
+
+ expect(CharsToUnicodeString("$a=[a-z\\U00010300-\\U00010323];"
+ "$b=[A-Z\\U00010400-\\U0001044D];"
+ "($a)($b) > $2 $1;"),
+ CharsToUnicodeString("aB\\U00010300\\U00010400c\\U00010401\\U00010301D"),
+ CharsToUnicodeString("Ba\\U00010400\\U00010300\\U00010401cD\\U00010301"));
+
+ // k|ax\\U00010300xm
+
+ // k|a\\U00010400\\U00010300xm
+ // ky|\\U00010400\\U00010300xm
+ // ky\\U00010400|\\U00010300xm
+
+ // ky\\U00010400|\\U00010300\\U00010400m
+ // ky\\U00010400y|\\U00010400m
+ expect(CharsToUnicodeString("$a=[a\\U00010300-\\U00010323];"
+ "$a {x} > | @ \\U00010400;"
+ "{$a} [^\\u0000-\\uFFFF] > y;"),
+ CharsToUnicodeString("kax\\U00010300xm"),
+ CharsToUnicodeString("ky\\U00010400y\\U00010400m"));
+
+ expectT("Any-Name",
+ CharsToUnicodeString("\\U00010330\\U000E0061\\u00A0"),
+ "\\N{GOTHIC LETTER AHSA}\\N{TAG LATIN SMALL LETTER A}\\N{NO-BREAK SPACE}");
+
+ expectT("Any-Hex/Unicode",
+ CharsToUnicodeString("\\U00010330\\U0010FF00\\U000E0061\\u00A0"),
+ "U+10330U+10FF00U+E0061U+00A0");
+
+ expectT("Any-Hex/C",
+ CharsToUnicodeString("\\U00010330\\U0010FF00\\U000E0061\\u00A0"),
+ "\\U00010330\\U0010FF00\\U000E0061\\u00A0");
+
+ expectT("Any-Hex/Perl",
+ CharsToUnicodeString("\\U00010330\\U0010FF00\\U000E0061\\u00A0"),
+ "\\x{10330}\\x{10FF00}\\x{E0061}\\x{A0}");
+
+ expectT("Any-Hex/Java",
+ CharsToUnicodeString("\\U00010330\\U0010FF00\\U000E0061\\u00A0"),
+ "\\uD800\\uDF30\\uDBFF\\uDF00\\uDB40\\uDC61\\u00A0");
+
+ expectT("Any-Hex/XML",
+ CharsToUnicodeString("\\U00010330\\U0010FF00\\U000E0061\\u00A0"),
+ "&#x10330;&#x10FF00;&#xE0061;&#xA0;");
+
+ expectT("Any-Hex/XML10",
+ CharsToUnicodeString("\\U00010330\\U0010FF00\\U000E0061\\u00A0"),
+ "&#66352;&#1113856;&#917601;&#160;");
+
+ expectT("[\\U000E0000-\\U000E0FFF] Remove",
+ CharsToUnicodeString("\\U00010330\\U0010FF00\\U000E0061\\u00A0"),
+ CharsToUnicodeString("\\U00010330\\U0010FF00\\u00A0"));
+}
+
+void TransliteratorTest::TestQuantifier() {
+
+ // Make sure @ in a quantified anteContext works
+ expect("a+ {b} > | @@ c; A > a; (a+ c) > '(' $1 ')';",
+ "AAAAAb",
+ "aaa(aac)");
+
+ // Make sure @ in a quantified postContext works
+ expect("{b} a+ > c @@ |; (a+) > '(' $1 ')';",
+ "baaaaa",
+ "caa(aaa)");
+
+ // Make sure @ in a quantified postContext with seg ref works
+ expect("{(b)} a+ > $1 @@ |; (a+) > '(' $1 ')';",
+ "baaaaa",
+ "baa(aaa)");
+
+ // Make sure @ past ante context doesn't enter ante context
+ UTransPosition pos = {0, 5, 3, 5};
+ expect("a+ {b} > | @@ c; x > y; (a+ c) > '(' $1 ')';",
+ "xxxab",
+ "xxx(ac)",
+ &pos);
+
+ // Make sure @ past post context doesn't pass limit
+ UTransPosition pos2 = {0, 4, 0, 2};
+ expect("{b} a+ > c @@ |; x > y; a > A;",
+ "baxx",
+ "caxx",
+ &pos2);
+
+ // Make sure @ past post context doesn't enter post context
+ expect("{b} a+ > c @@ |; x > y; a > A;",
+ "baxx",
+ "cayy");
+
+ expect("(ab)? c > d;",
+ "c abc ababc",
+ "d d abd");
+
+ // NOTE: The (ab)+ when referenced just yields a single "ab",
+ // not the full sequence of them. This accords with perl behavior.
+ expect("(ab)+ {x} > '(' $1 ')';",
+ "x abx ababxy",
+ "x ab(ab) abab(ab)y");
+
+ expect("b+ > x;",
+ "ac abc abbc abbbc",
+ "ac axc axc axc");
+
+ expect("[abc]+ > x;",
+ "qac abrc abbcs abtbbc",
+ "qx xrx xs xtx");
+
+ expect("q{(ab)+} > x;",
+ "qa qab qaba qababc qaba",
+ "qa qx qxa qxc qxa");
+
+ expect("q(ab)* > x;",
+ "qa qab qaba qababc",
+ "xa x xa xc");
+
+ // NOTE: The (ab)+ when referenced just yields a single "ab",
+ // not the full sequence of them. This accords with perl behavior.
+ expect("q(ab)* > '(' $1 ')';",
+ "qa qab qaba qababc",
+ "()a (ab) (ab)a (ab)c");
+
+ // 'foo'+ and 'foo'* -- the quantifier should apply to the entire
+ // quoted string
+ expect("'ab'+ > x;",
+ "bb ab ababb",
+ "bb x xb");
+
+ // $foo+ and $foo* -- the quantifier should apply to the entire
+ // variable reference
+ expect("$var = ab; $var+ > x;",
+ "bb ab ababb",
+ "bb x xb");
+}
+
+class TestTrans : public Transliterator {
+public:
+ TestTrans(const UnicodeString& id) : Transliterator(id, 0) {
+ }
+ virtual Transliterator* clone(void) const {
+ return new TestTrans(getID());
+ }
+ virtual void handleTransliterate(Replaceable& /*text*/, UTransPosition& offsets,
+ UBool /*isIncremental*/) const
+ {
+ offsets.start = offsets.limit;
+ }
+ virtual UClassID getDynamicClassID() const;
+ static UClassID U_EXPORT2 getStaticClassID();
+};
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TestTrans)
+
+/**
+ * Test Source-Target/Variant.
+ */
+void TransliteratorTest::TestSTV(void) {
+ int32_t ns = Transliterator::countAvailableSources();
+ if (ns < 0 || ns > 255) {
+ errln((UnicodeString)"FAIL: Bad source count: " + ns);
+ return;
+ }
+ int32_t i, j;
+ for (i=0; i<ns; ++i) {
+ UnicodeString source;
+ Transliterator::getAvailableSource(i, source);
+ logln((UnicodeString)"" + i + ": " + source);
+ if (source.length() == 0) {
+ errln("FAIL: empty source");
+ continue;
+ }
+ int32_t nt = Transliterator::countAvailableTargets(source);
+ if (nt < 0 || nt > 255) {
+ errln((UnicodeString)"FAIL: Bad target count: " + nt);
+ continue;
+ }
+ for (int32_t j=0; j<nt; ++j) {
+ UnicodeString target;
+ Transliterator::getAvailableTarget(j, source, target);
+ logln((UnicodeString)" " + j + ": " + target);
+ if (target.length() == 0) {
+ errln("FAIL: empty target");
+ continue;
+ }
+ int32_t nv = Transliterator::countAvailableVariants(source, target);
+ if (nv < 0 || nv > 255) {
+ errln((UnicodeString)"FAIL: Bad variant count: " + nv);
+ continue;
+ }
+ for (int32_t k=0; k<nv; ++k) {
+ UnicodeString variant;
+ Transliterator::getAvailableVariant(k, source, target, variant);
+ if (variant.length() == 0) {
+ logln((UnicodeString)" " + k + ": <empty>");
+ } else {
+ logln((UnicodeString)" " + k + ": " + variant);
+ }
+ }
+ }
+ }
+
+ // Test registration
+ const char* IDS[] = { "Fieruwer", "Seoridf-Sweorie", "Oewoir-Oweri/Vsie" };
+ const char* FULL_IDS[] = { "Any-Fieruwer", "Seoridf-Sweorie", "Oewoir-Oweri/Vsie" };
+ const char* SOURCES[] = { NULL, "Seoridf", "Oewoir" };
+ for (i=0; i<3; ++i) {
+ Transliterator *t = new TestTrans(IDS[i]);
+ if (t == 0) {
+ errln("FAIL: out of memory");
+ return;
+ }
+ if (t->getID() != IDS[i]) {
+ errln((UnicodeString)"FAIL: ID mismatch for " + IDS[i]);
+ delete t;
+ return;
+ }
+ Transliterator::registerInstance(t);
+ UErrorCode status = U_ZERO_ERROR;
+ t = Transliterator::createInstance(IDS[i], UTRANS_FORWARD, status);
+ if (t == NULL) {
+ errln((UnicodeString)"FAIL: Registration/creation failed for ID " +
+ IDS[i]);
+ } else {
+ logln((UnicodeString)"Ok: Registration/creation succeeded for ID " +
+ IDS[i]);
+ delete t;
+ }
+ Transliterator::unregister(IDS[i]);
+ t = Transliterator::createInstance(IDS[i], UTRANS_FORWARD, status);
+ if (t != NULL) {
+ errln((UnicodeString)"FAIL: Unregistration failed for ID " +
+ IDS[i]);
+ delete t;
+ }
+ }
+
+ // Make sure getAvailable API reflects removal
+ int32_t n = Transliterator::countAvailableIDs();
+ for (i=0; i<n; ++i) {
+ UnicodeString id = Transliterator::getAvailableID(i);
+ for (j=0; j<3; ++j) {
+ if (id.caseCompare(FULL_IDS[j],0)==0) {
+ errln((UnicodeString)"FAIL: unregister(" + id + ") failed");
+ }
+ }
+ }
+ n = Transliterator::countAvailableTargets("Any");
+ for (i=0; i<n; ++i) {
+ UnicodeString t;
+ Transliterator::getAvailableTarget(i, "Any", t);
+ if (t.caseCompare(IDS[0],0)==0) {
+ errln((UnicodeString)"FAIL: unregister(Any-" + t + ") failed");
+ }
+ }
+ n = Transliterator::countAvailableSources();
+ for (i=0; i<n; ++i) {
+ UnicodeString s;
+ Transliterator::getAvailableSource(i, s);
+ for (j=0; j<3; ++j) {
+ if (SOURCES[j] == NULL) continue;
+ if (s.caseCompare(SOURCES[j],0)==0) {
+ errln((UnicodeString)"FAIL: unregister(" + s + "-*) failed");
+ }
+ }
+ }
+}
+
+/**
+ * Test inverse of Greek-Latin; Title()
+ */
+void TransliteratorTest::TestCompoundInverse(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance
+ ("Greek-Latin; Title()", UTRANS_REVERSE,parseError, status);
+ if (t == 0) {
+ errln("FAIL: createInstance");
+ return;
+ }
+ UnicodeString exp("(Title);Latin-Greek");
+ if (t->getID() == exp) {
+ logln("Ok: inverse of \"Greek-Latin; Title()\" is \"" +
+ t->getID());
+ } else {
+ errln("FAIL: inverse of \"Greek-Latin; Title()\" is \"" +
+ t->getID() + "\", expected \"" + exp + "\"");
+ }
+ delete t;
+}
+
+/**
+ * Test NFD chaining with RBT
+ */
+void TransliteratorTest::TestNFDChainRBT() {
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator* t = Transliterator::createFromRules(
+ "TEST", "::NFD; aa > Q; a > q;",
+ UTRANS_FORWARD, pe, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ errln("FAIL: Transliterator::createFromRules failed with %s", u_errorName(ec));
+ return;
+ }
+ expect(*t, "aa", "Q");
+ delete t;
+
+ // TEMPORARY TESTS -- BEING DEBUGGED
+//=- UnicodeString s, s2;
+//=- t = Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, pe, ec);
+//=- s = CharsToUnicodeString("rmk\\u1E63\\u0113t");
+//=- s2 = CharsToUnicodeString("\\u0930\\u094D\\u092E\\u094D\\u0915\\u094D\\u0937\\u0947\\u0924\\u094D");
+//=- expect(*t, s, s2);
+//=- delete t;
+//=-
+//=- t = Transliterator::createInstance("Devanagari-Latin", UTRANS_FORWARD, pe, ec);
+//=- expect(*t, s2, s);
+//=- delete t;
+//=-
+//=- t = Transliterator::createInstance("Latin-Devanagari;Devanagari-Latin", UTRANS_FORWARD, pe, ec);
+//=- s = CharsToUnicodeString("rmk\\u1E63\\u0113t");
+//=- expect(*t, s, s);
+//=- delete t;
+
+// const char* source[] = {
+// /*
+// "\\u015Br\\u012Bmad",
+// "bhagavadg\\u012Bt\\u0101",
+// "adhy\\u0101ya",
+// "arjuna",
+// "vi\\u1E63\\u0101da",
+// "y\\u014Dga",
+// "dhr\\u0325tar\\u0101\\u1E63\\u1E6Dra",
+// "uv\\u0101cr\\u0325",
+// */
+// "rmk\\u1E63\\u0113t",
+// //"dharmak\\u1E63\\u0113tr\\u0113",
+// /*
+// "kuruk\\u1E63\\u0113tr\\u0113",
+// "samav\\u0113t\\u0101",
+// "yuyutsava-\\u1E25",
+// "m\\u0101mak\\u0101-\\u1E25",
+// // "p\\u0101\\u1E47\\u1E0Dav\\u0101\\u015Bcaiva",
+// "kimakurvata",
+// "san\\u0304java",
+// */
+//
+// 0
+// };
+// const char* expected[] = {
+// /*
+// "\\u0936\\u094d\\u0930\\u0940\\u092e\\u0926\\u094d",
+// "\\u092d\\u0917\\u0935\\u0926\\u094d\\u0917\\u0940\\u0924\\u093e",
+// "\\u0905\\u0927\\u094d\\u092f\\u093e\\u092f",
+// "\\u0905\\u0930\\u094d\\u091c\\u0941\\u0928",
+// "\\u0935\\u093f\\u0937\\u093e\\u0926",
+// "\\u092f\\u094b\\u0917",
+// "\\u0927\\u0943\\u0924\\u0930\\u093e\\u0937\\u094d\\u091f\\u094d\\u0930",
+// "\\u0909\\u0935\\u093E\\u091A\\u0943",
+// */
+// "\\u0927",
+// //"\\u0927\\u0930\\u094d\\u092e\\u0915\\u094d\\u0937\\u0947\\u0924\\u094d\\u0930\\u0947",
+// /*
+// "\\u0915\\u0941\\u0930\\u0941\\u0915\\u094d\\u0937\\u0947\\u0924\\u094d\\u0930\\u0947",
+// "\\u0938\\u092e\\u0935\\u0947\\u0924\\u093e",
+// "\\u092f\\u0941\\u092f\\u0941\\u0924\\u094d\\u0938\\u0935\\u0903",
+// "\\u092e\\u093e\\u092e\\u0915\\u093e\\u0903",
+// // "\\u092a\\u093e\\u0923\\u094d\\u0921\\u0935\\u093e\\u0936\\u094d\\u091a\\u0948\\u0935",
+// "\\u0915\\u093f\\u092e\\u0915\\u0941\\u0930\\u094d\\u0935\\u0924",
+// "\\u0938\\u0902\\u091c\\u0935",
+// */
+// 0
+// };
+// UErrorCode status = U_ZERO_ERROR;
+// UParseError parseError;
+// UnicodeString message;
+// Transliterator* latinToDevToLatin=Transliterator::createInstance("Latin-Devanagari;Devanagari-Latin", UTRANS_FORWARD, parseError, status);
+// Transliterator* devToLatinToDev=Transliterator::createInstance("Devanagari-Latin;Latin-Devanagari", UTRANS_FORWARD, parseError, status);
+// if(U_FAILURE(status)){
+// errln("FAIL: construction " + UnicodeString(" Error: ") + u_errorName(status));
+// errln("PreContext: " + prettify(parseError.preContext) + "PostContext: " + prettify( parseError.postContext) );
+// delete latinToDevToLatin;
+// delete devToLatinToDev;
+// return;
+// }
+// UnicodeString gotResult;
+// for(int i= 0; source[i] != 0; i++){
+// gotResult = source[i];
+// expect(*latinToDevToLatin,CharsToUnicodeString(source[i]),CharsToUnicodeString(source[i]));
+// expect(*devToLatinToDev,CharsToUnicodeString(expected[i]),CharsToUnicodeString(expected[i]));
+// }
+// delete latinToDevToLatin;
+// delete devToLatinToDev;
+}
+
+/**
+ * Inverse of "Null" should be "Null". (J21)
+ */
+void TransliteratorTest::TestNullInverse() {
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance("Null", UTRANS_FORWARD, pe, ec);
+ if (t == 0 || U_FAILURE(ec)) {
+ errln("FAIL: createInstance");
+ return;
+ }
+ Transliterator *u = t->createInverse(ec);
+ if (u == 0 || U_FAILURE(ec)) {
+ errln("FAIL: createInverse");
+ delete t;
+ return;
+ }
+ if (u->getID() != "Null") {
+ errln("FAIL: Inverse of Null should be Null");
+ }
+ delete t;
+ delete u;
+}
+
+/**
+ * Check ID of inverse of alias. (J22)
+ */
+void TransliteratorTest::TestAliasInverseID() {
+ UnicodeString ID("Latin-Hangul", ""); // This should be any alias ID with an inverse
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance(ID, UTRANS_FORWARD, pe, ec);
+ if (t == 0 || U_FAILURE(ec)) {
+ errln("FAIL: createInstance");
+ return;
+ }
+ Transliterator *u = t->createInverse(ec);
+ if (u == 0 || U_FAILURE(ec)) {
+ errln("FAIL: createInverse");
+ delete t;
+ return;
+ }
+ UnicodeString exp = "Hangul-Latin";
+ UnicodeString got = u->getID();
+ if (got != exp) {
+ errln((UnicodeString)"FAIL: Inverse of " + ID + " is " + got +
+ ", expected " + exp);
+ }
+ delete t;
+ delete u;
+}
+
+/**
+ * Test IDs of inverses of compound transliterators. (J20)
+ */
+void TransliteratorTest::TestCompoundInverseID() {
+ UnicodeString ID = "Latin-Jamo;NFC(NFD)";
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance(ID, UTRANS_FORWARD, pe, ec);
+ if (t == 0 || U_FAILURE(ec)) {
+ errln("FAIL: createInstance");
+ return;
+ }
+ Transliterator *u = t->createInverse(ec);
+ if (u == 0 || U_FAILURE(ec)) {
+ errln("FAIL: createInverse");
+ delete t;
+ return;
+ }
+ UnicodeString exp = "NFD(NFC);Jamo-Latin";
+ UnicodeString got = u->getID();
+ if (got != exp) {
+ errln((UnicodeString)"FAIL: Inverse of " + ID + " is " + got +
+ ", expected " + exp);
+ }
+ delete t;
+ delete u;
+}
+
+/**
+ * Test undefined variable.
+
+ */
+void TransliteratorTest::TestUndefinedVariable() {
+ UnicodeString rule = "$initial } a <> \\u1161;";
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("<ID>", rule, UTRANS_FORWARD, pe, ec);
+ delete t;
+ if (U_FAILURE(ec)) {
+ logln((UnicodeString)"OK: Got exception for " + rule + ", as expected: " +
+ u_errorName(ec));
+ return;
+ }
+ errln((UnicodeString)"Fail: bogus rule " + rule + " compiled with error " +
+ u_errorName(ec));
+}
+
+/**
+ * Test empty context.
+ */
+void TransliteratorTest::TestEmptyContext() {
+ expect(" { a } > b;", "xay a ", "xby b ");
+}
+
+/**
+* Test compound filter ID syntax
+*/
+void TransliteratorTest::TestCompoundFilterID(void) {
+ static const char* DATA[] = {
+ // Col. 1 = ID or rule set (latter must start with #)
+
+ // = columns > 1 are null if expect col. 1 to be illegal =
+
+ // Col. 2 = direction, "F..." or "R..."
+ // Col. 3 = source string
+ // Col. 4 = exp result
+
+ "[abc]; [abc]", NULL, NULL, NULL, // multiple filters
+ "Latin-Greek; [abc];", NULL, NULL, NULL, // misplaced filter
+ "[b]; Latin-Greek; Upper; ([xyz])", "F", "abc", "a\\u0392c",
+ "[b]; (Lower); Latin-Greek; Upper(); ([\\u0392])", "R", "\\u0391\\u0392\\u0393", "\\u0391b\\u0393",
+ "#\n::[b]; ::Latin-Greek; ::Upper; ::([xyz]);", "F", "abc", "a\\u0392c",
+ "#\n::[b]; ::(Lower); ::Latin-Greek; ::Upper(); ::([\\u0392]);", "R", "\\u0391\\u0392\\u0393", "\\u0391b\\u0393",
+ NULL,
+ };
+
+ for (int32_t i=0; DATA[i]; i+=4) {
+ UnicodeString id = CharsToUnicodeString(DATA[i]);
+ UTransDirection direction = (DATA[i+1] != NULL && DATA[i+1][0] == 'R') ?
+ UTRANS_REVERSE : UTRANS_FORWARD;
+ UnicodeString source;
+ UnicodeString exp;
+ if (DATA[i+2] != NULL) {
+ source = CharsToUnicodeString(DATA[i+2]);
+ exp = CharsToUnicodeString(DATA[i+3]);
+ }
+ UBool expOk = (DATA[i+1] != NULL);
+ Transliterator* t = NULL;
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ if (id.charAt(0) == 0x23/*#*/) {
+ t = Transliterator::createFromRules("ID", id, direction, pe, ec);
+ } else {
+ t = Transliterator::createInstance(id, direction, pe, ec);
+ }
+ UBool ok = (t != NULL && U_SUCCESS(ec));
+ UnicodeString transID;
+ if (t!=0) {
+ transID = t->getID();
+ }
+ else {
+ transID = UnicodeString("NULL", "");
+ }
+ if (ok == expOk) {
+ logln((UnicodeString)"Ok: " + id + " => " + transID + ", " +
+ u_errorName(ec));
+ if (source.length() != 0) {
+ expect(*t, source, exp);
+ }
+ delete t;
+ } else {
+ errln((UnicodeString)"FAIL: " + id + " => " + transID + ", " +
+ u_errorName(ec));
+ }
+ }
+}
+
+/**
+ * Test new property set syntax
+ */
+void TransliteratorTest::TestPropertySet() {
+ expect("a>A; \\p{Lu}>x; \\p{ANY}>y;", "abcDEF", "Ayyxxx");
+ expect("(.+)>'[' $1 ']';", " a stitch \n in time \r saves 9",
+ "[ a stitch ]\n[ in time ]\r[ saves 9]");
+}
+
+/**
+ * Test various failure points of the new 2.0 engine.
+ */
+void TransliteratorTest::TestNewEngine() {
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance("Latin-Hiragana", UTRANS_FORWARD, pe, ec);
+ if (t == 0 || U_FAILURE(ec)) {
+ errln("FAIL: createInstance Latin-Hiragana");
+ return;
+ }
+ // Katakana should be untouched
+ expect(*t, CharsToUnicodeString("a\\u3042\\u30A2"),
+ CharsToUnicodeString("\\u3042\\u3042\\u30A2"));
+
+ delete t;
+
+#if 1
+ // This test will only work if Transliterator.ROLLBACK is
+ // true. Otherwise, this test will fail, revealing a
+ // limitation of global filters in incremental mode.
+ Transliterator *a =
+ Transliterator::createFromRules("a_to_A", "a > A;", UTRANS_FORWARD, pe, ec);
+ Transliterator *A =
+ Transliterator::createFromRules("A_to_b", "A > b;", UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ delete a;
+ delete A;
+ return;
+ }
+
+ Transliterator* array[3];
+ array[0] = a;
+ array[1] = Transliterator::createInstance("NFD", UTRANS_FORWARD, pe, ec);
+ array[2] = A;
+ if (U_FAILURE(ec)) {
+ errln("FAIL: createInstance NFD");
+ delete a;
+ delete A;
+ delete array[1];
+ return;
+ }
+
+ t = new CompoundTransliterator(array, 3, new UnicodeSet("[:Ll:]", ec));
+ if (U_FAILURE(ec)) {
+ errln("FAIL: UnicodeSet constructor");
+ delete a;
+ delete A;
+ delete array[1];
+ delete t;
+ return;
+ }
+
+ expect(*t, "aAaA", "bAbA");
+
+ assertTrue("countElements", t->countElements() == 3);
+ assertEquals("getElement(0)", t->getElement(0, ec).getID(), "a_to_A");
+ assertEquals("getElement(1)", t->getElement(1, ec).getID(), "NFD");
+ assertEquals("getElement(2)", t->getElement(2, ec).getID(), "A_to_b");
+ assertSuccess("getElement", ec);
+
+ delete a;
+ delete A;
+ delete array[1];
+ delete t;
+#endif
+
+ expect("$smooth = x; $macron = q; [:^L:] { ([aeiouyAEIOUY] $macron?) } [^aeiouyAEIOUY$smooth$macron] > | $1 $smooth ;",
+ "a",
+ "ax");
+
+ UnicodeString gr = CharsToUnicodeString(
+ "$ddot = \\u0308 ;"
+ "$lcgvowel = [\\u03b1\\u03b5\\u03b7\\u03b9\\u03bf\\u03c5\\u03c9] ;"
+ "$rough = \\u0314 ;"
+ "($lcgvowel+ $ddot?) $rough > h | $1 ;"
+ "\\u03b1 <> a ;"
+ "$rough <> h ;");
+
+ expect(gr, CharsToUnicodeString("\\u03B1\\u0314"), "ha");
+}
+
+/**
+ * Test quantified segment behavior. We want:
+ * ([abc])+ > x $1 x; applied to "cba" produces "xax"
+ */
+void TransliteratorTest::TestQuantifiedSegment(void) {
+ // The normal case
+ expect("([abc]+) > x $1 x;", "cba", "xcbax");
+
+ // The tricky case; the quantifier is around the segment
+ expect("([abc])+ > x $1 x;", "cba", "xax");
+
+ // Tricky case in reverse direction
+ expect("([abc])+ { q > x $1 x;", "cbaq", "cbaxax");
+
+ // Check post-context segment
+ expect("{q} ([a-d])+ > '(' $1 ')';", "ddqcba", "dd(a)cba");
+
+ // Test toRule/toPattern for non-quantified segment.
+ // Careful with spacing here.
+ UnicodeString r("([a-c]){q} > x $1 x;");
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator* t = Transliterator::createFromRules("ID", r, UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: createFromRules");
+ delete t;
+ return;
+ }
+ UnicodeString rr;
+ t->toRules(rr, TRUE);
+ if (r != rr) {
+ errln((UnicodeString)"FAIL: \"" + r + "\" x toRules() => \"" + rr + "\"");
+ } else {
+ logln((UnicodeString)"Ok: \"" + r + "\" x toRules() => \"" + rr + "\"");
+ }
+ delete t;
+
+ // Test toRule/toPattern for quantified segment.
+ // Careful with spacing here.
+ r = "([a-c])+{q} > x $1 x;";
+ t = Transliterator::createFromRules("ID", r, UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: createFromRules");
+ delete t;
+ return;
+ }
+ t->toRules(rr, TRUE);
+ if (r != rr) {
+ errln((UnicodeString)"FAIL: \"" + r + "\" x toRules() => \"" + rr + "\"");
+ } else {
+ logln((UnicodeString)"Ok: \"" + r + "\" x toRules() => \"" + rr + "\"");
+ }
+ delete t;
+}
+
+//======================================================================
+// Ram's tests
+//======================================================================
+void TransliteratorTest::TestDevanagariLatinRT(){
+ const int MAX_LEN= 52;
+ const char* const source[MAX_LEN] = {
+ "bh\\u0101rata",
+ "kra",
+ "k\\u1E63a",
+ "khra",
+ "gra",
+ "\\u1E45ra",
+ "cra",
+ "chra",
+ "j\\u00F1a",
+ "jhra",
+ "\\u00F1ra",
+ "\\u1E6Dya",
+ "\\u1E6Dhra",
+ "\\u1E0Dya",
+ //"r\\u0323ya", // \u095c is not valid in Devanagari
+ "\\u1E0Dhya",
+ "\\u1E5Bhra",
+ "\\u1E47ra",
+ "tta",
+ "thra",
+ "dda",
+ "dhra",
+ "nna",
+ "pra",
+ "phra",
+ "bra",
+ "bhra",
+ "mra",
+ "\\u1E49ra",
+ //"l\\u0331ra",
+ "yra",
+ "\\u1E8Fra",
+ //"l-",
+ "vra",
+ "\\u015Bra",
+ "\\u1E63ra",
+ "sra",
+ "hma",
+ "\\u1E6D\\u1E6Da",
+ "\\u1E6D\\u1E6Dha",
+ "\\u1E6Dh\\u1E6Dha",
+ "\\u1E0D\\u1E0Da",
+ "\\u1E0D\\u1E0Dha",
+ "\\u1E6Dya",
+ "\\u1E6Dhya",
+ "\\u1E0Dya",
+ "\\u1E0Dhya",
+ // Not roundtrippable --
+ // \\u0939\\u094d\\u094d\\u092E - hma
+ // \\u0939\\u094d\\u092E - hma
+ // CharsToUnicodeString("hma"),
+ "hya",
+ "\\u015Br\\u0325",
+ "\\u015Bca",
+ "\\u0115",
+ "san\\u0304j\\u012Bb s\\u0113nagupta",
+ "\\u0101nand vaddir\\u0101ju",
+ "\\u0101",
+ "a"
+ };
+ const char* const expected[MAX_LEN] = {
+ "\\u092D\\u093E\\u0930\\u0924", /* bha\\u0304rata */
+ "\\u0915\\u094D\\u0930", /* kra */
+ "\\u0915\\u094D\\u0937", /* ks\\u0323a */
+ "\\u0916\\u094D\\u0930", /* khra */
+ "\\u0917\\u094D\\u0930", /* gra */
+ "\\u0919\\u094D\\u0930", /* n\\u0307ra */
+ "\\u091A\\u094D\\u0930", /* cra */
+ "\\u091B\\u094D\\u0930", /* chra */
+ "\\u091C\\u094D\\u091E", /* jn\\u0303a */
+ "\\u091D\\u094D\\u0930", /* jhra */
+ "\\u091E\\u094D\\u0930", /* n\\u0303ra */
+ "\\u091F\\u094D\\u092F", /* t\\u0323ya */
+ "\\u0920\\u094D\\u0930", /* t\\u0323hra */
+ "\\u0921\\u094D\\u092F", /* d\\u0323ya */
+ //"\\u095C\\u094D\\u092F", /* r\\u0323ya */ // \u095c is not valid in Devanagari
+ "\\u0922\\u094D\\u092F", /* d\\u0323hya */
+ "\\u0922\\u093C\\u094D\\u0930", /* r\\u0323hra */
+ "\\u0923\\u094D\\u0930", /* n\\u0323ra */
+ "\\u0924\\u094D\\u0924", /* tta */
+ "\\u0925\\u094D\\u0930", /* thra */
+ "\\u0926\\u094D\\u0926", /* dda */
+ "\\u0927\\u094D\\u0930", /* dhra */
+ "\\u0928\\u094D\\u0928", /* nna */
+ "\\u092A\\u094D\\u0930", /* pra */
+ "\\u092B\\u094D\\u0930", /* phra */
+ "\\u092C\\u094D\\u0930", /* bra */
+ "\\u092D\\u094D\\u0930", /* bhra */
+ "\\u092E\\u094D\\u0930", /* mra */
+ "\\u0929\\u094D\\u0930", /* n\\u0331ra */
+ //"\\u0934\\u094D\\u0930", /* l\\u0331ra */
+ "\\u092F\\u094D\\u0930", /* yra */
+ "\\u092F\\u093C\\u094D\\u0930", /* y\\u0307ra */
+ //"l-",
+ "\\u0935\\u094D\\u0930", /* vra */
+ "\\u0936\\u094D\\u0930", /* s\\u0301ra */
+ "\\u0937\\u094D\\u0930", /* s\\u0323ra */
+ "\\u0938\\u094D\\u0930", /* sra */
+ "\\u0939\\u094d\\u092E", /* hma */
+ "\\u091F\\u094D\\u091F", /* t\\u0323t\\u0323a */
+ "\\u091F\\u094D\\u0920", /* t\\u0323t\\u0323ha */
+ "\\u0920\\u094D\\u0920", /* t\\u0323ht\\u0323ha*/
+ "\\u0921\\u094D\\u0921", /* d\\u0323d\\u0323a */
+ "\\u0921\\u094D\\u0922", /* d\\u0323d\\u0323ha */
+ "\\u091F\\u094D\\u092F", /* t\\u0323ya */
+ "\\u0920\\u094D\\u092F", /* t\\u0323hya */
+ "\\u0921\\u094D\\u092F", /* d\\u0323ya */
+ "\\u0922\\u094D\\u092F", /* d\\u0323hya */
+ // "hma", /* hma */
+ "\\u0939\\u094D\\u092F", /* hya */
+ "\\u0936\\u0943", /* s\\u0301r\\u0325a */
+ "\\u0936\\u094D\\u091A", /* s\\u0301ca */
+ "\\u090d", /* e\\u0306 */
+ "\\u0938\\u0902\\u091C\\u0940\\u092C\\u094D \\u0938\\u0947\\u0928\\u0917\\u0941\\u092A\\u094D\\u0924",
+ "\\u0906\\u0928\\u0902\\u0926\\u094D \\u0935\\u0926\\u094D\\u0926\\u093F\\u0930\\u093E\\u091C\\u0941",
+ "\\u0906",
+ "\\u0905",
+ };
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ UnicodeString message;
+ Transliterator* latinToDev=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
+ Transliterator* devToLatin=Transliterator::createInstance("Devanagari-Latin", UTRANS_FORWARD, parseError, status);
+ if(U_FAILURE(status)){
+ errln("FAIL: construction " + UnicodeString(" Error: ") + u_errorName(status));
+ errln("PreContext: " + prettify(parseError.preContext) + " PostContext: " + prettify( parseError.postContext) );
+ return;
+ }
+ UnicodeString gotResult;
+ for(int i= 0; i<MAX_LEN; i++){
+ gotResult = source[i];
+ expect(*latinToDev,CharsToUnicodeString(source[i]),CharsToUnicodeString(expected[i]));
+ expect(*devToLatin,CharsToUnicodeString(expected[i]),CharsToUnicodeString(source[i]));
+ }
+ delete latinToDev;
+ delete devToLatin;
+}
+
+void TransliteratorTest::TestTeluguLatinRT(){
+ const int MAX_LEN=10;
+ const char* const source[MAX_LEN] = {
+ "raghur\\u0101m vi\\u015Bvan\\u0101dha", /* Raghuram Viswanadha */
+ "\\u0101nand vaddir\\u0101ju", /* Anand Vaddiraju */
+ "r\\u0101j\\u012Bv ka\\u015Barab\\u0101da", /* Rajeev Kasarabada */
+ "san\\u0304j\\u012Bv ka\\u015Barab\\u0101da", /* sanjeev kasarabada */
+ "san\\u0304j\\u012Bb sen'gupta", /* sanjib sengupata */
+ "amar\\u0113ndra hanum\\u0101nula", /* Amarendra hanumanula */
+ "ravi kum\\u0101r vi\\u015Bvan\\u0101dha", /* Ravi Kumar Viswanadha */
+ "\\u0101ditya kandr\\u0113gula", /* Aditya Kandregula */
+ "\\u015Br\\u012Bdhar ka\\u1E47\\u1E6Dama\\u015Be\\u1E6D\\u1E6Di",/* Shridhar Kantamsetty */
+ "m\\u0101dhav de\\u015Be\\u1E6D\\u1E6Di" /* Madhav Desetty */
+ };
+
+ const char* const expected[MAX_LEN] = {
+ "\\u0c30\\u0c18\\u0c41\\u0c30\\u0c3e\\u0c2e\\u0c4d \\u0c35\\u0c3f\\u0c36\\u0c4d\\u0c35\\u0c28\\u0c3e\\u0c27",
+ "\\u0c06\\u0c28\\u0c02\\u0c26\\u0c4d \\u0C35\\u0C26\\u0C4D\\u0C26\\u0C3F\\u0C30\\u0C3E\\u0C1C\\u0C41",
+ "\\u0c30\\u0c3e\\u0c1c\\u0c40\\u0c35\\u0c4d \\u0c15\\u0c36\\u0c30\\u0c2c\\u0c3e\\u0c26",
+ "\\u0c38\\u0c02\\u0c1c\\u0c40\\u0c35\\u0c4d \\u0c15\\u0c36\\u0c30\\u0c2c\\u0c3e\\u0c26",
+ "\\u0c38\\u0c02\\u0c1c\\u0c40\\u0c2c\\u0c4d \\u0c38\\u0c46\\u0c28\\u0c4d\\u0c17\\u0c41\\u0c2a\\u0c4d\\u0c24",
+ "\\u0c05\\u0c2e\\u0c30\\u0c47\\u0c02\\u0c26\\u0c4d\\u0c30 \\u0c39\\u0c28\\u0c41\\u0c2e\\u0c3e\\u0c28\\u0c41\\u0c32",
+ "\\u0c30\\u0c35\\u0c3f \\u0c15\\u0c41\\u0c2e\\u0c3e\\u0c30\\u0c4d \\u0c35\\u0c3f\\u0c36\\u0c4d\\u0c35\\u0c28\\u0c3e\\u0c27",
+ "\\u0c06\\u0c26\\u0c3f\\u0c24\\u0c4d\\u0c2f \\u0C15\\u0C02\\u0C26\\u0C4D\\u0C30\\u0C47\\u0C17\\u0C41\\u0c32",
+ "\\u0c36\\u0c4d\\u0c30\\u0c40\\u0C27\\u0C30\\u0C4D \\u0c15\\u0c02\\u0c1f\\u0c2e\\u0c36\\u0c46\\u0c1f\\u0c4d\\u0c1f\\u0c3f",
+ "\\u0c2e\\u0c3e\\u0c27\\u0c35\\u0c4d \\u0c26\\u0c46\\u0c36\\u0c46\\u0c1f\\u0c4d\\u0c1f\\u0c3f",
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ UnicodeString message;
+ Transliterator* latinToDev=Transliterator::createInstance("Latin-Telugu", UTRANS_FORWARD, parseError, status);
+ Transliterator* devToLatin=Transliterator::createInstance("Telugu-Latin", UTRANS_FORWARD, parseError, status);
+ if(U_FAILURE(status)){
+ errln("FAIL: construction " + UnicodeString(" Error: ") + u_errorName(status));
+ errln("PreContext: " + prettify(parseError.preContext) + " PostContext: " + prettify( parseError.postContext) );
+ return;
+ }
+ UnicodeString gotResult;
+ for(int i= 0; i<MAX_LEN; i++){
+ gotResult = source[i];
+ expect(*latinToDev,CharsToUnicodeString(source[i]),CharsToUnicodeString(expected[i]));
+ expect(*devToLatin,CharsToUnicodeString(expected[i]),CharsToUnicodeString(source[i]));
+ }
+ delete latinToDev;
+ delete devToLatin;
+}
+
+void TransliteratorTest::TestSanskritLatinRT(){
+ const int MAX_LEN =16;
+ const char* const source[MAX_LEN] = {
+ "rmk\\u1E63\\u0113t",
+ "\\u015Br\\u012Bmad",
+ "bhagavadg\\u012Bt\\u0101",
+ "adhy\\u0101ya",
+ "arjuna",
+ "vi\\u1E63\\u0101da",
+ "y\\u014Dga",
+ "dhr\\u0325tar\\u0101\\u1E63\\u1E6Dra",
+ "uv\\u0101cr\\u0325",
+ "dharmak\\u1E63\\u0113tr\\u0113",
+ "kuruk\\u1E63\\u0113tr\\u0113",
+ "samav\\u0113t\\u0101",
+ "yuyutsava\\u1E25",
+ "m\\u0101mak\\u0101\\u1E25",
+ // "p\\u0101\\u1E47\\u1E0Dav\\u0101\\u015Bcaiva",
+ "kimakurvata",
+ "san\\u0304java",
+ };
+ const char* const expected[MAX_LEN] = {
+ "\\u0930\\u094D\\u092E\\u094D\\u0915\\u094D\\u0937\\u0947\\u0924\\u094D",
+ "\\u0936\\u094d\\u0930\\u0940\\u092e\\u0926\\u094d",
+ "\\u092d\\u0917\\u0935\\u0926\\u094d\\u0917\\u0940\\u0924\\u093e",
+ "\\u0905\\u0927\\u094d\\u092f\\u093e\\u092f",
+ "\\u0905\\u0930\\u094d\\u091c\\u0941\\u0928",
+ "\\u0935\\u093f\\u0937\\u093e\\u0926",
+ "\\u092f\\u094b\\u0917",
+ "\\u0927\\u0943\\u0924\\u0930\\u093e\\u0937\\u094d\\u091f\\u094d\\u0930",
+ "\\u0909\\u0935\\u093E\\u091A\\u0943",
+ "\\u0927\\u0930\\u094d\\u092e\\u0915\\u094d\\u0937\\u0947\\u0924\\u094d\\u0930\\u0947",
+ "\\u0915\\u0941\\u0930\\u0941\\u0915\\u094d\\u0937\\u0947\\u0924\\u094d\\u0930\\u0947",
+ "\\u0938\\u092e\\u0935\\u0947\\u0924\\u093e",
+ "\\u092f\\u0941\\u092f\\u0941\\u0924\\u094d\\u0938\\u0935\\u0903",
+ "\\u092e\\u093e\\u092e\\u0915\\u093e\\u0903",
+ //"\\u092a\\u093e\\u0923\\u094d\\u0921\\u0935\\u093e\\u0936\\u094d\\u091a\\u0948\\u0935",
+ "\\u0915\\u093f\\u092e\\u0915\\u0941\\u0930\\u094d\\u0935\\u0924",
+ "\\u0938\\u0902\\u091c\\u0935",
+ };
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ UnicodeString message;
+ Transliterator* latinToDev=Transliterator::createInstance("Latin-Devanagari", UTRANS_FORWARD, parseError, status);
+ Transliterator* devToLatin=Transliterator::createInstance("Devanagari-Latin", UTRANS_FORWARD, parseError, status);
+ if(U_FAILURE(status)){
+ errln("FAIL: construction " + UnicodeString(" Error: ") + u_errorName(status));
+ errln("PreContext: " + prettify(parseError.preContext) + " PostContext: " + prettify( parseError.postContext) );
+ return;
+ }
+ UnicodeString gotResult;
+ for(int i= 0; i<MAX_LEN; i++){
+ gotResult = source[i];
+ expect(*latinToDev,CharsToUnicodeString(source[i]),CharsToUnicodeString(expected[i]));
+ expect(*devToLatin,CharsToUnicodeString(expected[i]),CharsToUnicodeString(source[i]));
+ }
+ delete latinToDev;
+ delete devToLatin;
+}
+
+
+void TransliteratorTest::TestCompoundLatinRT(){
+ const char* const source[] = {
+ "rmk\\u1E63\\u0113t",
+ "\\u015Br\\u012Bmad",
+ "bhagavadg\\u012Bt\\u0101",
+ "adhy\\u0101ya",
+ "arjuna",
+ "vi\\u1E63\\u0101da",
+ "y\\u014Dga",
+ "dhr\\u0325tar\\u0101\\u1E63\\u1E6Dra",
+ "uv\\u0101cr\\u0325",
+ "dharmak\\u1E63\\u0113tr\\u0113",
+ "kuruk\\u1E63\\u0113tr\\u0113",
+ "samav\\u0113t\\u0101",
+ "yuyutsava\\u1E25",
+ "m\\u0101mak\\u0101\\u1E25",
+ // "p\\u0101\\u1E47\\u1E0Dav\\u0101\\u015Bcaiva",
+ "kimakurvata",
+ "san\\u0304java"
+ };
+ const int MAX_LEN = sizeof(source)/sizeof(source[0]);
+ const char* const expected[MAX_LEN] = {
+ "\\u0930\\u094D\\u092E\\u094D\\u0915\\u094D\\u0937\\u0947\\u0924\\u094D",
+ "\\u0936\\u094d\\u0930\\u0940\\u092e\\u0926\\u094d",
+ "\\u092d\\u0917\\u0935\\u0926\\u094d\\u0917\\u0940\\u0924\\u093e",
+ "\\u0905\\u0927\\u094d\\u092f\\u093e\\u092f",
+ "\\u0905\\u0930\\u094d\\u091c\\u0941\\u0928",
+ "\\u0935\\u093f\\u0937\\u093e\\u0926",
+ "\\u092f\\u094b\\u0917",
+ "\\u0927\\u0943\\u0924\\u0930\\u093e\\u0937\\u094d\\u091f\\u094d\\u0930",
+ "\\u0909\\u0935\\u093E\\u091A\\u0943",
+ "\\u0927\\u0930\\u094d\\u092e\\u0915\\u094d\\u0937\\u0947\\u0924\\u094d\\u0930\\u0947",
+ "\\u0915\\u0941\\u0930\\u0941\\u0915\\u094d\\u0937\\u0947\\u0924\\u094d\\u0930\\u0947",
+ "\\u0938\\u092e\\u0935\\u0947\\u0924\\u093e",
+ "\\u092f\\u0941\\u092f\\u0941\\u0924\\u094d\\u0938\\u0935\\u0903",
+ "\\u092e\\u093e\\u092e\\u0915\\u093e\\u0903",
+ // "\\u092a\\u093e\\u0923\\u094d\\u0921\\u0935\\u093e\\u0936\\u094d\\u091a\\u0948\\u0935",
+ "\\u0915\\u093f\\u092e\\u0915\\u0941\\u0930\\u094d\\u0935\\u0924",
+ "\\u0938\\u0902\\u091c\\u0935"
+ };
+ if(MAX_LEN != sizeof(expected)/sizeof(expected[0])) {
+ errln("error in TestCompoundLatinRT: source[] and expected[] have different lengths!");
+ return;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ UnicodeString message;
+ Transliterator* devToLatinToDev =Transliterator::createInstance("Devanagari-Latin;Latin-Devanagari", UTRANS_FORWARD, parseError, status);
+ Transliterator* latinToDevToLatin=Transliterator::createInstance("Latin-Devanagari;Devanagari-Latin", UTRANS_FORWARD, parseError, status);
+ Transliterator* devToTelToDev =Transliterator::createInstance("Devanagari-Telugu;Telugu-Devanagari", UTRANS_FORWARD, parseError, status);
+ Transliterator* latinToTelToLatin=Transliterator::createInstance("Latin-Telugu;Telugu-Latin", UTRANS_FORWARD, parseError, status);
+
+ if(U_FAILURE(status)){
+ errln("FAIL: construction " + UnicodeString(" Error: ") + u_errorName(status));
+ errln("PreContext: " + prettify(parseError.preContext) + " PostContext: " + prettify( parseError.postContext) );
+ return;
+ }
+ UnicodeString gotResult;
+ for(int i= 0; i<MAX_LEN; i++){
+ gotResult = source[i];
+ expect(*devToLatinToDev,CharsToUnicodeString(expected[i]),CharsToUnicodeString(expected[i]));
+ expect(*latinToDevToLatin,CharsToUnicodeString(source[i]),CharsToUnicodeString(source[i]));
+ expect(*latinToTelToLatin,CharsToUnicodeString(source[i]),CharsToUnicodeString(source[i]));
+
+ }
+ delete(latinToDevToLatin);
+ delete(devToLatinToDev);
+ delete(devToTelToDev);
+ delete(latinToTelToLatin);
+}
+
+/**
+ * Test Gurmukhi-Devanagari Tippi and Bindi
+ */
+void TransliteratorTest::TestGurmukhiDevanagari(){
+ // the rule says:
+ // (\u0902) (when preceded by vowel) ---> (\u0A02)
+ // (\u0902) (when preceded by consonant) ---> (\u0A70)
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet vowel(UnicodeString("[\\u0905-\\u090A \\u090F\\u0910\\u0913\\u0914 \\u093e-\\u0942\\u0947\\u0948\\u094B\\u094C\\u094D]").unescape(), status);
+ UnicodeSet non_vowel(UnicodeString("[\\u0915-\\u0928\\u092A-\\u0930]").unescape(), status);
+ UParseError parseError;
+
+ UnicodeSetIterator vIter(vowel);
+ UnicodeSetIterator nvIter(non_vowel);
+ Transliterator* trans = Transliterator::createInstance("Devanagari-Gurmukhi",UTRANS_FORWARD, parseError, status);
+ if(U_FAILURE(status)) {
+ errln("Error creating transliterator %s", u_errorName(status));
+ delete trans;
+ return;
+ }
+ UnicodeString src (" \\u0902");
+ UnicodeString expected(" \\u0A02");
+ src = src.unescape();
+ expected= expected.unescape();
+
+ while(vIter.next()){
+ src.setCharAt(0,(UChar) vIter.getCodepoint());
+ expected.setCharAt(0,(UChar) (vIter.getCodepoint()+0x0100));
+ expect(*trans,src,expected);
+ }
+
+ expected.setCharAt(1,0x0A70);
+ while(nvIter.next()){
+ //src.setCharAt(0,(char) nvIter.codepoint);
+ src.setCharAt(0,(UChar)nvIter.getCodepoint());
+ expected.setCharAt(0,(UChar) (nvIter.getCodepoint()+0x0100));
+ expect(*trans,src,expected);
+ }
+ delete trans;
+}
+/**
+ * Test instantiation from a locale.
+ */
+void TransliteratorTest::TestLocaleInstantiation(void) {
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance("ru_RU-Latin", UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: createInstance(ru_RU-Latin)");
+ delete t;
+ return;
+ }
+ expect(*t, CharsToUnicodeString("\\u0430"), "a");
+ delete t;
+
+ t = Transliterator::createInstance("en-el", UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: createInstance(en-el)");
+ delete t;
+ return;
+ }
+ expect(*t, "a", CharsToUnicodeString("\\u03B1"));
+ delete t;
+}
+
+/**
+ * Test title case handling of accent (should ignore accents)
+ */
+void TransliteratorTest::TestTitleAccents(void) {
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance("Title", UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: createInstance(Title)");
+ delete t;
+ return;
+ }
+ expect(*t, CharsToUnicodeString("a\\u0300b can't abe"), CharsToUnicodeString("A\\u0300b Can't Abe"));
+ delete t;
+}
+
+/**
+ * Basic test of a locale resource based rule.
+ */
+void TransliteratorTest::TestLocaleResource() {
+ const char* DATA[] = {
+ // id from to
+ //"Latin-Greek/UNGEGN", "b", "\\u03bc\\u03c0",
+ "Latin-el", "b", "\\u03bc\\u03c0",
+ "Latin-Greek", "b", "\\u03B2",
+ "Greek-Latin/UNGEGN", "\\u03B2", "v",
+ "el-Latin", "\\u03B2", "v",
+ "Greek-Latin", "\\u03B2", "b",
+ };
+ const int32_t DATA_length = sizeof(DATA) / sizeof(DATA[0]);
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createInstance(DATA[i], UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createInstance(" + DATA[i] + ")");
+ delete t;
+ continue;
+ }
+ expect(*t, CharsToUnicodeString(DATA[i+1]),
+ CharsToUnicodeString(DATA[i+2]));
+ delete t;
+ }
+}
+
+/**
+ * Make sure parse errors reference the right line.
+ */
+void TransliteratorTest::TestParseError() {
+ static const char* rule =
+ "a > b;\n"
+ "# more stuff\n"
+ "d << b;";
+ UErrorCode ec = U_ZERO_ERROR;
+ UParseError pe;
+ Transliterator *t = Transliterator::createFromRules("ID", rule, UTRANS_FORWARD, pe, ec);
+ delete t;
+ if (U_FAILURE(ec)) {
+ UnicodeString err(pe.preContext);
+ err.append((UChar)124/*|*/).append(pe.postContext);
+ if (err.indexOf("d << b") >= 0) {
+ logln("Ok: " + err);
+ } else {
+ errln("FAIL: " + err);
+ }
+ }
+ else {
+ errln("FAIL: no syntax error");
+ }
+ static const char* maskingRule =
+ "a>x;\n"
+ "# more stuff\n"
+ "ab>y;";
+ ec = U_ZERO_ERROR;
+ delete Transliterator::createFromRules("ID", maskingRule, UTRANS_FORWARD, pe, ec);
+ if (ec != U_RULE_MASK_ERROR) {
+ errln("FAIL: returned %s instead of U_RULE_MASK_ERROR", u_errorName(ec));
+ }
+ else if (UnicodeString("a > x;") != UnicodeString(pe.preContext)) {
+ errln("FAIL: did not get expected precontext");
+ }
+ else if (UnicodeString("ab > y;") != UnicodeString(pe.postContext)) {
+ errln("FAIL: did not get expected postcontext");
+ }
+}
+
+/**
+ * Make sure sets on output are disallowed.
+ */
+void TransliteratorTest::TestOutputSet() {
+ UnicodeString rule = "$set = [a-cm-n]; b > $set;";
+ UErrorCode ec = U_ZERO_ERROR;
+ UParseError pe;
+ Transliterator *t = Transliterator::createFromRules("ID", rule, UTRANS_FORWARD, pe, ec);
+ delete t;
+ if (U_FAILURE(ec)) {
+ UnicodeString err(pe.preContext);
+ err.append((UChar)124/*|*/).append(pe.postContext);
+ logln("Ok: " + err);
+ return;
+ }
+ errln("FAIL: No syntax error");
+}
+
+/**
+ * Test the use variable range pragma, making sure that use of
+ * variable range characters is detected and flagged as an error.
+ */
+void TransliteratorTest::TestVariableRange() {
+ UnicodeString rule = "use variable range 0x70 0x72; a > A; b > B; q > Q;";
+ UErrorCode ec = U_ZERO_ERROR;
+ UParseError pe;
+ Transliterator *t = Transliterator::createFromRules("ID", rule, UTRANS_FORWARD, pe, ec);
+ delete t;
+ if (U_FAILURE(ec)) {
+ UnicodeString err(pe.preContext);
+ err.append((UChar)124/*|*/).append(pe.postContext);
+ logln("Ok: " + err);
+ return;
+ }
+ errln("FAIL: No syntax error");
+}
+
+/**
+ * Test invalid post context error handling
+ */
+void TransliteratorTest::TestInvalidPostContext() {
+ UnicodeString rule = "a}b{c>d;";
+ UErrorCode ec = U_ZERO_ERROR;
+ UParseError pe;
+ Transliterator *t = Transliterator::createFromRules("ID", rule, UTRANS_FORWARD, pe, ec);
+ delete t;
+ if (U_FAILURE(ec)) {
+ UnicodeString err(pe.preContext);
+ err.append((UChar)124/*|*/).append(pe.postContext);
+ if (err.indexOf("a}b{c") >= 0) {
+ logln("Ok: " + err);
+ } else {
+ errln("FAIL: " + err);
+ }
+ return;
+ }
+ errln("FAIL: No syntax error");
+}
+
+/**
+ * Test ID form variants
+ */
+void TransliteratorTest::TestIDForms() {
+ const char* DATA[] = {
+ "NFC", NULL, "NFD",
+ "nfd", NULL, "NFC", // make sure case is ignored
+ "Any-NFKD", NULL, "Any-NFKC",
+ "Null", NULL, "Null",
+ "-nfkc", "nfkc", "NFKD",
+ "-nfkc/", "nfkc", "NFKD",
+ "Latin-Greek/UNGEGN", NULL, "Greek-Latin/UNGEGN",
+ "Greek/UNGEGN-Latin", "Greek-Latin/UNGEGN", "Latin-Greek/UNGEGN",
+ "Bengali-Devanagari/", "Bengali-Devanagari", "Devanagari-Bengali",
+ "Source-", NULL, NULL,
+ "Source/Variant-", NULL, NULL,
+ "Source-/Variant", NULL, NULL,
+ "/Variant", NULL, NULL,
+ "/Variant-", NULL, NULL,
+ "-/Variant", NULL, NULL,
+ "-/", NULL, NULL,
+ "-", NULL, NULL,
+ "/", NULL, NULL,
+ };
+ const int32_t DATA_length = sizeof(DATA)/sizeof(DATA[0]);
+
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ const char* ID = DATA[i];
+ const char* expID = DATA[i+1];
+ const char* expInvID = DATA[i+2];
+ UBool expValid = (expInvID != NULL);
+ if (expID == NULL) {
+ expID = ID;
+ }
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t =
+ Transliterator::createInstance(ID, UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ if (!expValid) {
+ logln((UnicodeString)"Ok: getInstance(" + ID +") => " + u_errorName(ec));
+ } else {
+ errln((UnicodeString)"FAIL: Couldn't create " + ID);
+ }
+ delete t;
+ continue;
+ }
+ Transliterator *u = t->createInverse(ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: Couldn't create inverse of " + ID);
+ delete t;
+ delete u;
+ continue;
+ }
+ if (t->getID() == expID &&
+ u->getID() == expInvID) {
+ logln((UnicodeString)"Ok: " + ID + ".getInverse() => " + expInvID);
+ } else {
+ errln((UnicodeString)"FAIL: getInstance(" + ID + ") => " +
+ t->getID() + " x getInverse() => " + u->getID() +
+ ", expected " + expInvID);
+ }
+ delete t;
+ delete u;
+ }
+}
+
+static const UChar SPACE[] = {32,0};
+static const UChar NEWLINE[] = {10,0};
+static const UChar RETURN[] = {13,0};
+static const UChar EMPTY[] = {0};
+
+void TransliteratorTest::checkRules(const UnicodeString& label, Transliterator& t2,
+ const UnicodeString& testRulesForward) {
+ UnicodeString rules2; t2.toRules(rules2, TRUE);
+ //rules2 = TestUtility.replaceAll(rules2, new UnicodeSet("[' '\n\r]"), "");
+ rules2.findAndReplace(SPACE, EMPTY);
+ rules2.findAndReplace(NEWLINE, EMPTY);
+ rules2.findAndReplace(RETURN, EMPTY);
+
+ UnicodeString testRules(testRulesForward); testRules.findAndReplace(SPACE, EMPTY);
+
+ if (rules2 != testRules) {
+ errln(label);
+ logln((UnicodeString)"GENERATED RULES: " + rules2);
+ logln((UnicodeString)"SHOULD BE: " + testRulesForward);
+ }
+}
+
+/**
+ * Mark's toRules test.
+ */
+void TransliteratorTest::TestToRulesMark() {
+ const char* testRules =
+ "::[[:Latin:][:Mark:]];"
+ "::NFKD (NFC);"
+ "::Lower (Lower);"
+ "a <> \\u03B1;" // alpha
+ "::NFKC (NFD);"
+ "::Upper (Lower);"
+ "::Lower ();"
+ "::([[:Greek:][:Mark:]]);"
+ ;
+ const char* testRulesForward =
+ "::[[:Latin:][:Mark:]];"
+ "::NFKD(NFC);"
+ "::Lower(Lower);"
+ "a > \\u03B1;"
+ "::NFKC(NFD);"
+ "::Upper (Lower);"
+ "::Lower ();"
+ ;
+ const char* testRulesBackward =
+ "::[[:Greek:][:Mark:]];"
+ "::Lower (Upper);"
+ "::NFD(NFKC);"
+ "\\u03B1 > a;"
+ "::Lower(Lower);"
+ "::NFC(NFKD);"
+ ;
+ UnicodeString source = CharsToUnicodeString("\\u00E1"); // a-acute
+ UnicodeString target = CharsToUnicodeString("\\u03AC"); // alpha-acute
+
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t2 = Transliterator::createFromRules("source-target", testRules, UTRANS_FORWARD, pe, ec);
+ Transliterator *t3 = Transliterator::createFromRules("target-source", testRules, UTRANS_REVERSE, pe, ec);
+
+ if (U_FAILURE(ec)) {
+ delete t2;
+ delete t3;
+ errln((UnicodeString)"FAIL: createFromRules => " + u_errorName(ec));
+ return;
+ }
+
+ expect(*t2, source, target);
+ expect(*t3, target, source);
+
+ checkRules("Failed toRules FORWARD", *t2, testRulesForward);
+ checkRules("Failed toRules BACKWARD", *t3, testRulesBackward);
+
+ delete t2;
+ delete t3;
+}
+
+/**
+ * Test Escape and Unescape transliterators.
+ */
+void TransliteratorTest::TestEscape() {
+ UParseError pe;
+ UErrorCode ec;
+ Transliterator *t;
+
+ ec = U_ZERO_ERROR;
+ t = Transliterator::createInstance("Hex-Any", UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createInstance");
+ } else {
+ expect(*t,
+ "\\x{40}\\U00000031&#x32;&#81;",
+ "@12Q");
+ }
+ delete t;
+
+ ec = U_ZERO_ERROR;
+ t = Transliterator::createInstance("Any-Hex/C", UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createInstance");
+ } else {
+ expect(*t,
+ CharsToUnicodeString("A\\U0010BEEF\\uFEED"),
+ "\\u0041\\U0010BEEF\\uFEED");
+ }
+ delete t;
+
+ ec = U_ZERO_ERROR;
+ t = Transliterator::createInstance("Any-Hex/Java", UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createInstance");
+ } else {
+ expect(*t,
+ CharsToUnicodeString("A\\U0010BEEF\\uFEED"),
+ "\\u0041\\uDBEF\\uDEEF\\uFEED");
+ }
+ delete t;
+
+ ec = U_ZERO_ERROR;
+ t = Transliterator::createInstance("Any-Hex/Perl", UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createInstance");
+ } else {
+ expect(*t,
+ CharsToUnicodeString("A\\U0010BEEF\\uFEED"),
+ "\\x{41}\\x{10BEEF}\\x{FEED}");
+ }
+ delete t;
+}
+
+
+void TransliteratorTest::TestAnchorMasking(){
+ UnicodeString rule ("^a > Q; a > q;");
+ UErrorCode status= U_ZERO_ERROR;
+ UParseError parseError;
+
+ Transliterator* t = Transliterator::createFromRules("ID", rule, UTRANS_FORWARD,parseError,status);
+ if(U_FAILURE(status)){
+ errln(UnicodeString("FAIL: ") + "ID" +
+ ".createFromRules() => bad rules" +
+ /*", parse error " + parseError.code +*/
+ ", line " + parseError.line +
+ ", offset " + parseError.offset +
+ ", context " + prettify(parseError.preContext, TRUE) +
+ ", rules: " + prettify(rule, TRUE));
+ }
+ delete t;
+}
+
+/**
+ * Make sure display names of variants look reasonable.
+ */
+void TransliteratorTest::TestDisplayName() {
+#if UCONFIG_NO_FORMATTING
+ logln("Skipping, UCONFIG_NO_FORMATTING is set\n");
+ return;
+#else
+ static const char* DATA[] = {
+ // ID, forward name, reverse name
+ // Update the text as necessary -- the important thing is
+ // not the text itself, but how various cases are handled.
+
+ // Basic test
+ "Any-Hex", "Any to Hex Escape", "Hex Escape to Any",
+
+ // Variants
+ "Any-Hex/Perl", "Any to Hex Escape/Perl", "Hex Escape to Any/Perl",
+
+ // Target-only IDs
+ "NFC", "Any to NFC", "Any to NFD",
+ };
+
+ int32_t DATA_length = sizeof(DATA) / sizeof(DATA[0]);
+
+ Locale US("en", "US");
+
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ UnicodeString name;
+ Transliterator::getDisplayName(DATA[i], US, name);
+ if (name != DATA[i+1]) {
+ errln((UnicodeString)"FAIL: " + DATA[i] + ".getDisplayName() => " +
+ name + ", expected " + DATA[i+1]);
+ } else {
+ logln((UnicodeString)"Ok: " + DATA[i] + ".getDisplayName() => " + name);
+ }
+ UErrorCode ec = U_ZERO_ERROR;
+ UParseError pe;
+ Transliterator *t = Transliterator::createInstance(DATA[i], UTRANS_REVERSE, pe, ec);
+ if (U_FAILURE(ec)) {
+ delete t;
+ errln("FAIL: createInstance failed");
+ continue;
+ }
+ name = Transliterator::getDisplayName(t->getID(), US, name);
+ if (name != DATA[i+2]) {
+ errln((UnicodeString)"FAIL: " + t->getID() + ".getDisplayName() => " +
+ name + ", expected " + DATA[i+2]);
+ } else {
+ logln((UnicodeString)"Ok: " + t->getID() + ".getDisplayName() => " + name);
+ }
+ delete t;
+ }
+#endif
+}
+
+void TransliteratorTest::TestSpecialCases(void) {
+ const UnicodeString registerRules[] = {
+ "Any-Dev1", "x > X; y > Y;",
+ "Any-Dev2", "XY > Z",
+ "Greek-Latin/FAKE",
+ CharsToUnicodeString
+ ("[^[:L:][:M:]] { \\u03bc\\u03c0 > b ; \\u03bc\\u03c0 } [^[:L:][:M:]] > b ; [^[:L:][:M:]] { [\\u039c\\u03bc][\\u03a0\\u03c0] > B ; [\\u039c\\u03bc][\\u03a0\\u03c0] } [^[:L:][:M:]] > B ;"),
+ "" // END MARKER
+ };
+
+ const UnicodeString testCases[] = {
+ // NORMALIZATION
+ // should add more test cases
+ "NFD" , CharsToUnicodeString("a\\u0300 \\u00E0 \\u1100\\u1161 \\uFF76\\uFF9E\\u03D3"), "",
+ "NFC" , CharsToUnicodeString("a\\u0300 \\u00E0 \\u1100\\u1161 \\uFF76\\uFF9E\\u03D3"), "",
+ "NFKD", CharsToUnicodeString("a\\u0300 \\u00E0 \\u1100\\u1161 \\uFF76\\uFF9E\\u03D3"), "",
+ "NFKC", CharsToUnicodeString("a\\u0300 \\u00E0 \\u1100\\u1161 \\uFF76\\uFF9E\\u03D3"), "",
+
+ // mp -> b BUG
+ "Greek-Latin/UNGEGN", CharsToUnicodeString("(\\u03BC\\u03C0)"), "(b)",
+ "Greek-Latin/FAKE", CharsToUnicodeString("(\\u03BC\\u03C0)"), "(b)",
+
+ // check for devanagari bug
+ "nfd;Dev1;Dev2;nfc", "xy", "Z",
+
+ // ff, i, dotless-i, I, dotted-I, LJLjlj deseret deeDEE
+ "Title", CharsToUnicodeString("ab'cD ffi\\u0131I\\u0130 \\u01C7\\u01C8\\u01C9 ") + DESERET_dee + DESERET_DEE,
+ CharsToUnicodeString("Ab'cd Ffi\\u0131ii\\u0307 \\u01C8\\u01C9\\u01C9 ") + DESERET_DEE + DESERET_dee,
+
+ //TODO: enable this test once Titlecase works right
+ /*
+ "Title", CharsToUnicodeString("\\uFB00i\\u0131I\\u0130 \\u01C7\\u01C8\\u01C9 ") + DESERET_dee + DESERET_DEE,
+ CharsToUnicodeString("Ffi\\u0131ii \\u01C8\\u01C9\\u01C9 ") + DESERET_DEE + DESERET_dee,
+ */
+ "Upper", CharsToUnicodeString("ab'cD \\uFB00i\\u0131I\\u0130 \\u01C7\\u01C8\\u01C9 ") + DESERET_dee + DESERET_DEE,
+ CharsToUnicodeString("AB'CD FFIII\\u0130 \\u01C7\\u01C7\\u01C7 ") + DESERET_DEE + DESERET_DEE,
+ "Lower", CharsToUnicodeString("ab'cD \\uFB00i\\u0131I\\u0130 \\u01C7\\u01C8\\u01C9 ") + DESERET_dee + DESERET_DEE,
+ CharsToUnicodeString("ab'cd \\uFB00i\\u0131ii\\u0307 \\u01C9\\u01C9\\u01C9 ") + DESERET_dee + DESERET_dee,
+
+ "Upper", CharsToUnicodeString("ab'cD \\uFB00i\\u0131I\\u0130 \\u01C7\\u01C8\\u01C9 ") + DESERET_dee + DESERET_DEE, "",
+ "Lower", CharsToUnicodeString("ab'cD \\uFB00i\\u0131I\\u0130 \\u01C7\\u01C8\\u01C9 ") + DESERET_dee + DESERET_DEE, "",
+
+ // FORMS OF S
+ "Greek-Latin/UNGEGN", CharsToUnicodeString("\\u03C3 \\u03C3\\u03C2 \\u03C2\\u03C3"),
+ CharsToUnicodeString("s ss s\\u0331s\\u0331") ,
+ "Latin-Greek/UNGEGN", CharsToUnicodeString("s ss s\\u0331s\\u0331"),
+ CharsToUnicodeString("\\u03C3 \\u03C3\\u03C2 \\u03C2\\u03C3") ,
+ "Greek-Latin", CharsToUnicodeString("\\u03C3 \\u03C3\\u03C2 \\u03C2\\u03C3"),
+ CharsToUnicodeString("s ss s\\u0331s\\u0331") ,
+ "Latin-Greek", CharsToUnicodeString("s ss s\\u0331s\\u0331"),
+ CharsToUnicodeString("\\u03C3 \\u03C3\\u03C2 \\u03C2\\u03C3"),
+ // Tatiana bug
+ // Upper: TAT\\u02B9\\u00C2NA
+ // Lower: tat\\u02B9\\u00E2na
+ // Title: Tat\\u02B9\\u00E2na
+ "Upper", CharsToUnicodeString("tat\\u02B9\\u00E2na"),
+ CharsToUnicodeString("TAT\\u02B9\\u00C2NA"),
+ "Lower", CharsToUnicodeString("TAT\\u02B9\\u00C2NA"),
+ CharsToUnicodeString("tat\\u02B9\\u00E2na"),
+ "Title", CharsToUnicodeString("tat\\u02B9\\u00E2na"),
+ CharsToUnicodeString("Tat\\u02B9\\u00E2na"),
+
+ "" // END MARKER
+ };
+
+ UParseError pos;
+ int32_t i;
+ for (i = 0; registerRules[i].length()!=0; i+=2) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ Transliterator *t = Transliterator::createFromRules(registerRules[0+i],
+ registerRules[i+1], UTRANS_FORWARD, pos, status);
+ if (U_FAILURE(status)) {
+ errln("Fails: Unable to create the transliterator from rules.");
+ } else {
+ Transliterator::registerInstance(t);
+ }
+ }
+ for (i = 0; testCases[i].length()!=0; i+=3) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UParseError pe;
+ const UnicodeString& name = testCases[i];
+ Transliterator *t = Transliterator::createInstance(name, UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: Couldn't create " + name);
+ delete t;
+ continue;
+ }
+ const UnicodeString& id = t->getID();
+ const UnicodeString& source = testCases[i+1];
+ UnicodeString target;
+
+ // Automatic generation of targets, to make it simpler to add test cases (and more fail-safe)
+
+ if (testCases[i+2].length() > 0) {
+ target = testCases[i+2];
+ } else if (0==id.caseCompare("NFD", U_FOLD_CASE_DEFAULT)) {
+ Normalizer::normalize(source, UNORM_NFD, 0, target, ec);
+ } else if (0==id.caseCompare("NFC", U_FOLD_CASE_DEFAULT)) {
+ Normalizer::normalize(source, UNORM_NFC, 0, target, ec);
+ } else if (0==id.caseCompare("NFKD", U_FOLD_CASE_DEFAULT)) {
+ Normalizer::normalize(source, UNORM_NFKD, 0, target, ec);
+ } else if (0==id.caseCompare("NFKC", U_FOLD_CASE_DEFAULT)) {
+ Normalizer::normalize(source, UNORM_NFKC, 0, target, ec);
+ } else if (0==id.caseCompare("Lower", U_FOLD_CASE_DEFAULT)) {
+ target = source;
+ target.toLower(Locale::getUS());
+ } else if (0==id.caseCompare("Upper", U_FOLD_CASE_DEFAULT)) {
+ target = source;
+ target.toUpper(Locale::getUS());
+ }
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: Internal error normalizing " + source);
+ continue;
+ }
+
+ expect(*t, source, target);
+ delete t;
+ }
+ for (i = 0; registerRules[i].length()!=0; i+=2) {
+ Transliterator::unregister(registerRules[i]);
+ }
+}
+
+char* Char32ToEscapedChars(UChar32 ch, char* buffer) {
+ if (ch <= 0xFFFF) {
+ sprintf(buffer, "\\u%04x", (int)ch);
+ } else {
+ sprintf(buffer, "\\U%08x", (int)ch);
+ }
+ return buffer;
+}
+
+void TransliteratorTest::TestSurrogateCasing (void) {
+ // check that casing handles surrogates
+ // titlecase is currently defective
+ char buffer[20];
+ UChar buffer2[20];
+ UChar32 dee;
+ UTF_GET_CHAR(DESERET_dee,0, 0, DESERET_dee.length(), dee);
+ UnicodeString DEE(u_totitle(dee));
+ if (DEE != DESERET_DEE) {
+ err("Fails titlecase of surrogates");
+ err(Char32ToEscapedChars(dee, buffer));
+ err(", ");
+ errln(Char32ToEscapedChars(DEE.char32At(0), buffer));
+ }
+
+ UnicodeString deeDEETest=DESERET_dee + DESERET_DEE;
+ UnicodeString deedeeTest = DESERET_dee + DESERET_dee;
+ UnicodeString DEEDEETest = DESERET_DEE + DESERET_DEE;
+ UErrorCode status= U_ZERO_ERROR;
+
+ u_strToUpper(buffer2, 20, deeDEETest.getBuffer(), deeDEETest.length(), NULL, &status);
+ if (U_FAILURE(status) || (UnicodeString(buffer2)!= DEEDEETest)) {
+ errln("Fails: Can't uppercase surrogates.");
+ }
+
+ status= U_ZERO_ERROR;
+ u_strToLower(buffer2, 20, deeDEETest.getBuffer(), deeDEETest.length(), NULL, &status);
+ if (U_FAILURE(status) || (UnicodeString(buffer2)!= deedeeTest)) {
+ errln("Fails: Can't lowercase surrogates.");
+ }
+}
+
+static void _trans(Transliterator& t, const UnicodeString& src,
+ UnicodeString& result) {
+ result = src;
+ t.transliterate(result);
+}
+
+static void _trans(const UnicodeString& id, const UnicodeString& src,
+ UnicodeString& result, UErrorCode ec) {
+ UParseError pe;
+ Transliterator *t = Transliterator::createInstance(id, UTRANS_FORWARD, pe, ec);
+ if (U_SUCCESS(ec)) {
+ _trans(*t, src, result);
+ }
+ delete t;
+}
+
+static UnicodeString _findMatch(const UnicodeString& source,
+ const UnicodeString* pairs) {
+ UnicodeString empty;
+ for (int32_t i=0; pairs[i].length() > 0; i+=2) {
+ if (0==source.caseCompare(pairs[i], U_FOLD_CASE_DEFAULT)) {
+ return pairs[i+1];
+ }
+ }
+ return empty;
+}
+
+// Check to see that incremental gets at least part way through a reasonable string.
+
+void TransliteratorTest::TestIncrementalProgress(void) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString latinTest = "The Quick Brown Fox.";
+ UnicodeString devaTest;
+ _trans("Latin-Devanagari", latinTest, devaTest, ec);
+ UnicodeString kataTest;
+ _trans("Latin-Katakana", latinTest, kataTest, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Internal error");
+ return;
+ }
+ const UnicodeString tests[] = {
+ "Any", latinTest,
+ "Latin", latinTest,
+ "Halfwidth", latinTest,
+ "Devanagari", devaTest,
+ "Katakana", kataTest,
+ "" // END MARKER
+ };
+
+ UnicodeString test("The Quick Brown Fox Jumped Over The Lazy Dog.");
+ int32_t i = 0, j=0, k=0;
+ int32_t sources = Transliterator::countAvailableSources();
+ for (i = 0; i < sources; i++) {
+ UnicodeString source;
+ Transliterator::getAvailableSource(i, source);
+ UnicodeString test = _findMatch(source, tests);
+ if (test.length() == 0) {
+ logln((UnicodeString)"Skipping " + source + "-X");
+ continue;
+ }
+ int32_t targets = Transliterator::countAvailableTargets(source);
+ for (j = 0; j < targets; j++) {
+ UnicodeString target;
+ Transliterator::getAvailableTarget(j, source, target);
+ int32_t variants = Transliterator::countAvailableVariants(source, target);
+ for (k =0; k< variants; k++) {
+ UnicodeString variant;
+ UParseError err;
+ UErrorCode status = U_ZERO_ERROR;
+
+ Transliterator::getAvailableVariant(k, source, target, variant);
+ UnicodeString id = source + "-" + target + "/" + variant;
+
+ if(id.indexOf("Thai")>-1 && !isICUVersionAtLeast(ICU_39)){
+ /* The Thai-Latin transliterator doesn't exist in ICU4C yet */
+ continue;
+ }
+ Transliterator *t = Transliterator::createInstance(id, UTRANS_FORWARD, err, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: Could not create " + id);
+ delete t;
+ continue;
+ }
+ status = U_ZERO_ERROR;
+ CheckIncrementalAux(t, test);
+
+ UnicodeString rev;
+ _trans(*t, test, rev);
+ Transliterator *inv = t->createInverse(status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: Could not create inverse of " + id);
+ delete t;
+ delete inv;
+ continue;
+ }
+ CheckIncrementalAux(inv, rev);
+ delete t;
+ delete inv;
+ }
+ }
+ }
+}
+
+void TransliteratorTest::CheckIncrementalAux(const Transliterator* t,
+ const UnicodeString& input) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UTransPosition pos;
+ UnicodeString test = input;
+
+ pos.contextStart = 0;
+ pos.contextLimit = input.length();
+ pos.start = 0;
+ pos.limit = input.length();
+
+ t->transliterate(test, pos, ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: transliterate() error " + u_errorName(ec));
+ return;
+ }
+ UBool gotError = FALSE;
+
+ // we have a few special cases. Any-Remove (pos.start = 0, but also = limit) and U+XXXXX?X?
+
+ if (pos.start == 0 && pos.limit != 0 && t->getID() != "Hex-Any/Unicode") {
+ errln((UnicodeString)"No Progress, " +
+ t->getID() + ": " + formatInput(test, input, pos));
+ gotError = TRUE;
+ } else {
+ logln((UnicodeString)"PASS Progress, " +
+ t->getID() + ": " + formatInput(test, input, pos));
+ }
+ t->finishTransliteration(test, pos);
+ if (pos.start != pos.limit) {
+ errln((UnicodeString)"Incomplete, " +
+ t->getID() + ": " + formatInput(test, input, pos));
+ gotError = TRUE;
+ }
+}
+
+void TransliteratorTest::TestFunction() {
+ // Careful with spacing and ';' here: Phrase this exactly
+ // as toRules() is going to return it. If toRules() changes
+ // with regard to spacing or ';', then adjust this string.
+ UnicodeString rule =
+ "([:Lu:]) > $1 '(' &Lower( $1 ) '=' &Hex( &Any-Lower( $1 ) ) ')';";
+
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("Test", rule, UTRANS_FORWARD, pe, ec);
+ if (t == NULL) {
+ errln("FAIL: createFromRules failed");
+ return;
+ }
+
+ UnicodeString r;
+ t->toRules(r, TRUE);
+ if (r == rule) {
+ logln((UnicodeString)"OK: toRules() => " + r);
+ } else {
+ errln((UnicodeString)"FAIL: toRules() => " + r +
+ ", expected " + rule);
+ }
+
+ expect(*t, "The Quick Brown Fox",
+ "T(t=\\u0074)he Q(q=\\u0071)uick B(b=\\u0062)rown F(f=\\u0066)ox");
+
+ delete t;
+}
+
+void TransliteratorTest::TestInvalidBackRef(void) {
+ UnicodeString rule = ". > $1;";
+ UnicodeString rule2 =CharsToUnicodeString("(.) <> &hex/unicode($1) &name($1); . > $1; [{}] >\\u0020;");
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator *t = Transliterator::createFromRules("Test", rule, UTRANS_FORWARD, pe, ec);
+ Transliterator *t2 = Transliterator::createFromRules("Test2", rule2, UTRANS_FORWARD, pe, ec);
+
+ if (t != NULL) {
+ errln("FAIL: createFromRules should have returned NULL");
+ delete t;
+ }
+
+ if (t2 != NULL) {
+ errln("FAIL: createFromRules should have returned NULL");
+ delete t2;
+ }
+
+ if (U_SUCCESS(ec)) {
+ errln("FAIL: Ok: . > $1; => no error");
+ } else {
+ logln((UnicodeString)"Ok: . > $1; => " + u_errorName(ec));
+ }
+}
+
+void TransliteratorTest::TestMulticharStringSet() {
+ // Basic testing
+ const char* rule =
+ " [{aa}] > x;"
+ " a > y;"
+ " [b{bc}] > z;"
+ "[{gd}] { e > q;"
+ " e } [{fg}] > r;" ;
+
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+ Transliterator* t = Transliterator::createFromRules("Test", rule, UTRANS_FORWARD, pe, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ delete t;
+ errln("FAIL: createFromRules failed");
+ return;
+ }
+
+ expect(*t, "a aa ab bc d gd de gde gdefg ddefg",
+ "y x yz z d gd de gdq gdqfg ddrfg");
+ delete t;
+
+ // Overlapped string test. Make sure that when multiple
+ // strings can match that the longest one is matched.
+ rule =
+ " [a {ab} {abc}] > x;"
+ " b > y;"
+ " c > z;"
+ " q [t {st} {rst}] { e > p;" ;
+
+ t = Transliterator::createFromRules("Test", rule, UTRANS_FORWARD, pe, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ delete t;
+ errln("FAIL: createFromRules failed");
+ return;
+ }
+
+ expect(*t, "a ab abc qte qste qrste",
+ "x x x qtp qstp qrstp");
+ delete t;
+}
+
+// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+// BEGIN TestUserFunction support factory
+
+Transliterator* _TUFF[4];
+UnicodeString* _TUFID[4];
+
+static Transliterator* U_EXPORT2 _TUFFactory(const UnicodeString& /*ID*/,
+ Transliterator::Token context) {
+ return _TUFF[context.integer]->clone();
+}
+
+static void _TUFReg(const UnicodeString& ID, Transliterator* t, int32_t n) {
+ _TUFF[n] = t;
+ _TUFID[n] = new UnicodeString(ID);
+ Transliterator::registerFactory(ID, _TUFFactory, Transliterator::integerToken(n));
+}
+
+static void _TUFUnreg(int32_t n) {
+ if (_TUFF[n] != NULL) {
+ Transliterator::unregister(*_TUFID[n]);
+ delete _TUFF[n];
+ delete _TUFID[n];
+ }
+}
+
+// END TestUserFunction support factory
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+/**
+ * Test that user-registered transliterators can be used under function
+ * syntax.
+ */
+void TransliteratorTest::TestUserFunction() {
+
+ Transliterator* t;
+ UParseError pe;
+ UErrorCode ec = U_ZERO_ERROR;
+
+ // Setup our factory
+ int32_t i;
+ for (i=0; i<4; ++i) {
+ _TUFF[i] = NULL;
+ }
+
+ // There's no need to register inverses if we don't use them
+ t = Transliterator::createFromRules("gif",
+ "'\\'u(..)(..) > '<img src=\"http://www.unicode.org/gifs/24/' $1 '/U' $1$2 '.gif\">';",
+ UTRANS_FORWARD, pe, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createFromRules gif " + u_errorName(ec));
+ return;
+ }
+ _TUFReg("Any-gif", t, 0);
+
+ t = Transliterator::createFromRules("RemoveCurly",
+ "[\\{\\}] > ; '\\N' > ;",
+ UTRANS_FORWARD, pe, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createFromRules RemoveCurly " + u_errorName(ec));
+ goto FAIL;
+ }
+ expect(*t, "\\N{name}", "name");
+ _TUFReg("Any-RemoveCurly", t, 1);
+
+ logln("Trying &hex");
+ t = Transliterator::createFromRules("hex2",
+ "(.) > &hex($1);",
+ UTRANS_FORWARD, pe, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ errln("FAIL: createFromRules");
+ goto FAIL;
+ }
+ logln("Registering");
+ _TUFReg("Any-hex2", t, 2);
+ t = Transliterator::createInstance("Any-hex2", UTRANS_FORWARD, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createInstance Any-hex2 " + u_errorName(ec));
+ goto FAIL;
+ }
+ expect(*t, "abc", "\\u0061\\u0062\\u0063");
+ delete t;
+
+ logln("Trying &gif");
+ t = Transliterator::createFromRules("gif2",
+ "(.) > &Gif(&Hex2($1));",
+ UTRANS_FORWARD, pe, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createFromRules gif2 " + u_errorName(ec));
+ goto FAIL;
+ }
+ logln("Registering");
+ _TUFReg("Any-gif2", t, 3);
+ t = Transliterator::createInstance("Any-gif2", UTRANS_FORWARD, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createInstance Any-gif2 " + u_errorName(ec));
+ goto FAIL;
+ }
+ expect(*t, "ab", "<img src=\"http://www.unicode.org/gifs/24/00/U0061.gif\">"
+ "<img src=\"http://www.unicode.org/gifs/24/00/U0062.gif\">");
+ delete t;
+
+ // Test that filters are allowed after &
+ t = Transliterator::createFromRules("test",
+ "(.) > &Hex($1) ' ' &RemoveCurly(&Name($1)) ' ';",
+ UTRANS_FORWARD, pe, ec);
+ if (t == NULL || U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: createFromRules test " + u_errorName(ec));
+ goto FAIL;
+ }
+ expect(*t, "abc",
+ "\\u0061 LATIN SMALL LETTER A \\u0062 LATIN SMALL LETTER B \\u0063 LATIN SMALL LETTER C ");
+ delete t;
+
+ FAIL:
+ for (i=0; i<4; ++i) {
+ _TUFUnreg(i);
+ }
+}
+
+/**
+ * Test the Any-X transliterators.
+ */
+void TransliteratorTest::TestAnyX(void) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* anyLatin =
+ Transliterator::createInstance("Any-Latin", UTRANS_FORWARD, parseError, status);
+ if (anyLatin==0) {
+ errln("FAIL: createInstance returned NULL");
+ delete anyLatin;
+ return;
+ }
+
+ expect(*anyLatin,
+ CharsToUnicodeString("greek:\\u03B1\\u03B2\\u03BA\\u0391\\u0392\\u039A hiragana:\\u3042\\u3076\\u304F cyrillic:\\u0430\\u0431\\u0446"),
+ CharsToUnicodeString("greek:abkABK hiragana:abuku cyrillic:abc"));
+
+ delete anyLatin;
+}
+
+/**
+ * Test the source and target set API. These are only implemented
+ * for RBT and CompoundTransliterator at this time.
+ */
+void TransliteratorTest::TestSourceTargetSet() {
+ UErrorCode ec = U_ZERO_ERROR;
+
+ // Rules
+ const char* r =
+ "a > b; "
+ "r [x{lu}] > q;";
+
+ // Expected source
+ UnicodeSet expSrc("[arx{lu}]", ec);
+
+ // Expected target
+ UnicodeSet expTrg("[bq]", ec);
+
+ UParseError pe;
+ Transliterator* t = Transliterator::createFromRules("test", r, UTRANS_FORWARD, pe, ec);
+
+ if (U_FAILURE(ec)) {
+ delete t;
+ errln("FAIL: Couldn't set up test");
+ return;
+ }
+
+ UnicodeSet src; t->getSourceSet(src);
+ UnicodeSet trg; t->getTargetSet(trg);
+
+ if (src == expSrc && trg == expTrg) {
+ UnicodeString a, b;
+ logln((UnicodeString)"Ok: " +
+ r + " => source = " + src.toPattern(a, TRUE) +
+ ", target = " + trg.toPattern(b, TRUE));
+ } else {
+ UnicodeString a, b, c, d;
+ errln((UnicodeString)"FAIL: " +
+ r + " => source = " + src.toPattern(a, TRUE) +
+ ", expected " + expSrc.toPattern(b, TRUE) +
+ "; target = " + trg.toPattern(c, TRUE) +
+ ", expected " + expTrg.toPattern(d, TRUE));
+ }
+
+ delete t;
+}
+
+/**
+ * Test handling of rule whitespace, for both RBT and UnicodeSet.
+ */
+void TransliteratorTest::TestRuleWhitespace() {
+ // Rules
+ const char* r = "a > \\u200E b;";
+
+ UErrorCode ec = U_ZERO_ERROR;
+ UParseError pe;
+ Transliterator* t = Transliterator::createFromRules("test", CharsToUnicodeString(r), UTRANS_FORWARD, pe, ec);
+
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Couldn't set up test");
+ } else {
+ expect(*t, "a", "b");
+ }
+ delete t;
+
+ // UnicodeSet
+ ec = U_ZERO_ERROR;
+ UnicodeSet set(CharsToUnicodeString("[a \\u200E]"), ec);
+
+ if (U_FAILURE(ec)) {
+ errln("FAIL: Couldn't set up test");
+ } else {
+ if (set.contains(0x200E)) {
+ errln("FAIL: U+200E not being ignored by UnicodeSet");
+ }
+ }
+}
+//======================================================================
+// this method is in TestUScript.java
+//======================================================================
+void TransliteratorTest::TestAllCodepoints(){
+ UScriptCode code= USCRIPT_INVALID_CODE;
+ char id[256]={'\0'};
+ char abbr[256]={'\0'};
+ char newId[256]={'\0'};
+ char newAbbrId[256]={'\0'};
+ char oldId[256]={'\0'};
+ char oldAbbrId[256]={'\0'};
+
+ UErrorCode status =U_ZERO_ERROR;
+ UParseError pe;
+
+ for(uint32_t i = 0; i<=0x10ffff; i++){
+ code = uscript_getScript(i,&status);
+ if(code == USCRIPT_INVALID_CODE){
+ errln("uscript_getScript for codepoint \\U%08X failed.\n", i);
+ }
+ const char* myId = uscript_getName(code);
+ if(!myId) {
+ errln("Valid script code returned NULL name. Check your data!");
+ return;
+ }
+ uprv_strcpy(id,myId);
+ uprv_strcpy(abbr,uscript_getShortName(code));
+
+ uprv_strcpy(newId,"[:");
+ uprv_strcat(newId,id);
+ uprv_strcat(newId,":];NFD");
+
+ uprv_strcpy(newAbbrId,"[:");
+ uprv_strcat(newAbbrId,abbr);
+ uprv_strcat(newAbbrId,":];NFD");
+
+ if(uprv_strcmp(newId,oldId)!=0){
+ Transliterator* t = Transliterator::createInstance(newId,UTRANS_FORWARD,pe,status);
+ if(t==NULL || U_FAILURE(status)){
+ errln((UnicodeString)"FAIL: Could not create " + id);
+ }
+ delete t;
+ }
+ if(uprv_strcmp(newAbbrId,oldAbbrId)!=0){
+ Transliterator* t = Transliterator::createInstance(newAbbrId,UTRANS_FORWARD,pe,status);
+ if(t==NULL || U_FAILURE(status)){
+ errln((UnicodeString)"FAIL: Could not create " + id);
+ }
+ delete t;
+ }
+ uprv_strcpy(oldId,newId);
+ uprv_strcpy(oldAbbrId, newAbbrId);
+
+ }
+
+}
+
+#define TEST_TRANSLIT_ID(id, cls) { \
+ UErrorCode ec = U_ZERO_ERROR; \
+ Transliterator* t = Transliterator::createInstance(id, UTRANS_FORWARD, ec); \
+ if (U_FAILURE(ec)) { \
+ errln("FAIL: Couldn't create " id); \
+ } else { \
+ if (t->getDynamicClassID() != cls::getStaticClassID()) { \
+ errln("FAIL: " #cls " dynamic and static class ID mismatch"); \
+ } \
+ /* *t = *t; */ /*can't do this: coverage test for assignment op*/ \
+ } \
+ delete t; \
+}
+
+#define TEST_TRANSLIT_RULE(rule, cls) { \
+ UErrorCode ec = U_ZERO_ERROR; \
+ UParseError pe; \
+ Transliterator* t = Transliterator::createFromRules("_", rule, UTRANS_FORWARD, pe, ec); \
+ if (U_FAILURE(ec)) { \
+ errln("FAIL: Couldn't create " rule); \
+ } else { \
+ if (t->getDynamicClassID() != cls ::getStaticClassID()) { \
+ errln("FAIL: " #cls " dynamic and static class ID mismatch"); \
+ } \
+ /* *t = *t; */ /*can't do this: coverage test for assignment op*/ \
+ } \
+ delete t; \
+}
+
+void TransliteratorTest::TestBoilerplate() {
+ TEST_TRANSLIT_ID("Any-Latin", AnyTransliterator);
+ TEST_TRANSLIT_ID("Any-Hex", EscapeTransliterator);
+ TEST_TRANSLIT_ID("Hex-Any", UnescapeTransliterator);
+ TEST_TRANSLIT_ID("Lower", LowercaseTransliterator);
+ TEST_TRANSLIT_ID("Upper", UppercaseTransliterator);
+ TEST_TRANSLIT_ID("Title", TitlecaseTransliterator);
+ TEST_TRANSLIT_ID("Null", NullTransliterator);
+ TEST_TRANSLIT_ID("Remove", RemoveTransliterator);
+ TEST_TRANSLIT_ID("Any-Name", UnicodeNameTransliterator);
+ TEST_TRANSLIT_ID("Name-Any", NameUnicodeTransliterator);
+ TEST_TRANSLIT_ID("NFD", NormalizationTransliterator);
+ TEST_TRANSLIT_ID("Latin-Greek", CompoundTransliterator);
+ TEST_TRANSLIT_RULE("a>b;", RuleBasedTransliterator);
+}
+
+void TransliteratorTest::TestAlternateSyntax() {
+ // U+2206 == &
+ // U+2190 == <
+ // U+2192 == >
+ // U+2194 == <>
+ expect(CharsToUnicodeString("a \\u2192 x; b \\u2190 y; c \\u2194 z"),
+ "abc",
+ "xbz");
+ expect(CharsToUnicodeString("([:^ASCII:]) \\u2192 \\u2206Name($1);"),
+ CharsToUnicodeString("<=\\u2190; >=\\u2192; <>=\\u2194; &=\\u2206"),
+ "<=\\N{LEFTWARDS ARROW}; >=\\N{RIGHTWARDS ARROW}; <>=\\N{LEFT RIGHT ARROW}; &=\\N{INCREMENT}");
+}
+
+static const char* BEGIN_END_RULES[] = {
+ // [0]
+ "abc > xy;"
+ "aba > z;",
+
+ // [1]
+/*
+ "::BEGIN;"
+ "abc > xy;"
+ "::END;"
+ "::BEGIN;"
+ "aba > z;"
+ "::END;",
+*/
+ "", // test case commented out below, this is here to keep from messing up the indexes
+
+ // [2]
+/*
+ "abc > xy;"
+ "::BEGIN;"
+ "aba > z;"
+ "::END;",
+*/
+ "", // test case commented out below, this is here to keep from messing up the indexes
+
+ // [3]
+/*
+ "::BEGIN;"
+ "abc > xy;"
+ "::END;"
+ "aba > z;",
+*/
+ "", // test case commented out below, this is here to keep from messing up the indexes
+
+ // [4]
+ "abc > xy;"
+ "::Null;"
+ "aba > z;",
+
+ // [5]
+ "::Upper;"
+ "ABC > xy;"
+ "AB > x;"
+ "C > z;"
+ "::Upper;"
+ "XYZ > p;"
+ "XY > q;"
+ "Z > r;"
+ "::Upper;",
+
+ // [6]
+ "$ws = [[:Separator:][\\u0009-\\u000C]$];"
+ "$delim = [\\-$ws];"
+ "$ws $delim* > ' ';"
+ "'-' $delim* > '-';",
+
+ // [7]
+ "::Null;"
+ "$ws = [[:Separator:][\\u0009-\\u000C]$];"
+ "$delim = [\\-$ws];"
+ "$ws $delim* > ' ';"
+ "'-' $delim* > '-';",
+
+ // [8]
+ "$ws = [[:Separator:][\\u0009-\\u000C]$];"
+ "$delim = [\\-$ws];"
+ "$ws $delim* > ' ';"
+ "'-' $delim* > '-';"
+ "::Null;",
+
+ // [9]
+ "$ws = [[:Separator:][\\u0009-\\u000C]$];"
+ "$delim = [\\-$ws];"
+ "::Null;"
+ "$ws $delim* > ' ';"
+ "'-' $delim* > '-';",
+
+ // [10]
+/*
+ "::BEGIN;"
+ "$ws = [[:Separator:][\\u0009-\\u000C]$];"
+ "$delim = [\\-$ws];"
+ "::END;"
+ "$ws $delim* > ' ';"
+ "'-' $delim* > '-';",
+*/
+ "", // test case commented out below, this is here to keep from messing up the indexes
+
+ // [11]
+/*
+ "$ws = [[:Separator:][\\u0009-\\u000C]$];"
+ "$delim = [\\-$ws];"
+ "::BEGIN;"
+ "$ws $delim* > ' ';"
+ "'-' $delim* > '-';"
+ "::END;",
+*/
+ "", // test case commented out below, this is here to keep from messing up the indexes
+
+ // [12]
+/*
+ "$ws = [[:Separator:][\\u0009-\\u000C]$];"
+ "$delim = [\\-$ws];"
+ "$ab = [ab];"
+ "::BEGIN;"
+ "$ws $delim* > ' ';"
+ "'-' $delim* > '-';"
+ "::END;"
+ "::BEGIN;"
+ "$ab { ' ' } $ab > '-';"
+ "c { ' ' > ;"
+ "::END;"
+ "::BEGIN;"
+ "'a-a' > a\\%|a;"
+ "::END;",
+*/
+ "", // test case commented out below, this is here to keep from messing up the indexes
+
+ // [13]
+ "$ws = [[:Separator:][\\u0009-\\u000C]$];"
+ "$delim = [\\-$ws];"
+ "$ab = [ab];"
+ "::Null;"
+ "$ws $delim* > ' ';"
+ "'-' $delim* > '-';"
+ "::Null;"
+ "$ab { ' ' } $ab > '-';"
+ "c { ' ' > ;"
+ "::Null;"
+ "'a-a' > a\\%|a;",
+
+ // [14]
+/*
+ "::[abc];"
+ "::BEGIN;"
+ "abc > xy;"
+ "::END;"
+ "::BEGIN;"
+ "aba > yz;"
+ "::END;"
+ "::Upper;",
+*/
+ "", // test case commented out below, this is here to keep from messing up the indexes
+
+ // [15]
+ "::[abc];"
+ "abc > xy;"
+ "::Null;"
+ "aba > yz;"
+ "::Upper;",
+
+ // [16]
+/*
+ "::[abc];"
+ "::BEGIN;"
+ "abc <> xy;"
+ "::END;"
+ "::BEGIN;"
+ "aba <> yz;"
+ "::END;"
+ "::Upper(Lower);"
+ "::([XYZ]);"
+*/
+ "", // test case commented out below, this is here to keep from messing up the indexes
+
+ // [17]
+ "::[abc];"
+ "abc <> xy;"
+ "::Null;"
+ "aba <> yz;"
+ "::Upper(Lower);"
+ "::([XYZ]);"
+};
+static const int32_t BEGIN_END_RULES_length = (int32_t)(sizeof(BEGIN_END_RULES) / sizeof(BEGIN_END_RULES[0]));
+
+/*
+(This entire test is commented out below and will need some heavy revision when we re-add
+the ::BEGIN/::END stuff)
+static const char* BOGUS_BEGIN_END_RULES[] = {
+ // [7]
+ "::BEGIN;"
+ "abc > xy;"
+ "::BEGIN;"
+ "aba > z;"
+ "::END;"
+ "::END;",
+
+ // [8]
+ "abc > xy;"
+ " aba > z;"
+ "::END;",
+
+ // [9]
+ "::BEGIN;"
+ "::Upper;"
+ "::END;"
+};
+static const int32_t BOGUS_BEGIN_END_RULES_length = (int32_t)(sizeof(BOGUS_BEGIN_END_RULES) / sizeof(BOGUS_BEGIN_END_RULES[0]));
+*/
+
+static const char* BEGIN_END_TEST_CASES[] = {
+ // rules input expected output
+ BEGIN_END_RULES[0], "abc ababc aba", "xy zbc z",
+// BEGIN_END_RULES[1], "abc ababc aba", "xy abxy z",
+// BEGIN_END_RULES[2], "abc ababc aba", "xy abxy z",
+// BEGIN_END_RULES[3], "abc ababc aba", "xy abxy z",
+ BEGIN_END_RULES[4], "abc ababc aba", "xy abxy z",
+ BEGIN_END_RULES[5], "abccabaacababcbc", "PXAARXQBR",
+
+ BEGIN_END_RULES[6], "e e - e---e- e", "e e e-e-e",
+ BEGIN_END_RULES[7], "e e - e---e- e", "e e e-e-e",
+ BEGIN_END_RULES[8], "e e - e---e- e", "e e e-e-e",
+ BEGIN_END_RULES[9], "e e - e---e- e", "e e e-e-e",
+// BEGIN_END_RULES[10], "e e - e---e- e", "e e e-e-e",
+// BEGIN_END_RULES[11], "e e - e---e- e", "e e e-e-e",
+// BEGIN_END_RULES[12], "e e - e---e- e", "e e e-e-e",
+// BEGIN_END_RULES[12], "a a a a", "a%a%a%a",
+// BEGIN_END_RULES[12], "a a-b c b a", "a%a-b cb-a",
+ BEGIN_END_RULES[13], "e e - e---e- e", "e e e-e-e",
+ BEGIN_END_RULES[13], "a a a a", "a%a%a%a",
+ BEGIN_END_RULES[13], "a a-b c b a", "a%a-b cb-a",
+
+// BEGIN_END_RULES[14], "abc xy ababc xyz aba", "XY xy ABXY xyz YZ",
+ BEGIN_END_RULES[15], "abc xy ababc xyz aba", "XY xy ABXY xyz YZ",
+// BEGIN_END_RULES[16], "abc xy ababc xyz aba", "XY xy ABXY xyz YZ",
+ BEGIN_END_RULES[17], "abc xy ababc xyz aba", "XY xy ABXY xyz YZ"
+};
+static const int32_t BEGIN_END_TEST_CASES_length = (int32_t)(sizeof(BEGIN_END_TEST_CASES) / sizeof(BEGIN_END_TEST_CASES[0]));
+
+void TransliteratorTest::TestBeginEnd() {
+ // run through the list of test cases above
+ int32_t i = 0;
+ for (i = 0; i < BEGIN_END_TEST_CASES_length; i += 3) {
+ expect((UnicodeString)"Test case #" + (i / 3),
+ UnicodeString(BEGIN_END_TEST_CASES[i]),
+ UnicodeString(BEGIN_END_TEST_CASES[i + 1]),
+ UnicodeString(BEGIN_END_TEST_CASES[i + 2]));
+ }
+
+ // instantiate the one reversible rule set in the reverse direction and make sure it does the right thing
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* reversed = Transliterator::createFromRules("Reversed", UnicodeString(BEGIN_END_RULES[17]),
+ UTRANS_REVERSE, parseError, status);
+ if (reversed == 0 || U_FAILURE(status)) {
+ reportParseError(UnicodeString("FAIL: Couldn't create reversed transliterator"), parseError, status);
+ } else {
+ expect(*reversed, UnicodeString("xy XY XYZ yz YZ"), UnicodeString("xy abc xaba yz aba"));
+ }
+ delete reversed;
+
+ // finally, run through the list of syntactically-ill-formed rule sets above and make sure
+ // that all of them cause errors
+/*
+(commented out until we have the real ::BEGIN/::END stuff in place
+ for (i = 0; i < BOGUS_BEGIN_END_RULES_length; i++) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* t = Transliterator::createFromRules("foo", UnicodeString(BOGUS_BEGIN_END_RULES[i]),
+ UTRANS_FORWARD, parseError, status);
+ if (!U_FAILURE(status)) {
+ delete t;
+ errln((UnicodeString)"Should have gotten syntax error from " + BOGUS_BEGIN_END_RULES[i]);
+ }
+ }
+*/
+}
+
+void TransliteratorTest::TestBeginEndToRules() {
+ // run through the same list of test cases we used above, but this time, instead of just
+ // instantiating a Transliterator from the rules and running the test against it, we instantiate
+ // a Transliterator from the rules, do toRules() on it, instantiate a Transliterator from
+ // the resulting set of rules, and make sure that the generated rule set is semantically equivalent
+ // to (i.e., does the same thing as) the original rule set
+ for (int32_t i = 0; i < BEGIN_END_TEST_CASES_length; i += 3) {
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* t = Transliterator::createFromRules("--", UnicodeString(BEGIN_END_TEST_CASES[i]),
+ UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ reportParseError(UnicodeString("FAIL: Couldn't create transliterator"), parseError, status);
+ } else {
+ UnicodeString rules;
+ t->toRules(rules, TRUE);
+ Transliterator* t2 = Transliterator::createFromRules((UnicodeString)"Test case #" + (i / 3), rules,
+ UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ reportParseError(UnicodeString("FAIL: Couldn't create transliterator from generated rules"),
+ parseError, status);
+ delete t;
+ } else {
+ expect(*t2,
+ UnicodeString(BEGIN_END_TEST_CASES[i + 1]),
+ UnicodeString(BEGIN_END_TEST_CASES[i + 2]));
+ delete t;
+ delete t2;
+ }
+ }
+ }
+
+ // do the same thing for the reversible test case
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ Transliterator* reversed = Transliterator::createFromRules("Reversed", UnicodeString(BEGIN_END_RULES[17]),
+ UTRANS_REVERSE, parseError, status);
+ if (U_FAILURE(status)) {
+ reportParseError(UnicodeString("FAIL: Couldn't create reversed transliterator"), parseError, status);
+ } else {
+ UnicodeString rules;
+ reversed->toRules(rules, FALSE);
+ Transliterator* reversed2 = Transliterator::createFromRules("Reversed", rules, UTRANS_FORWARD,
+ parseError, status);
+ if (U_FAILURE(status)) {
+ reportParseError(UnicodeString("FAIL: Couldn't create reversed transliterator from generated rules"),
+ parseError, status);
+ delete reversed;
+ } else {
+ expect(*reversed2,
+ UnicodeString("xy XY XYZ yz YZ"),
+ UnicodeString("xy abc xaba yz aba"));
+ delete reversed;
+ delete reversed2;
+ }
+ }
+}
+
+void TransliteratorTest::TestRegisterAlias() {
+ UnicodeString longID("Lower;[aeiou]Upper");
+ UnicodeString shortID("Any-CapVowels");
+ UnicodeString reallyShortID("CapVowels");
+
+ Transliterator::registerAlias(shortID, longID);
+
+ UErrorCode err = U_ZERO_ERROR;
+ Transliterator* t1 = Transliterator::createInstance(longID, UTRANS_FORWARD, err);
+ if (U_FAILURE(err)) {
+ errln("Failed to instantiate transliterator with long ID");
+ Transliterator::unregister(shortID);
+ return;
+ }
+ Transliterator* t2 = Transliterator::createInstance(reallyShortID, UTRANS_FORWARD, err);
+ if (U_FAILURE(err)) {
+ errln("Failed to instantiate transliterator with short ID");
+ delete t1;
+ Transliterator::unregister(shortID);
+ return;
+ }
+
+ if (t1->getID() != longID)
+ errln("Transliterator instantiated with long ID doesn't have long ID");
+ if (t2->getID() != reallyShortID)
+ errln("Transliterator instantiated with short ID doesn't have short ID");
+
+ UnicodeString rules1;
+ UnicodeString rules2;
+
+ t1->toRules(rules1, TRUE);
+ t2->toRules(rules2, TRUE);
+ if (rules1 != rules2)
+ errln("Alias transliterators aren't the same");
+
+ delete t1;
+ delete t2;
+ Transliterator::unregister(shortID);
+
+ t1 = Transliterator::createInstance(shortID, UTRANS_FORWARD, err);
+ if (U_SUCCESS(err)) {
+ errln("Instantiation with short ID succeeded after short ID was unregistered");
+ delete t1;
+ }
+
+ // try the same thing again, but this time with something other than
+ // an instance of CompoundTransliterator
+ UnicodeString realID("Latin-Greek");
+ UnicodeString fakeID("Latin-dlgkjdflkjdl");
+ Transliterator::registerAlias(fakeID, realID);
+
+ err = U_ZERO_ERROR;
+ t1 = Transliterator::createInstance(realID, UTRANS_FORWARD, err);
+ if (U_FAILURE(err)) {
+ errln("Failed to instantiate transliterator with real ID");
+ Transliterator::unregister(realID);
+ return;
+ }
+ t2 = Transliterator::createInstance(fakeID, UTRANS_FORWARD, err);
+ if (U_FAILURE(err)) {
+ errln("Failed to instantiate transliterator with fake ID");
+ delete t1;
+ Transliterator::unregister(realID);
+ return;
+ }
+
+ t1->toRules(rules1, TRUE);
+ t2->toRules(rules2, TRUE);
+ if (rules1 != rules2)
+ errln("Alias transliterators aren't the same");
+
+ delete t1;
+ delete t2;
+ Transliterator::unregister(fakeID);
+}
+
+void TransliteratorTest::TestRuleStripping() {
+ /*
+#
+\uE001>\u0C01; # SIGN
+ */
+ static const UChar rule[] = {
+ 0x0023,0x0020,0x000D,0x000A,
+ 0xE001,0x003E,0x0C01,0x003B,0x0020,0x0023,0x0020,0x0053,0x0049,0x0047,0x004E,0
+ };
+ static const UChar expectedRule[] = {
+ 0xE001,0x003E,0x0C01,0x003B,0
+ };
+ UChar result[sizeof(rule)/sizeof(rule[0])];
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t len = utrans_stripRules(rule, (int32_t)(sizeof(rule)/sizeof(rule[0])), result, &status);
+ if (len != u_strlen(expectedRule)) {
+ errln("utrans_stripRules return len = %d", len);
+ }
+ if (u_strncmp(expectedRule, result, len) != 0) {
+ errln("utrans_stripRules did not return expected string");
+ }
+}
+
+//======================================================================
+// Support methods
+//======================================================================
+void TransliteratorTest::expectT(const UnicodeString& id,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UParseError pe;
+ Transliterator *t = Transliterator::createInstance(id, UTRANS_FORWARD, pe, ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: Could not create " + id);
+ delete t;
+ return;
+ }
+ expect(*t, source, expectedResult);
+ delete t;
+}
+
+void TransliteratorTest::reportParseError(const UnicodeString& message,
+ const UParseError& parseError,
+ const UErrorCode& status) {
+ errln(message +
+ /*", parse error " + parseError.code +*/
+ ", line " + parseError.line +
+ ", offset " + parseError.offset +
+ ", pre-context " + prettify(parseError.preContext, TRUE) +
+ ", post-context " + prettify(parseError.postContext,TRUE) +
+ ", Error: " + u_errorName(status));
+}
+
+void TransliteratorTest::expect(const UnicodeString& rules,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult,
+ UTransPosition *pos) {
+ expect("<ID>", rules, source, expectedResult, pos);
+}
+
+void TransliteratorTest::expect(const UnicodeString& id,
+ const UnicodeString& rules,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult,
+ UTransPosition *pos) {
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ Transliterator* t = Transliterator::createFromRules(id, rules, UTRANS_FORWARD, parseError, status);
+ if (U_FAILURE(status)) {
+ reportParseError(UnicodeString("Couldn't create transliterator from ") + rules, parseError, status);
+ } else {
+ expect(*t, source, expectedResult, pos);
+ }
+ delete t;
+}
+
+void TransliteratorTest::expect(const Transliterator& t,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult,
+ const Transliterator& reverseTransliterator) {
+ expect(t, source, expectedResult);
+ expect(reverseTransliterator, expectedResult, source);
+}
+
+void TransliteratorTest::expect(const Transliterator& t,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult,
+ UTransPosition *pos) {
+ if (pos == 0) {
+ UnicodeString result(source);
+ t.transliterate(result);
+ expectAux(t.getID() + ":String", source, result, expectedResult);
+ }
+ UTransPosition index={0, 0, 0, 0};
+ if (pos != 0) {
+ index = *pos;
+ }
+
+ UnicodeString rsource(source);
+ if (pos == 0) {
+ t.transliterate(rsource);
+ } else {
+ // Do it all at once -- below we do it incrementally
+ t.finishTransliteration(rsource, *pos);
+ }
+ expectAux(t.getID() + ":Replaceable", source, rsource, expectedResult);
+
+ // Test keyboard (incremental) transliteration -- this result
+ // must be the same after we finalize (see below).
+ UnicodeString log;
+ rsource.remove();
+ if (pos != 0) {
+ rsource = source;
+ formatInput(log, rsource, index);
+ log.append(" -> ");
+ UErrorCode status = U_ZERO_ERROR;
+ t.transliterate(rsource, index, status);
+ formatInput(log, rsource, index);
+ } else {
+ for (int32_t i=0; i<source.length(); ++i) {
+ if (i != 0) {
+ log.append(" + ");
+ }
+ log.append(source.charAt(i)).append(" -> ");
+ UErrorCode status = U_ZERO_ERROR;
+ t.transliterate(rsource, index, source.charAt(i), status);
+ formatInput(log, rsource, index);
+ }
+ }
+
+ // As a final step in keyboard transliteration, we must call
+ // transliterate to finish off any pending partial matches that
+ // were waiting for more input.
+ t.finishTransliteration(rsource, index);
+ log.append(" => ").append(rsource);
+
+ expectAux(t.getID() + ":Keyboard", log,
+ rsource == expectedResult,
+ expectedResult);
+}
+
+
+/**
+ * @param appendTo result is appended to this param.
+ * @param input the string being transliterated
+ * @param pos the index struct
+ */
+UnicodeString& TransliteratorTest::formatInput(UnicodeString &appendTo,
+ const UnicodeString& input,
+ const UTransPosition& pos) {
+ // Output a string of the form aaa{bbb|ccc|ddd}eee, where
+ // the {} indicate the context start and limit, and the ||
+ // indicate the start and limit.
+ if (0 <= pos.contextStart &&
+ pos.contextStart <= pos.start &&
+ pos.start <= pos.limit &&
+ pos.limit <= pos.contextLimit &&
+ pos.contextLimit <= input.length()) {
+
+ UnicodeString a, b, c, d, e;
+ input.extractBetween(0, pos.contextStart, a);
+ input.extractBetween(pos.contextStart, pos.start, b);
+ input.extractBetween(pos.start, pos.limit, c);
+ input.extractBetween(pos.limit, pos.contextLimit, d);
+ input.extractBetween(pos.contextLimit, input.length(), e);
+ appendTo.append(a).append((UChar)123/*{*/).append(b).
+ append((UChar)PIPE).append(c).append((UChar)PIPE).append(d).
+ append((UChar)125/*}*/).append(e);
+ } else {
+ appendTo.append((UnicodeString)"INVALID UTransPosition {cs=" +
+ pos.contextStart + ", s=" + pos.start + ", l=" +
+ pos.limit + ", cl=" + pos.contextLimit + "} on " +
+ input);
+ }
+ return appendTo;
+}
+
+void TransliteratorTest::expectAux(const UnicodeString& tag,
+ const UnicodeString& source,
+ const UnicodeString& result,
+ const UnicodeString& expectedResult) {
+ expectAux(tag, source + " -> " + result,
+ result == expectedResult,
+ expectedResult);
+}
+
+void TransliteratorTest::expectAux(const UnicodeString& tag,
+ const UnicodeString& summary, UBool pass,
+ const UnicodeString& expectedResult) {
+ if (pass) {
+ logln(UnicodeString("(")+tag+") " + prettify(summary));
+ } else {
+ errln(UnicodeString("FAIL: (")+tag+") "
+ + prettify(summary)
+ + ", expected " + prettify(expectedResult));
+ }
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/transtst.h b/Build/source/libs/icu/icu-xetex/test/intltest/transtst.h
new file mode 100644
index 00000000000..0a6eef78c40
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/transtst.h
@@ -0,0 +1,421 @@
+/*
+**********************************************************************
+* Copyright (C) 1999-2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+* Date Name Description
+* 11/10/99 aliu Creation.
+**********************************************************************
+*/
+#ifndef TRANSTST_H
+#define TRANSTST_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "intltest.h"
+
+/**
+ * @test
+ * @summary General test of Transliterator
+ */
+class TransliteratorTest : public IntlTest {
+
+public:
+ TransliteratorTest();
+ virtual ~TransliteratorTest();
+
+private:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name,
+ char* par=NULL);
+
+ void TestInstantiation(void);
+
+ void TestSimpleRules(void);
+
+ void TestInlineSet(void);
+
+ void TestAnchors(void);
+
+ void TestPatternQuoting(void);
+
+ /**
+ * Create some inverses and confirm that they work. We have to be
+ * careful how we do this, since the inverses will not be true
+ * inverses -- we can't throw any random string at the composition
+ * of the transliterators and expect the identity function. F x
+ * F' != I. However, if we are careful about the input, we will
+ * get the expected results.
+ */
+ void TestRuleBasedInverse(void);
+
+ /**
+ * Basic test of keyboard.
+ */
+ void TestKeyboard(void);
+
+ /**
+ * Basic test of keyboard with cursor.
+ */
+ void TestKeyboard2(void);
+
+ /**
+ * Test keyboard transliteration with back-replacement.
+ */
+ void TestKeyboard3(void);
+
+ void keyboardAux(const Transliterator& t,
+ const char* DATA[], int32_t DATA_length);
+
+ void TestArabic(void);
+
+ /**
+ * Compose the Kana transliterator forward and reverse and try
+ * some strings that should come out unchanged.
+ */
+ void TestCompoundKana(void);
+
+ /**
+ * Compose the hex transliterators forward and reverse.
+ */
+ void TestCompoundHex(void);
+
+ /**
+ * Do some basic tests of filtering.
+ */
+ void TestFiltering(void);
+
+ /**
+ * Regression test for bugs found in Greek transliteration.
+ */
+ void TestJ277(void);
+
+ /**
+ * Prefix, suffix support in hex transliterators.
+ */
+ void TestJ243(void);
+
+ /**
+ * Parsers need better syntax error messages.
+ */
+ void TestJ329(void);
+
+ /**
+ * Test segments and segment references.
+ */
+ void TestSegments(void);
+
+ /**
+ * Test cursor positioning outside of the key
+ */
+ void TestCursorOffset(void);
+
+ /**
+ * Test zero length and > 1 char length variable values. Test
+ * use of variable refs in UnicodeSets.
+ */
+ void TestArbitraryVariableValues(void);
+
+ /**
+ * Confirm that the contextStart, contextLimit, start, and limit
+ * behave correctly. J474.
+ */
+ void TestPositionHandling(void);
+
+ /**
+ * Test the Hiragana-Katakana transliterator.
+ */
+ void TestHiraganaKatakana(void);
+
+ /**
+ * Test cloning / copy constructor of RBT.
+ */
+ void TestCopyJ476(void);
+
+ /**
+ * Test inter-Indic transliterators. These are composed.
+ * ICU4C Jitterbug 483.
+ */
+ void TestInterIndic(void);
+
+ /**
+ * Test filter syntax in IDs. (J918)
+ */
+ void TestFilterIDs(void);
+
+ /**
+ * Test the case mapping transliterators.
+ */
+ void TestCaseMap(void);
+
+ /**
+ * Test the name mapping transliterators.
+ */
+ void TestNameMap(void);
+
+ /**
+ * Test liberalized ID syntax. 1006c
+ */
+ void TestLiberalizedID(void);
+ /**
+ * Test Jitterbug 912
+ */
+ void TestCreateInstance(void);
+
+ void TestNormalizationTransliterator(void);
+
+ void TestCompoundRBT(void);
+
+ void TestCompoundFilter(void);
+
+ void TestRemove(void);
+
+ void TestToRules(void);
+
+ void TestContext(void);
+
+ void TestSupplemental(void);
+
+ void TestQuantifier(void);
+
+ /**
+ * Test Source-Target/Variant.
+ */
+ void TestSTV(void);
+
+ void TestCompoundInverse(void);
+
+ void TestNFDChainRBT(void);
+
+ /**
+ * Inverse of "Null" should be "Null". (J21)
+ */
+ void TestNullInverse(void);
+
+ /**
+ * Check ID of inverse of alias. (J22)
+ */
+ void TestAliasInverseID(void);
+
+ /**
+ * Test IDs of inverses of compound transliterators. (J20)
+ */
+ void TestCompoundInverseID(void);
+
+ /**
+ * Test undefined variable.
+ */
+ void TestUndefinedVariable(void);
+
+ /**
+ * Test empty context.
+ */
+ void TestEmptyContext(void);
+
+ /**
+ * Test compound filter ID syntax
+ */
+ void TestCompoundFilterID(void);
+
+ /**
+ * Test new property set syntax
+ */
+ void TestPropertySet(void);
+
+ /**
+ * Test various failure points of the new 2.0 engine.
+ */
+ void TestNewEngine(void);
+
+ /**
+ * Test quantified segment behavior. We want:
+ * ([abc])+ > x $1 x; applied to "cba" produces "xax"
+ */
+ void TestQuantifiedSegment(void);
+
+ /* Devanagari-Latin rules Test */
+ void TestDevanagariLatinRT(void);
+
+ /* Telugu-Latin rules Test */
+ void TestTeluguLatinRT(void);
+
+ /* Gujarati-Latin rules Test */
+ void TestGujaratiLatinRT(void);
+
+ /* Sanskrit-Latin rules Test */
+ void TestSanskritLatinRT(void);
+
+ /* Test Compound Indic-Latin transliterators*/
+ void TestCompoundLatinRT(void);
+
+ /* Test bindi and tippi for Gurmukhi */
+ void TestGurmukhiDevanagari(void);
+ /**
+ * Test instantiation from a locale.
+ */
+ void TestLocaleInstantiation(void);
+
+ /**
+ * Test title case handling of accent (should ignore accents)
+ */
+ void TestTitleAccents(void);
+
+ /**
+ * Basic test of a locale resource based rule.
+ */
+ void TestLocaleResource(void);
+
+ /**
+ * Make sure parse errors reference the right line.
+ */
+ void TestParseError(void);
+
+ /**
+ * Make sure sets on output are disallowed.
+ */
+ void TestOutputSet(void);
+
+ /**
+ * Test the use variable range pragma, making sure that use of
+ * variable range characters is detected and flagged as an error.
+ */
+ void TestVariableRange(void);
+
+ /**
+ * Test invalid post context error handling
+ */
+ void TestInvalidPostContext(void);
+
+ /**
+ * Test ID form variants
+ */
+ void TestIDForms(void);
+
+ /**
+ * Mark's toRules test.
+ */
+ void TestToRulesMark(void);
+
+ /**
+ * Test Escape and Unescape transliterators.
+ */
+ void TestEscape(void);
+
+ void TestAnchorMasking(void);
+
+ /**
+ * Make sure display names of variants look reasonable.
+ */
+ void TestDisplayName(void);
+
+ /**
+ * Check to see if case mapping works correctly.
+ */
+ void TestSpecialCases(void);
+ /**
+ * Check to see that incremental gets at least part way through a reasonable string.
+ */
+ void TestIncrementalProgress(void);
+
+ /**
+ * Check that casing handles surrogates.
+ */
+ void TestSurrogateCasing (void);
+
+ void TestFunction(void);
+
+ void TestInvalidBackRef(void);
+
+ void TestMulticharStringSet(void);
+
+ void TestUserFunction(void);
+
+ void TestAnyX(void);
+
+ void TestSourceTargetSet(void);
+
+ void TestRuleWhitespace(void);
+
+ void TestAllCodepoints(void);
+
+ void TestBoilerplate(void);
+
+ void TestAlternateSyntax(void);
+
+ void TestRuleStripping(void);
+
+ /**
+ * Tests the multiple-pass syntax
+ */
+ void TestBeginEnd(void);
+
+ /**
+ * Tests that toRules() works right with the multiple-pass syntax
+ */
+ void TestBeginEndToRules(void);
+
+ /**
+ * Tests the registerAlias() function
+ */
+ void TestRegisterAlias(void);
+
+ //======================================================================
+ // Support methods
+ //======================================================================
+ protected:
+ void expectT(const UnicodeString& id,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult);
+
+ void expect(const UnicodeString& rules,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult,
+ UTransPosition *pos=0);
+
+ void expect(const UnicodeString& id,
+ const UnicodeString& rules,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult,
+ UTransPosition *pos=0);
+
+ void expect(const Transliterator& t,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult,
+ const Transliterator& reverseTransliterator);
+
+ void expect(const Transliterator& t,
+ const UnicodeString& source,
+ const UnicodeString& expectedResult,
+ UTransPosition *pos=0);
+
+ void expectAux(const UnicodeString& tag,
+ const UnicodeString& source,
+ const UnicodeString& result,
+ const UnicodeString& expectedResult);
+
+ virtual void expectAux(const UnicodeString& tag,
+ const UnicodeString& summary, UBool pass,
+ const UnicodeString& expectedResult);
+
+ static UnicodeString& formatInput(UnicodeString &appendTo,
+ const UnicodeString& input,
+ const UTransPosition& pos);
+
+ void checkRules(const UnicodeString& label, Transliterator& t2,
+ const UnicodeString& testRulesForward);
+ void CheckIncrementalAux(const Transliterator* t,
+ const UnicodeString& input);
+
+ void reportParseError(const UnicodeString& message, const UParseError& parseError, const UErrorCode& status);
+
+
+ const UnicodeString DESERET_DEE;
+ const UnicodeString DESERET_dee;
+
+};
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/trcoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/trcoll.cpp
new file mode 100644
index 00000000000..7da003a8ca3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/trcoll.cpp
@@ -0,0 +1,106 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/unistr.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/tstdtmod.h"
+#include "unicode/coll.h"
+#include "unicode/tblcoll.h"
+#include "unicode/sortkey.h"
+#include "trcoll.h"
+#include "sfwdchit.h"
+
+CollationTurkishTest::CollationTurkishTest()
+: myCollation(0)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ myCollation = Collator::createInstance(Locale("tr", "", ""),status);
+}
+
+CollationTurkishTest::~CollationTurkishTest()
+{
+ delete myCollation;
+}
+
+const UChar CollationTurkishTest::testSourceCases[][CollationTurkishTest::MAX_TOKEN_LEN] = {
+ {0x73, 0x0327, 0},
+ {0x76, 0x00E4, 0x74, 0},
+ {0x6f, 0x6c, 0x64, 0},
+ {0x00FC, 0x6f, 0x69, 0x64, 0},
+ {0x68, 0x011E, 0x61, 0x6c, 0x74, 0},
+ {0x73, 0x74, 0x72, 0x65, 0x73, 0x015E, 0},
+ {0x76, 0x6f, 0x0131, 0x64, 0},
+ {0x69, 0x64, 0x65, 0x61, 0},
+ {0x00FC, 0x6f, 0x69, 0x64, 0},
+ {0x76, 0x6f, 0x0131, 0x64, 0},
+ {0x69, 0x64, 0x65, 0x61, 0}
+};
+
+const UChar CollationTurkishTest::testTargetCases[][CollationTurkishTest::MAX_TOKEN_LEN] = {
+ {0x75, 0x0308, 0},
+ {0x76, 0x62, 0x74, 0},
+ {0x00D6, 0x61, 0x79, 0},
+ {0x76, 0x6f, 0x69, 0x64, 0},
+ {0x68, 0x61, 0x6c, 0x74, 0},
+ {0x015E, 0x74, 0x72, 0x65, 0x015E, 0x73, 0},
+ {0x76, 0x6f, 0x69, 0x64, 0},
+ {0x49, 0x64, 0x65, 0x61, 0},
+ {0x76, 0x6f, 0x69, 0x64, 0},
+ {0x76, 0x6f, 0x69, 0x64, 0},
+ {0x49, 0x64, 0x65, 0x61, 0}
+};
+
+const Collator::EComparisonResult CollationTurkishTest::results[] = {
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::GREATER,
+ Collator::LESS,
+ Collator::LESS,
+ Collator::GREATER,
+ // test priamry > 8
+ Collator::LESS,
+ Collator::LESS,
+ Collator::GREATER
+};
+
+void CollationTurkishTest::TestTertiary(/* char* par */)
+{
+ int32_t i = 0;
+ myCollation->setStrength(Collator::TERTIARY);
+ for (i = 0; i < 8 ; i++) {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+void CollationTurkishTest::TestPrimary(/* char* par */)
+{
+ int32_t i;
+ myCollation->setStrength(Collator::PRIMARY);
+ for (i = 8; i < 11; i++) {
+ doTest(myCollation, testSourceCases[i], testTargetCases[i], results[i]);
+ }
+}
+
+void CollationTurkishTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite CollationTurkishTest: ");
+
+ if((!myCollation) && exec) {
+ errln(__FILE__ " cannot test - failed to create collator.");
+ name = "some test";
+ return;
+ }
+ switch (index) {
+ case 0: name = "TestPrimary"; if (exec) TestPrimary(/* par */); break;
+ case 1: name = "TestTertiary"; if (exec) TestTertiary(/* par */); break;
+ default: name = ""; break;
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/trcoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/trcoll.h
new file mode 100644
index 00000000000..4ab553e2621
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/trcoll.h
@@ -0,0 +1,49 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * CollationTurkishTest is a third level test class. This tests the locale
+ * specific primary and tertiary rules. For example, the dotless-i and dotted-I
+ * sorts between h and j.
+ */
+
+#ifndef _TRCOLL
+#define _TRCOLL
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "tscoll.h"
+
+class CollationTurkishTest: public IntlTestCollator {
+public:
+ // If this is too small for the test data, just increase it.
+ // Just don't make it too large, otherwise the executable will get too big
+ enum EToken_Len { MAX_TOKEN_LEN = 16 };
+
+ CollationTurkishTest();
+ virtual ~CollationTurkishTest();
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // perform tests for turkish locale with strength PRIMARY
+ void TestPrimary(/* char* par */);
+
+ // perform tests for turkish locale with strength TERTIARY
+ void TestTertiary(/* char* par */);
+
+private:
+ // static constants
+ static const UChar testSourceCases[][MAX_TOKEN_LEN];
+ static const UChar testTargetCases[][MAX_TOKEN_LEN];
+ static const Collator::EComparisonResult results[];
+
+ Collator *myCollation;
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/trnserr.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/trnserr.cpp
new file mode 100644
index 00000000000..40f41850f07
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/trnserr.cpp
@@ -0,0 +1,283 @@
+/********************************************************************
+ * Copyright (c) 2001-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ *********************************************************************
+ * This test program is intended for testing error conditions of the
+ * transliterator APIs to make sure the exceptions are raised where
+ * necessary.
+ *
+ * Date Name Description
+ * 11/14/2001 hshih Creation.
+ *
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "ittrans.h"
+#include "trnserr.h"
+#include "unicode/utypes.h"
+#include "unicode/translit.h"
+#include "unicode/uniset.h"
+#include "unicode/unifilt.h"
+#include "cpdtrans.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "unicode/rep.h"
+#include "unicode/locid.h"
+
+//---------------------------------------------
+// runIndexedTest
+//---------------------------------------------
+
+void
+TransliteratorErrorTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ TESTCASE(0,TestTransliteratorErrors);
+ TESTCASE(1, TestUnicodeSetErrors);
+ TESTCASE(2, TestRBTErrors);
+ TESTCASE(3, TestCoverage);
+ //TESTCASE(3, TestUniToHexErrors);
+ //TESTCASE(4, TestHexToUniErrors);
+ // TODO: Add a subclass to test clone().
+ default: name = ""; break;
+ }
+}
+
+
+void TransliteratorErrorTest::TestTransliteratorErrors() {
+ UnicodeString trans="Latin-Greek";
+ UnicodeString bogusID="LATINGREEK-GREEKLATIN";
+ UnicodeString newID="Bogus-Latin";
+ UnicodeString newIDRules="zzz > Z; f <> ph";
+ UnicodeString bogusRules="a } [b-g m-p ";
+ UParseError parseError;
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString testString="A quick fox jumped over the lazy dog.";
+ UnicodeString insertString="cats and dogs";
+ int32_t stoppedAt = 0, len;
+ UTransPosition pos;
+
+ Transliterator* t= Transliterator::createInstance(trans, UTRANS_FORWARD, parseError, status);
+ if(t==0 || U_FAILURE(status)){
+ errln("FAIL: construction of Latin-Greek");
+ return;
+ }
+ pos.contextLimit = 0;
+ pos.contextStart = 0;
+ pos.limit = 0;
+ pos.start = 0;
+ len = testString.length();
+ stoppedAt = t->transliterate(testString, 0, 100);
+ if (stoppedAt != -1) {
+ errln("FAIL: Out of bounds check failed (1).");
+ } else if (testString.length() != len) {
+ testString="A quick fox jumped over the lazy dog.";
+ errln("FAIL: Transliterate fails and the target string was modified.");
+ }
+ stoppedAt = t->transliterate(testString, 100, testString.length()-1);
+ if (stoppedAt != -1)
+ errln("FAIL: Out of bounds check failed (2).");
+ else if (testString.length() != len) {
+ testString="A quick fox jumped over the lazy dog.";
+ errln("FAIL: Transliterate fails and the target string was modified.");
+ }
+ pos.start = 100;
+ pos.limit = testString.length();
+ t->transliterate(testString, pos, status);
+ if (U_SUCCESS(status)) {
+ errln("FAIL: Start offset is out of bounds, error not reported.\n");
+ }
+ status = U_ZERO_ERROR;
+ pos.limit = 100;
+ pos.start = 0;
+ t->transliterate(testString, pos, status);
+ if (U_SUCCESS(status)) {
+ errln("FAIL: Limit offset is out of bounds, error not reported.\n");
+ }
+ status = U_ZERO_ERROR;
+ len = pos.contextLimit = testString.length();
+ pos.contextStart = 0;
+ pos.limit = len - 1;
+ pos.start = 5;
+ t->transliterate(testString, pos, insertString, status);
+ if (len == pos.limit) {
+ errln("FAIL: Test insertion with string: the transliteration position limit didn't change as expected.");
+ if (U_SUCCESS(status)) {
+ errln("FAIL: Error code wasn't set either.");
+ }
+ }
+ status = U_ZERO_ERROR;
+ pos.contextStart = 0;
+ pos.contextLimit = testString.length();
+ pos.limit = testString.length() -1;
+ pos.start = 5;
+ t->transliterate(testString, pos, (UChar32)0x0061, status);
+ if (len == pos.limit) {
+ errln("FAIL: Test insertion with character: the transliteration position limit didn't change as expected.");
+ if (U_SUCCESS(status)) {
+ errln("FAIL: Error code wasn't set either.");
+ }
+ }
+ status = U_ZERO_ERROR;
+ len = pos.limit = testString.length();
+ pos.contextStart = 0;
+ pos.contextLimit = testString.length() - 1;
+ pos.start = 5;
+ t->transliterate(testString, pos, insertString, status);
+ if (U_SUCCESS(status)) {
+ errln("FAIL: Out of bounds check failed (3).");
+ if (testString.length() != len)
+ errln("FAIL: The input string was modified though the offsets were out of bounds.");
+ }
+ Transliterator* t1= Transliterator::createInstance(bogusID, UTRANS_FORWARD, parseError, status);
+ if(t1!=0 || U_SUCCESS(status)){
+ delete t1;
+ errln("FAIL: construction of bogus ID \"LATINGREEK-GREEKLATIN\"");
+ }
+ status = U_ZERO_ERROR;
+ Transliterator* t2 = Transliterator::createFromRules(newID, newIDRules, UTRANS_FORWARD, parseError, status);
+ if (U_SUCCESS(status)) {
+ Transliterator* t3 = t2->createInverse(status);
+ if (U_SUCCESS(status)) {
+ delete t3;
+ errln("FAIL: The newID transliterator was not registered so createInverse should fail.");
+ } else {
+ delete t3;
+ }
+ }
+ status = U_ZERO_ERROR;
+ Transliterator* t4 = Transliterator::createFromRules(newID, bogusRules, UTRANS_FORWARD, parseError, status);
+ if (t4 != NULL || U_SUCCESS(status)) {
+ errln("FAIL: The rules is malformed but error was not reported.");
+ if (parseError.offset != -1) {
+ errln("FAIL: The parse error offset isn't set correctly when fails.");
+ } else if (parseError.postContext[0] == 0 || parseError.preContext[0] == 0) {
+ errln("FAIL: The parse error pre/post context isn't reset properly.");
+ }
+ delete t4;
+ }
+ delete t;
+ delete t2;
+}
+
+void TransliteratorErrorTest::TestUnicodeSetErrors() {
+ UnicodeString badPattern="[[:L:]-[0x0300-0x0400]";
+ UnicodeSet set;
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString result;
+
+ if (!set.isEmpty()) {
+ errln("FAIL: The default ctor of UnicodeSet created a non-empty object.");
+ }
+ set.applyPattern(badPattern, status);
+ if (U_SUCCESS(status)) {
+ errln("FAIL: Applied a bad pattern to the UnicodeSet object okay.");
+ }
+ status = U_ZERO_ERROR;
+ UnicodeSet *set1 = new UnicodeSet(badPattern, status);
+ if (U_SUCCESS(status)) {
+ errln("FAIL: Created a UnicodeSet based on bad patterns.");
+ }
+ delete set1;
+}
+
+//void TransliteratorErrorTest::TestUniToHexErrors() {
+// UErrorCode status = U_ZERO_ERROR;
+// Transliterator *t = new UnicodeToHexTransliterator("", TRUE, NULL, status);
+// if (U_SUCCESS(status)) {
+// errln("FAIL: Created a UnicodeToHexTransliterator with an empty pattern.");
+// }
+// delete t;
+//
+// status = U_ZERO_ERROR;
+// t = new UnicodeToHexTransliterator("\\x", TRUE, NULL, status);
+// if (U_SUCCESS(status)) {
+// errln("FAIL: Created a UnicodeToHexTransliterator with a bad pattern.");
+// }
+// delete t;
+//
+// status = U_ZERO_ERROR;
+// t = new UnicodeToHexTransliterator();
+// ((UnicodeToHexTransliterator*)t)->applyPattern("\\x", status);
+// if (U_SUCCESS(status)) {
+// errln("FAIL: UnicodeToHexTransliterator::applyPattern succeeded with a bad pattern.");
+// }
+// delete t;
+//}
+
+void TransliteratorErrorTest::TestRBTErrors() {
+
+ UnicodeString rules="ab>y";
+ UnicodeString id="MyRandom-YReverse";
+ //UnicodeString goodPattern="[[:L:]&[\\u0000-\\uFFFF]]"; /* all BMP letters */
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseErr;
+ /*UnicodeSet *set = new UnicodeSet(goodPattern, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Was not able to create a good UnicodeSet based on valid patterns.");
+ return;
+ }*/
+ Transliterator *t = Transliterator::createFromRules(id, rules, UTRANS_REVERSE, parseErr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Was not able to create a good RBT to test registration.");
+ //delete set;
+ return;
+ }
+ Transliterator::registerInstance(t);
+ Transliterator::unregister(id);
+ status = U_ZERO_ERROR;
+ Transliterator* t1= Transliterator::createInstance(id, UTRANS_REVERSE, parseErr, status);
+ if(U_SUCCESS(status)){
+ delete t1;
+ errln("FAIL: construction of unregistered ID failed.");
+ }
+}
+
+//void TransliteratorErrorTest::TestHexToUniErrors() {
+// UErrorCode status = U_ZERO_ERROR;
+// Transliterator *t = new HexToUnicodeTransliterator("", NULL, status);
+// if (U_FAILURE(status)) {
+// errln("FAIL: Could not create a HexToUnicodeTransliterator with an empty pattern.");
+// }
+// delete t;
+// status = U_ZERO_ERROR;
+// t = new HexToUnicodeTransliterator("\\x", NULL, status);
+// if (U_SUCCESS(status)) {
+// errln("FAIL: Created a HexToUnicodeTransliterator with a bad pattern.");
+// }
+// delete t;
+// status = U_ZERO_ERROR;
+// t = new HexToUnicodeTransliterator();
+// ((HexToUnicodeTransliterator*)t)->applyPattern("\\x", status);
+// if (U_SUCCESS(status)) {
+// errln("FAIL: HexToUnicodeTransliterator::applyPattern succeeded with a bad pattern.");
+// }
+// delete t;
+//}
+
+class StubTransliterator: public Transliterator{
+public:
+ StubTransliterator(): Transliterator(UNICODE_STRING_SIMPLE("Any-Null"), 0) {}
+ virtual void handleTransliterate(Replaceable& ,UTransPosition& offsets,UBool) const {
+ offsets.start = offsets.limit;
+ }
+
+ virtual UClassID getDynamicClassID() const{
+ static char classID = 0;
+ return (UClassID)&classID;
+ }
+};
+
+void TransliteratorErrorTest::TestCoverage() {
+ StubTransliterator stub;
+
+ if (stub.clone() != NULL){
+ errln("FAIL: default Transliterator::clone() should return NULL");
+ }
+}
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/trnserr.h b/Build/source/libs/icu/icu-xetex/test/intltest/trnserr.h
new file mode 100644
index 00000000000..35b4c5a4bd6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/trnserr.h
@@ -0,0 +1,54 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2001-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/************************************************************************
+* This test program is intended for testing error conditions of the
+* transliterator APIs to make sure the exceptions are raised where
+* necessary.
+*
+* Date Name Description
+* 11/14/2001 hshih Creation.
+*
+************************************************************************/
+
+
+#ifndef TRNSERR_H
+#define TRNSERR_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_TRANSLITERATION
+
+#include "unicode/translit.h"
+#include "intltest.h"
+
+/**
+ * @test
+ * @summary Error condition tests of Transliterator
+ */
+class TransliteratorErrorTest : public IntlTest {
+public:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par=NULL);
+
+ /*Tests the returned error codes on all the APIs according to the API documentation. */
+ void TestTransliteratorErrors(void);
+
+ void TestUnicodeSetErrors(void);
+
+ //void TestUniToHexErrors(void);
+
+ void TestRBTErrors(void);
+
+ //void TestHexToUniErrors(void);
+
+ // JitterBug 4452, for coverage. The reason to put this method here is
+ // this class is comparable smaller than other Transliterator*Test classes
+ void TestCoverage(void);
+
+};
+
+#endif /* #if !UCONFIG_NO_TRANSLITERATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tscoll.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tscoll.cpp
new file mode 100644
index 00000000000..4c65e670ae3
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tscoll.cpp
@@ -0,0 +1,513 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * IntlTestCollator is the medium level test class for everything in the directory "collate".
+ */
+
+/***********************************************************************
+* Modification history
+* Date Name Description
+* 02/14/2001 synwee Compare with cintltst and commented away tests
+* that are not run.
+***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+
+#include "dadrcoll.h"
+
+#include "encoll.h"
+#include "frcoll.h"
+#include "decoll.h"
+#include "escoll.h"
+#include "ficoll.h"
+#include "jacoll.h"
+#include "trcoll.h"
+#include "allcoll.h"
+#include "g7coll.h"
+#include "mnkytst.h"
+#include "apicoll.h"
+#include "regcoll.h"
+#include "currcoll.h"
+#include "itercoll.h"
+#include "tstnorm.h"
+#include "normconf.h"
+#include "thcoll.h"
+#include "srchtest.h"
+#include "cntabcol.h"
+#include "lcukocol.h"
+#include "ucaconf.h"
+#include "svccoll.h"
+#include "cmemory.h"
+//#include "rndmcoll.h"
+
+#define TESTCLASS(n,classname) \
+ case n: \
+ name = #classname; \
+ if (exec) { \
+ logln(#classname "---"); \
+ logln(""); \
+ classname t; \
+ callTest(t, par); \
+ } \
+ break
+
+void IntlTestCollator::runIndexedTest( int32_t index, UBool exec, const char* &name, char* par )
+{
+ if (exec) {
+ logln("TestSuite Collator: ");
+ }
+
+ switch (index) {
+ TESTCLASS(0, CollationEnglishTest);
+ TESTCLASS(1, CollationFrenchTest);
+ TESTCLASS(2, CollationGermanTest);
+ TESTCLASS(3, CollationSpanishTest);
+ TESTCLASS(4, CollationKanaTest);
+ TESTCLASS(5, CollationTurkishTest);
+ TESTCLASS(6, CollationDummyTest);
+ TESTCLASS(7, G7CollationTest);
+ TESTCLASS(8, CollationMonkeyTest);
+ TESTCLASS(9, CollationAPITest);
+ TESTCLASS(10, CollationRegressionTest);
+ TESTCLASS(11, CollationCurrencyTest);
+ TESTCLASS(12, CollationIteratorTest);
+ TESTCLASS(13, CollationThaiTest);
+ TESTCLASS(14, LotusCollationKoreanTest);
+ TESTCLASS(15, StringSearchTest);
+ TESTCLASS(16, ContractionTableTest);
+ TESTCLASS(17, DataDrivenCollatorTest);
+ TESTCLASS(18, UCAConformanceTest);
+ TESTCLASS(19, CollationServiceTest);
+ TESTCLASS(20, CollationFinnishTest); // removed by weiv - we have changed Finnish collation
+ //TESTCLASS(21, RandomCollatorTest); // See ticket 5747 about reenabling this test.
+
+ default: name = ""; break;
+ }
+}
+
+UCollationResult
+IntlTestCollator::compareUsingPartials(UCollator *coll, const UChar source[], int32_t sLen, const UChar target[], int32_t tLen, int32_t pieceSize, UErrorCode &status) {
+ int32_t partialSKResult = 0;
+ uint8_t sBuf[512], tBuf[512];
+ UCharIterator sIter, tIter;
+ uint32_t sState[2], tState[2];
+ int32_t sSize = pieceSize, tSize = pieceSize;
+ int32_t i = 0;
+ status = U_ZERO_ERROR;
+ sState[0] = 0; sState[1] = 0;
+ tState[0] = 0; tState[1] = 0;
+ while(sSize == pieceSize && tSize == pieceSize && partialSKResult == 0) {
+ uiter_setString(&sIter, source, sLen);
+ uiter_setString(&tIter, target, tLen);
+ sSize = ucol_nextSortKeyPart(coll, &sIter, sState, sBuf, pieceSize, &status);
+ tSize = ucol_nextSortKeyPart(coll, &tIter, tState, tBuf, pieceSize, &status);
+
+ if(sState[0] != 0 || tState[0] != 0) {
+ log("State != 0 : %08X %08X\n", sState[0], tState[0]);
+ }
+ log("%i ", i++);
+
+ partialSKResult = memcmp(sBuf, tBuf, pieceSize);
+ }
+
+ if(partialSKResult < 0) {
+ return UCOL_LESS;
+ } else if(partialSKResult > 0) {
+ return UCOL_GREATER;
+ } else {
+ return UCOL_EQUAL;
+ }
+}
+
+void
+IntlTestCollator::doTestVariant(Collator* col, const UnicodeString &source, const UnicodeString &target, Collator::EComparisonResult result)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ UCollator *myCollation = (UCollator *)((RuleBasedCollator *)col)->getUCollator();
+
+ Collator::EComparisonResult compareResult = col->compare(source, target);
+
+ CollationKey srckey, tgtkey;
+ col->getCollationKey(source, srckey, status);
+ col->getCollationKey(target, tgtkey, status);
+ if (U_FAILURE(status)){
+ errln("Creation of collation keys failed\n");
+ }
+ Collator::EComparisonResult keyResult = srckey.compareTo(tgtkey);
+
+ reportCResult(source, target, srckey, tgtkey, compareResult, keyResult, result, result);
+
+ UColAttributeValue norm = ucol_getAttribute(myCollation, UCOL_NORMALIZATION_MODE, &status);
+
+ int32_t sLen = source.length(), tLen = target.length();
+ const UChar* src = source.getBuffer();
+ const UChar* trg = target.getBuffer();
+ UCollationResult compareResultIter = (UCollationResult)result;
+
+ {
+ UCharIterator sIter, tIter;
+ uiter_setString(&sIter, src, sLen);
+ uiter_setString(&tIter, trg, tLen);
+ compareResultIter = ucol_strcollIter(myCollation, &sIter, &tIter, &status);
+ if(compareResultIter != (UCollationResult)result) {
+ errln("Different result for iterative comparison "+source+" "+target);
+ }
+ }
+ /* convert the strings to UTF-8 and do try comparing with char iterator */
+ if(!quick) { /*!QUICK*/
+ char utf8Source[256], utf8Target[256];
+ int32_t utf8SourceLen = 0, utf8TargetLen = 0;
+ u_strToUTF8(utf8Source, 256, &utf8SourceLen, src, sLen, &status);
+ if(U_FAILURE(status)) { /* probably buffer is not big enough */
+ log("Src UTF-8 buffer too small! Will not compare!\n");
+ } else {
+ u_strToUTF8(utf8Target, 256, &utf8TargetLen, trg, tLen, &status);
+ if(U_SUCCESS(status)) { /* probably buffer is not big enough */
+ UCollationResult compareResultUTF8 = (UCollationResult)result, compareResultUTF8Norm = (UCollationResult)result;
+ UCharIterator sIter, tIter;
+ /*log_verbose("Strings converted to UTF-8:%s, %s\n", aescstrdup(source,-1), aescstrdup(target,-1));*/
+ uiter_setUTF8(&sIter, utf8Source, utf8SourceLen);
+ uiter_setUTF8(&tIter, utf8Target, utf8TargetLen);
+ /*uiter_setString(&sIter, source, sLen);
+ uiter_setString(&tIter, target, tLen);*/
+ compareResultUTF8 = ucol_strcollIter(myCollation, &sIter, &tIter, &status);
+ ucol_setAttribute(myCollation, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
+ sIter.move(&sIter, 0, UITER_START);
+ tIter.move(&tIter, 0, UITER_START);
+ compareResultUTF8Norm = ucol_strcollIter(myCollation, &sIter, &tIter, &status);
+ ucol_setAttribute(myCollation, UCOL_NORMALIZATION_MODE, norm, &status);
+ if(compareResultUTF8 != compareResultIter) {
+ errln("different results in iterative comparison for UTF-16 and UTF-8 encoded strings. "+source+", "+target);
+ }
+ if(compareResultUTF8 != compareResultUTF8Norm) {
+ errln("different results in iterative when normalization is turned on with UTF-8 strings. "+source+", "+target);
+ }
+ } else {
+ log("Target UTF-8 buffer too small! Did not compare!\n");
+ }
+ if(U_FAILURE(status)) {
+ log("UTF-8 strcoll failed! Ignoring result\n");
+ }
+ }
+ }
+
+ /* testing the partial sortkeys */
+ { /*!QUICK*/
+ int32_t partialSizes[] = { 3, 1, 2, 4, 8, 20, 80 }; /* just size 3 in the quick mode */
+ int32_t partialSizesSize = 1;
+ if(!quick) {
+ partialSizesSize = 7;
+ }
+ int32_t i = 0;
+ log("partial sortkey test piecesize=");
+ for(i = 0; i < partialSizesSize; i++) {
+ UCollationResult partialSKResult = (UCollationResult)result, partialNormalizedSKResult = (UCollationResult)result;
+ log("%i ", partialSizes[i]);
+
+ partialSKResult = compareUsingPartials(myCollation, src, sLen, trg, tLen, partialSizes[i], status);
+ if(partialSKResult != (UCollationResult)result) {
+ errln("Partial sortkey comparison returned wrong result: "+source+", "+target+" (size "+partialSizes[i]+")");
+ }
+
+ if(norm != UCOL_ON && !quick) {
+ log("N ");
+ ucol_setAttribute(myCollation, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
+ partialNormalizedSKResult = compareUsingPartials(myCollation, src, sLen, trg, tLen, partialSizes[i], status);
+ ucol_setAttribute(myCollation, UCOL_NORMALIZATION_MODE, norm, &status);
+ if(partialSKResult != partialNormalizedSKResult) {
+ errln("Partial sortkey comparison gets different result when normalization is on: "+source+", "+target+" (size "+partialSizes[i]+")");
+ }
+ }
+ }
+ log("\n");
+ }
+/*
+ if (compareResult != result) {
+ errln("String comparison failed in variant test\n");
+ }
+ if (keyResult != result) {
+ errln("Collation key comparison failed in variant test\n");
+ }
+*/
+}
+
+void
+IntlTestCollator::doTest(Collator* col, const UChar *source, const UChar *target, Collator::EComparisonResult result) {
+ doTest(col, UnicodeString(source), UnicodeString(target), result);
+}
+
+void
+IntlTestCollator::doTest(Collator* col, const UnicodeString &source, const UnicodeString &target, Collator::EComparisonResult result)
+{
+ if(col) {
+ doTestVariant(col, source, target, result);
+ if(result == Collator::LESS) {
+ doTestVariant(col, target, source, Collator::GREATER);
+ } else if (result == Collator::GREATER) {
+ doTestVariant(col, target, source, Collator::LESS);
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ CollationElementIterator* c = ((RuleBasedCollator *)col)->createCollationElementIterator( source );
+ logln("Testing iterating source: "+source);
+ backAndForth(*c);
+ c->setText(target, status);
+ logln("Testing iterating target: "+target);
+ backAndForth(*c);
+ delete c;
+ }
+}
+
+
+// used for collation result reporting, defined here for convenience
+// (maybe moved later)
+void
+IntlTestCollator::reportCResult( const UnicodeString &source, const UnicodeString &target,
+ CollationKey &sourceKey, CollationKey &targetKey,
+ Collator::EComparisonResult compareResult,
+ Collator::EComparisonResult keyResult,
+ Collator::EComparisonResult incResult,
+ Collator::EComparisonResult expectedResult )
+{
+ if (expectedResult < -1 || expectedResult > 1)
+ {
+ errln("***** invalid call to reportCResult ****");
+ return;
+ }
+
+ UBool ok1 = (compareResult == expectedResult);
+ UBool ok2 = (keyResult == expectedResult);
+ UBool ok3 = (incResult == expectedResult);
+
+
+ if (ok1 && ok2 && ok3 && !verbose) {
+ // Keep non-verbose, passing tests fast
+ return;
+ } else {
+ UnicodeString msg1(ok1 ? "Ok: compare(" : "FAIL: compare(");
+ UnicodeString msg2(", "), msg3(") returned "), msg4("; expected ");
+ UnicodeString prettySource, prettyTarget, sExpect, sResult;
+
+ IntlTest::prettify(source, prettySource);
+ IntlTest::prettify(target, prettyTarget);
+ appendCompareResult(compareResult, sResult);
+ appendCompareResult(expectedResult, sExpect);
+
+ if (ok1) {
+ logln(msg1 + prettySource + msg2 + prettyTarget + msg3 + sResult);
+ } else {
+ errln(msg1 + prettySource + msg2 + prettyTarget + msg3 + sResult + msg4 + sExpect);
+ }
+
+ msg1 = UnicodeString(ok2 ? "Ok: key(" : "FAIL: key(");
+ msg2 = ").compareTo(key(";
+ msg3 = ")) returned ";
+
+ appendCompareResult(keyResult, sResult);
+
+ if (ok2) {
+ logln(msg1 + prettySource + msg2 + prettyTarget + msg3 + sResult);
+ } else {
+ errln(msg1 + prettySource + msg2 + prettyTarget + msg3 + sResult + msg4 + sExpect);
+
+ msg1 = " ";
+ msg2 = " vs. ";
+
+ prettify(sourceKey, prettySource);
+ prettify(targetKey, prettyTarget);
+
+ errln(msg1 + prettySource + msg2 + prettyTarget);
+ }
+ msg1 = UnicodeString (ok3 ? "Ok: incCompare(" : "FAIL: incCompare(");
+ msg2 = ", ";
+ msg3 = ") returned ";
+
+ appendCompareResult(incResult, sResult);
+
+ if (ok3) {
+ logln(msg1 + prettySource + msg2 + prettyTarget + msg3 + sResult);
+ } else {
+ errln(msg1 + prettySource + msg2 + prettyTarget + msg3 + sResult + msg4 + sExpect);
+ }
+ }
+}
+
+UnicodeString&
+IntlTestCollator::appendCompareResult(Collator::EComparisonResult result,
+ UnicodeString& target)
+{
+ if (result == Collator::LESS)
+ {
+ target += "LESS";
+ }
+ else if (result == Collator::EQUAL)
+ {
+ target += "EQUAL";
+ }
+ else if (result == Collator::GREATER)
+ {
+ target += "GREATER";
+ }
+ else
+ {
+ UnicodeString huh = "?";
+
+ target += (huh + (int32_t)result);
+ }
+
+ return target;
+}
+
+// Produce a printable representation of a CollationKey
+UnicodeString &IntlTestCollator::prettify(const CollationKey &source, UnicodeString &target)
+{
+ int32_t i, byteCount;
+ const uint8_t *bytes = source.getByteArray(byteCount);
+
+ target.remove();
+ target += "[";
+
+ for (i = 0; i < byteCount; i += 1)
+ {
+ appendHex(bytes[i], 2, target);
+ target += " ";
+ }
+
+ target += "]";
+
+ return target;
+}
+
+void IntlTestCollator::backAndForth(CollationElementIterator &iter)
+{
+ // Run through the iterator forwards and stick it into an array
+ int32_t orderLength = 0;
+ int32_t *orders = getOrders(iter, orderLength);
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Now go through it backwards and make sure we get the same values
+ int32_t index = orderLength;
+ int32_t o;
+
+ // reset the iterator
+ iter.reset();
+
+ while ((o = iter.previous(status)) != CollationElementIterator::NULLORDER)
+ {
+ if (index == 0) {
+ if(o == 0) {
+ continue;
+ } else { // this is an error, orders exhausted but there are non-ignorable CEs from
+ // going backwards
+ errln("Backward iteration returned a non ignorable after orders are exhausted");
+ break;
+ }
+ }
+ if (o != orders[--index])
+ {
+ if (o == 0)
+ index ++;
+ else
+ {
+ while (index > 0 && orders[--index] == 0)
+ {
+ }
+ if (o != orders[index])
+ {
+ errln("Mismatch at index %d: 0x%X vs 0x%X", index,
+ orders[index], o);
+ break;
+ }
+ }
+ }
+ }
+
+ while (index != 0 && orders[index - 1] == 0)
+ {
+ index --;
+ }
+
+ if (index != 0)
+ {
+ UnicodeString msg("Didn't get back to beginning - index is ");
+ errln(msg + index);
+
+ iter.reset();
+ err("next: ");
+ while ((o = iter.next(status)) != CollationElementIterator::NULLORDER)
+ {
+ UnicodeString hexString("0x");
+
+ appendHex(o, 8, hexString);
+ hexString += " ";
+ err(hexString);
+ }
+ errln("");
+
+ err("prev: ");
+ while ((o = iter.previous(status)) != CollationElementIterator::NULLORDER)
+ {
+ UnicodeString hexString("0x");
+
+ appendHex(o, 8, hexString);
+ hexString += " ";
+ err(hexString);
+ }
+ errln("");
+ }
+
+ delete[] orders;
+}
+
+
+/**
+ * Return an integer array containing all of the collation orders
+ * returned by calls to next on the specified iterator
+ */
+int32_t *IntlTestCollator::getOrders(CollationElementIterator &iter, int32_t &orderLength)
+{
+ int32_t maxSize = 100;
+ int32_t size = 0;
+ int32_t *orders = new int32_t[maxSize];
+ UErrorCode status = U_ZERO_ERROR;
+
+ int32_t order;
+ while ((order = iter.next(status)) != CollationElementIterator::NULLORDER)
+ {
+ if (size == maxSize)
+ {
+ maxSize *= 2;
+ int32_t *temp = new int32_t[maxSize];
+
+ uprv_memcpy(temp, orders, size * sizeof(int32_t));
+ delete[] orders;
+ orders = temp;
+ }
+
+ orders[size++] = order;
+ }
+
+ if (maxSize > size)
+ {
+ int32_t *temp = new int32_t[size];
+
+ uprv_memcpy(temp, orders, size * sizeof(int32_t));
+ delete[] orders;
+ orders = temp;
+ }
+
+ orderLength = size;
+ return orders;
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tscoll.h b/Build/source/libs/icu/icu-xetex/test/intltest/tscoll.h
new file mode 100644
index 00000000000..b3de70f3628
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tscoll.h
@@ -0,0 +1,52 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * MajorTestLevel is the top level test class for everything in the directory "IntlWork".
+ */
+
+#ifndef _INTLTESTCOLLATOR
+#define _INTLTESTCOLLATOR
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "intltest.h"
+#include "unicode/coll.h"
+#include "unicode/coleitr.h"
+
+
+class IntlTestCollator: public IntlTest {
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL );
+protected:
+ // These two should probably go down in IntlTest
+ void doTest(Collator* col, const UChar *source, const UChar *target, Collator::EComparisonResult result);
+
+ void doTest(Collator* col, const UnicodeString &source, const UnicodeString &target, Collator::EComparisonResult result);
+ void doTestVariant(Collator* col, const UnicodeString &source, const UnicodeString &target, Collator::EComparisonResult result);
+ virtual void reportCResult( const UnicodeString &source, const UnicodeString &target,
+ CollationKey &sourceKey, CollationKey &targetKey,
+ Collator::EComparisonResult compareResult,
+ Collator::EComparisonResult keyResult,
+ Collator::EComparisonResult incResult,
+ Collator::EComparisonResult expectedResult );
+
+ static UnicodeString &prettify(const CollationKey &source, UnicodeString &target);
+ static UnicodeString &appendCompareResult(Collator::EComparisonResult result, UnicodeString &target);
+ void backAndForth(CollationElementIterator &iter);
+ /**
+ * Return an integer array containing all of the collation orders
+ * returned by calls to next on the specified iterator
+ */
+ int32_t *getOrders(CollationElementIterator &iter, int32_t &orderLength);
+ UCollationResult compareUsingPartials(UCollator *coll, const UChar source[], int32_t sLen, const UChar target[], int32_t tLen, int32_t pieceSize, UErrorCode &status);
+
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsdate.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tsdate.cpp
new file mode 100644
index 00000000000..00f740ec0a1
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsdate.cpp
@@ -0,0 +1,288 @@
+/***********************************************************************
+ * Copyright (c) 1997-2006, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/datefmt.h"
+#include "unicode/smpdtfmt.h"
+#include "tsdate.h"
+#include "putilimp.h"
+
+#include <float.h>
+#include <stdlib.h>
+#include <math.h>
+
+const double IntlTestDateFormat::ONEYEAR = 365.25 * ONEDAY; // Approximate
+
+IntlTestDateFormat::~IntlTestDateFormat() {}
+
+/**
+ * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
+ * DateFormat.
+ */
+// par is ignored throughout this file
+void IntlTestDateFormat::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite DateFormat");
+ switch (index) {
+ case 0: name = "GenericTest";
+ if (exec) {
+ logln(name);
+ fFormat = DateFormat::createInstance();
+ fTestName = "createInstance";
+ fLimit = 3;
+ testFormat(/* par */);
+ }
+ break;
+ case 1: name = "DefaultLocale";
+ if (exec) {
+ logln(name);
+ testLocale(/*par, */Locale::getDefault(), "Default Locale");
+ }
+ break;
+
+ case 2: name = "TestAvailableLocales";
+ if (exec) {
+ logln(name);
+ testAvailableLocales(/* par */);
+ }
+ break;
+
+ case 3: name = "MonsterTest";
+ if (exec) {
+ logln(name);
+ monsterTest(/*par*/);
+ }
+ break;
+
+ default: name = ""; break;
+ }
+}
+
+void
+IntlTestDateFormat::testLocale(/*char* par, */const Locale& locale, const UnicodeString& localeName)
+{
+ DateFormat::EStyle timeStyle, dateStyle;
+
+ // For patterns including only time information and a timezone, it may take
+ // up to three iterations, since the timezone may shift as the year number
+ // is determined. For other patterns, 2 iterations should suffice.
+ fLimit = 3;
+
+ for(timeStyle = (DateFormat::EStyle)0;
+ timeStyle < (DateFormat::EStyle)4;
+ timeStyle = (DateFormat::EStyle) (timeStyle+1))
+ {
+ fTestName = (UnicodeString) "Time test " + (int32_t) timeStyle + " (" + localeName + ")";
+ fFormat = DateFormat::createTimeInstance(timeStyle, locale);
+ testFormat(/* par */);
+ }
+
+ fLimit = 2;
+
+ for(dateStyle = (DateFormat::EStyle)0;
+ dateStyle < (DateFormat::EStyle)4;
+ dateStyle = (DateFormat::EStyle) (dateStyle+1))
+ {
+ fTestName = (UnicodeString) "Date test " + (int32_t) dateStyle + " (" + localeName + ")";
+ fFormat = DateFormat::createDateInstance(dateStyle, locale);
+ testFormat(/* par */);
+ }
+
+ for(dateStyle = (DateFormat::EStyle)0;
+ dateStyle < (DateFormat::EStyle)4;
+ dateStyle = (DateFormat::EStyle) (dateStyle+1))
+ {
+ for(timeStyle = (DateFormat::EStyle)0;
+ timeStyle < (DateFormat::EStyle)4;
+ timeStyle = (DateFormat::EStyle) (timeStyle+1))
+ {
+ fTestName = (UnicodeString) "DateTime test " + (int32_t) dateStyle + "/" + (int32_t) timeStyle + " (" + localeName + ")";
+ fFormat = DateFormat::createDateTimeInstance(dateStyle, timeStyle, locale);
+ testFormat(/* par */);
+ }
+ }
+}
+
+void IntlTestDateFormat::testFormat(/* char* par */)
+{
+ if (fFormat == 0)
+ {
+ errln("FAIL: DateFormat creation failed");
+ return;
+ }
+
+ describeTest();
+
+ UDate now = Calendar::getNow();
+ tryDate(0);
+ tryDate(1278161801778.0);
+ tryDate(5264498352317.0); // Sunday, October 28, 2136 8:39:12 AM PST
+ tryDate(9516987689250.0); // In the year 2271
+ tryDate(now);
+ // Shift 6 months into the future, AT THE SAME TIME OF DAY.
+ // This will test the DST handling.
+ tryDate(now + 6.0*30*ONEDAY);
+
+ UDate limit = now * 10; // Arbitrary limit
+ for (int32_t i=0; i<3; ++i)
+ tryDate(uprv_floor(randDouble() * limit));
+
+ delete fFormat;
+}
+
+void
+IntlTestDateFormat::describeTest()
+{
+ // Assume it's a SimpleDateFormat and get some info
+ SimpleDateFormat *s = (SimpleDateFormat*)fFormat;
+ UnicodeString str;
+ logln(fTestName + " Pattern " + s->toPattern(str));
+}
+
+void IntlTestDateFormat::tryDate(UDate theDate)
+{
+ const int32_t DEPTH = 10;
+ UDate date[DEPTH];
+ UnicodeString string[DEPTH];
+
+ int32_t dateMatch = 0;
+ int32_t stringMatch = 0;
+ UBool dump = FALSE;
+#if defined (U_CAL_DEBUG)
+ dump = TRUE;
+#endif
+ int32_t i;
+
+ date[0] = theDate;
+ fFormat->format(theDate, string[0]);
+
+ for (i=1; i<DEPTH; ++i)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ date[i] = fFormat->parse(string[i-1], status);
+ if (U_FAILURE(status))
+ {
+ describeTest();
+ errln("**** FAIL: Parse of " + prettify(string[i-1], FALSE) + " failed.");
+ dump = TRUE;
+ break;
+ }
+ fFormat->format(date[i], string[i]);
+ if (dateMatch == 0 && date[i] == date[i-1])
+ dateMatch = i;
+ else if (dateMatch > 0 && date[i] != date[i-1])
+ {
+ describeTest();
+ errln("**** FAIL: Date mismatch after match for " + string[i]);
+ dump = TRUE;
+ break;
+ }
+ if (stringMatch == 0 && string[i] == string[i-1])
+ stringMatch = i;
+ else if (stringMatch > 0 && string[i] != string[i-1])
+ {
+ describeTest();
+ errln("**** FAIL: String mismatch after match for " + string[i]);
+ dump = TRUE;
+ break;
+ }
+ if (dateMatch > 0 && stringMatch > 0)
+ break;
+ }
+ if (i == DEPTH)
+ --i;
+
+ if (stringMatch > fLimit || dateMatch > fLimit)
+ {
+ describeTest();
+ errln((UnicodeString)"**** FAIL: No string and/or date match within " + fLimit
+ + " iterations for the Date " + string[0] + "\t(" + theDate + ").");
+ dump = TRUE;
+ }
+
+ if (dump)
+ {
+ for (int32_t k=0; k<=i; ++k)
+ {
+ logln((UnicodeString)"" + k + ": " + date[k] + " F> " +
+ string[k] + " P> ");
+ }
+ }
+}
+
+// Return a random double from 0.01 to 1, inclusive
+double IntlTestDateFormat::randDouble()
+{
+ // Assume 8-bit (or larger) rand values. Also assume
+ // that the system rand() function is very poor, which it always is.
+ double d=0.0;
+ uint32_t i;
+ char* poke = (char*)&d;
+ do {
+ do {
+ for (i=0; i < sizeof(double); ++i)
+ {
+ poke[i] = (char)(rand() & 0xFF);
+ }
+ } while (uprv_isNaN(d) || uprv_isInfinite(d));
+
+ if (d < 0.0)
+ d = -d;
+ if (d > 0.0)
+ {
+ double e = uprv_floor(log10(d));
+ if (e < -2.0)
+ d *= uprv_pow10((int32_t)(-e-2));
+ else if (e > -1.0)
+ d /= uprv_pow10((int32_t)(e+1));
+ }
+ // While this is not a real normalized number make another one.
+ } while (uprv_isNaN(d) || uprv_isInfinite(d)
+ || !((-DBL_MAX < d && d < DBL_MAX) || (d < -DBL_MIN && DBL_MIN < d)));
+ return d;
+}
+
+void IntlTestDateFormat::testAvailableLocales(/* char* par */)
+{
+ int32_t count = 0;
+ const Locale* locales = DateFormat::getAvailableLocales(count);
+ logln((UnicodeString)"" + count + " available locales");
+ if (locales && count)
+ {
+ UnicodeString name;
+ UnicodeString all;
+ for (int32_t i=0; i<count; ++i)
+ {
+ if (i!=0) all += ", ";
+ all += locales[i].getName();
+ }
+ logln(all);
+ }
+ else errln((UnicodeString)"**** FAIL: Zero available locales or null array pointer");
+}
+
+void IntlTestDateFormat::monsterTest(/*char *par*/)
+{
+ int32_t count;
+ const Locale* locales = DateFormat::getAvailableLocales(count);
+ if (locales && count)
+ {
+ if (quick && count > 3) {
+ logln("quick test: testing just 3 locales!");
+ count = 3;
+ }
+ for (int32_t i=0; i<count; ++i)
+ {
+ UnicodeString name = UnicodeString(locales[i].getName(), "");
+ logln((UnicodeString)"Testing " + name + "...");
+ testLocale(/*par, */locales[i], name);
+ }
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsdate.h b/Build/source/libs/icu/icu-xetex/test/intltest/tsdate.h
new file mode 100644
index 00000000000..2707bacde24
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsdate.h
@@ -0,0 +1,82 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _INTLTESTDATEFORMAT
+#define _INTLTESTDATEFORMAT
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/datefmt.h"
+#include "intltest.h"
+
+/**
+ * Performs some tests in many variations on DateFormat
+ **/
+class IntlTestDateFormat: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+private:
+
+ /**
+ * test DateFormat::getAvailableLocales
+ **/
+ void testAvailableLocales(/* char* par */);
+ /**
+ * call testLocale for all locales
+ **/
+ void monsterTest(/* char *par */);
+
+ /**
+ * call tryDate with variations, called by testLocale
+ **/
+ void testFormat(/* char* par */);
+ /**
+ * perform tests using date and fFormat, called in many variations
+ **/
+ void tryDate(UDate date);
+ /**
+ * call testFormat for different DateFormat::EStyle's, etc
+ **/
+ void testLocale(/*char *par, */const Locale&, const UnicodeString&);
+ /**
+ * return a random number
+ **/
+ double randDouble(void);
+ /**
+ * generate description for verbose test output
+ **/
+ void describeTest(void);
+
+ DateFormat *fFormat;
+ UnicodeString fTestName;
+ int32_t fLimit; // How many iterations it should take to reach convergence
+
+ enum
+ {
+ // Values in milliseconds (== Date)
+ ONESECOND = 1000,
+ ONEMINUTE = 60 * ONESECOND,
+ ONEHOUR = 60 * ONEMINUTE,
+ ONEDAY = 24 * ONEHOUR
+ };
+ static const double ONEYEAR;
+ enum EMode
+ {
+ GENERIC,
+ TIME,
+ DATE,
+ DATE_TIME
+ };
+public:
+ virtual ~IntlTestDateFormat();
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsdcfmsy.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tsdcfmsy.cpp
new file mode 100644
index 00000000000..e243eec1a1f
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsdcfmsy.cpp
@@ -0,0 +1,185 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/unum.h"
+#include "tsdcfmsy.h"
+
+void IntlTestDecimalFormatSymbols::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite DecimalFormatSymbols");
+ switch (index) {
+ case 0: name = "DecimalFormatSymbols test";
+ if (exec) {
+ logln("DecimalFormatSymbols test---"); logln("");
+ testSymbols(/*par*/);
+ }
+ break;
+
+ default: name = ""; break;
+ }
+}
+
+/**
+ * Test the API of DecimalFormatSymbols; primarily a simple get/set set.
+ */
+void IntlTestDecimalFormatSymbols::testSymbols(/* char *par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ DecimalFormatSymbols fr(Locale::getFrench(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Couldn't create French DecimalFormatSymbols");
+ }
+
+ status = U_ZERO_ERROR;
+ DecimalFormatSymbols en(Locale::getEnglish(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Couldn't create English DecimalFormatSymbols");
+ }
+
+ if(en == fr || ! (en != fr) ) {
+ errln("ERROR: English DecimalFormatSymbols equal to French");
+ }
+
+ // just do some VERY basic tests to make sure that get/set work
+
+ UnicodeString zero = en.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol);
+ fr.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, zero);
+ if(fr.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol) != en.getSymbol(DecimalFormatSymbols::kZeroDigitSymbol)) {
+ errln("ERROR: get/set ZeroDigit failed");
+ }
+
+ UnicodeString group = en.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
+ fr.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, group);
+ if(fr.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol) != en.getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol)) {
+ errln("ERROR: get/set GroupingSeparator failed");
+ }
+
+ UnicodeString decimal = en.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
+ fr.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, decimal);
+ if(fr.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol) != en.getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol)) {
+ errln("ERROR: get/set DecimalSeparator failed");
+ }
+
+ UnicodeString perMill = en.getSymbol(DecimalFormatSymbols::kPerMillSymbol);
+ fr.setSymbol(DecimalFormatSymbols::kPerMillSymbol, perMill);
+ if(fr.getSymbol(DecimalFormatSymbols::kPerMillSymbol) != en.getSymbol(DecimalFormatSymbols::kPerMillSymbol)) {
+ errln("ERROR: get/set PerMill failed");
+ }
+
+ UnicodeString percent = en.getSymbol(DecimalFormatSymbols::kPercentSymbol);
+ fr.setSymbol(DecimalFormatSymbols::kPercentSymbol, percent);
+ if(fr.getSymbol(DecimalFormatSymbols::kPercentSymbol) != en.getSymbol(DecimalFormatSymbols::kPercentSymbol)) {
+ errln("ERROR: get/set Percent failed");
+ }
+
+ UnicodeString digit(en.getSymbol(DecimalFormatSymbols::kDigitSymbol));
+ fr.setSymbol(DecimalFormatSymbols::kDigitSymbol, digit);
+ if(fr.getSymbol(DecimalFormatSymbols::kDigitSymbol) != en.getSymbol(DecimalFormatSymbols::kDigitSymbol)) {
+ errln("ERROR: get/set Percent failed");
+ }
+
+ UnicodeString patternSeparator = en.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol);
+ fr.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, patternSeparator);
+ if(fr.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol) != en.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol)) {
+ errln("ERROR: get/set PatternSeparator failed");
+ }
+
+ UnicodeString infinity(en.getSymbol(DecimalFormatSymbols::kInfinitySymbol));
+ fr.setSymbol(DecimalFormatSymbols::kInfinitySymbol, infinity);
+ UnicodeString infinity2(fr.getSymbol(DecimalFormatSymbols::kInfinitySymbol));
+ if(infinity != infinity2) {
+ errln("ERROR: get/set Infinity failed");
+ }
+
+ UnicodeString nan(en.getSymbol(DecimalFormatSymbols::kNaNSymbol));
+ fr.setSymbol(DecimalFormatSymbols::kNaNSymbol, nan);
+ UnicodeString nan2(fr.getSymbol(DecimalFormatSymbols::kNaNSymbol));
+ if(nan != nan2) {
+ errln("ERROR: get/set NaN failed");
+ }
+
+ UnicodeString minusSign = en.getSymbol(DecimalFormatSymbols::kMinusSignSymbol);
+ fr.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, minusSign);
+ if(fr.getSymbol(DecimalFormatSymbols::kMinusSignSymbol) != en.getSymbol(DecimalFormatSymbols::kMinusSignSymbol)) {
+ errln("ERROR: get/set MinusSign failed");
+ }
+
+ UnicodeString exponential(en.getSymbol(DecimalFormatSymbols::kExponentialSymbol));
+ fr.setSymbol(DecimalFormatSymbols::kExponentialSymbol, exponential);
+ if(fr.getSymbol(DecimalFormatSymbols::kExponentialSymbol) != en.getSymbol(DecimalFormatSymbols::kExponentialSymbol)) {
+ errln("ERROR: get/set Exponential failed");
+ }
+
+ status = U_ZERO_ERROR;
+ DecimalFormatSymbols foo(status);
+
+ DecimalFormatSymbols bar(foo);
+
+ en = fr;
+
+ if(en != fr || foo != bar) {
+ errln("ERROR: Copy Constructor or Assignment failed");
+ }
+
+ // test get/setSymbol()
+ if((int) UNUM_FORMAT_SYMBOL_COUNT != (int) DecimalFormatSymbols::kFormatSymbolCount) {
+ errln("unum.h and decimfmt.h have inconsistent numbers of format symbols!");
+ return;
+ }
+
+ int i;
+ for(i = 0; i < (int)DecimalFormatSymbols::kFormatSymbolCount; ++i) {
+ foo.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i, UnicodeString((UChar32)(0x10330 + i)));
+ }
+ for(i = 0; i < (int)DecimalFormatSymbols::kFormatSymbolCount; ++i) {
+ if(foo.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i) != UnicodeString((UChar32)(0x10330 + i))) {
+ errln("get/setSymbol did not roundtrip, got " +
+ foo.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)i) +
+ ", expected " +
+ UnicodeString((UChar32)(0x10330 + i)));
+ }
+ }
+
+
+ DecimalFormatSymbols sym(Locale::getUS(), status);
+
+ UnicodeString customDecSeperator("S");
+ Verify(34.5, (UnicodeString)"00.00", sym, (UnicodeString)"34.50");
+ sym.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)0, customDecSeperator);
+ Verify(34.5, (UnicodeString)"00.00", sym, (UnicodeString)"34S50");
+ sym.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)3, (UnicodeString)"P");
+ Verify(34.5, (UnicodeString)"00 %", sym, (UnicodeString)"3450 P");
+ sym.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)8, (UnicodeString)"D");
+ Verify(34.5, CharsToUnicodeString("\\u00a4##.##"), sym, (UnicodeString)"D34.5");
+ sym.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)1, (UnicodeString)"|");
+ Verify(3456.5, (UnicodeString)"0,000.##", sym, (UnicodeString)"3|456S5");
+
+}
+
+void IntlTestDecimalFormatSymbols::Verify(double value, const UnicodeString& pattern, DecimalFormatSymbols sym, const UnicodeString& expected){
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = new DecimalFormat(pattern, sym, status);
+ if(U_FAILURE(status)){
+ errln("ERROR: construction of decimal format failed");
+ }
+ UnicodeString buffer;
+ FieldPosition pos(FieldPosition::DONT_CARE);
+ buffer = df->format(value, buffer, pos);
+ if(buffer != expected){
+ errln((UnicodeString)"ERROR: format failed after setSymbols()\n Expected " +
+ expected + ", Got " + buffer);
+ }
+ delete df;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsdcfmsy.h b/Build/source/libs/icu/icu-xetex/test/intltest/tsdcfmsy.h
new file mode 100644
index 00000000000..828d0f434ad
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsdcfmsy.h
@@ -0,0 +1,35 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2001, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _INTLTESTDECIMALFORMATSYMBOLS
+#define _INTLTESTDECIMALFORMATSYMBOLS
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/unistr.h"
+#include "unicode/dcfmtsym.h"
+#include "intltest.h"
+/**
+ * Tests for DecimalFormatSymbols
+ **/
+class IntlTestDecimalFormatSymbols: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+private:
+ /**
+ * Test the API of DecimalFormatSymbols; primarily a simple get/set set.
+ */
+ void testSymbols(/*char *par*/);
+
+ /** helper functions**/
+ void Verify(double value, const UnicodeString& pattern, DecimalFormatSymbols sym, const UnicodeString& expected);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsdtfmsy.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tsdtfmsy.cpp
new file mode 100644
index 00000000000..3aae499398e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsdtfmsy.cpp
@@ -0,0 +1,347 @@
+/********************************************************************
+ * Copyright (c) 1997-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tsdtfmsy.h"
+
+#include "unicode/dtfmtsym.h"
+
+
+//--------------------------------------------------------------------
+// Time bomb - allows temporary behavior that expires at a given
+// release
+//--------------------------------------------------------------------
+
+void IntlTestDateFormatSymbols::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite DateFormatSymbols");
+ switch (index) {
+ TESTCASE(0,TestSymbols);
+ TESTCASE(1,TestGetMonths);
+ TESTCASE(2,TestGetMonths2);
+ TESTCASE(3,TestGetWeekdays2);
+ TESTCASE(4,TestGetEraNames);
+ default: name = ""; break;
+ }
+}
+
+/**
+ * Test getMonths.
+ */
+void IntlTestDateFormatSymbols::TestGetMonths()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t cnt;
+ const UnicodeString* month;
+ DateFormatSymbols *symbol;
+
+ symbol=new DateFormatSymbols(Locale::getDefault(), status);
+
+ month=symbol->getMonths(cnt);
+
+ logln((UnicodeString)"size = " + cnt);
+
+ for (int32_t i=0; i<cnt; ++i)
+ {
+ logln(month[i]);
+ }
+
+ delete symbol;
+}
+
+void IntlTestDateFormatSymbols::TestGetMonths2()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormatSymbols *symbol;
+
+ symbol=new DateFormatSymbols(Locale::getDefault(), status);
+
+ DateFormatSymbols::DtContextType context[] = {DateFormatSymbols::STANDALONE, DateFormatSymbols::FORMAT};
+ DateFormatSymbols::DtWidthType width[] = {DateFormatSymbols::WIDE, DateFormatSymbols::ABBREVIATED, DateFormatSymbols::NARROW};
+
+ for (int32_t i = 0; i < 2; i++) {
+ for (int32_t j = 0; j < 3; j++) {
+ int32_t cnt;
+ const UnicodeString * month = symbol->getMonths(cnt,context[i],width[j]);
+
+ logln((UnicodeString)"size = " + cnt);
+
+ for (int32_t k = 0; k < cnt; k++) {
+ logln(month[k]);
+ }
+ }
+ }
+ delete symbol;
+}
+
+void IntlTestDateFormatSymbols::TestGetWeekdays2()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DateFormatSymbols *symbol;
+
+ symbol=new DateFormatSymbols(Locale::getDefault(), status);
+
+ DateFormatSymbols::DtContextType context[] = {DateFormatSymbols::STANDALONE, DateFormatSymbols::FORMAT};
+ DateFormatSymbols::DtWidthType width[] = {DateFormatSymbols::WIDE, DateFormatSymbols::ABBREVIATED, DateFormatSymbols::NARROW};
+
+ for (int32_t i = 0; i < 2; i++) {
+ for (int32_t j = 0; j < 3; j++) {
+ int32_t cnt;
+ const UnicodeString * wd = symbol->getWeekdays(cnt,context[i],width[j]);
+
+ logln((UnicodeString)"size = " + cnt);
+
+ for (int32_t k = 0; k < cnt; k++) {
+ logln(wd[k]);
+ }
+ }
+ }
+ delete symbol;
+}
+
+
+void IntlTestDateFormatSymbols::TestGetEraNames()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t cnt;
+ const UnicodeString* name;
+ DateFormatSymbols *symbol;
+
+ symbol=new DateFormatSymbols(Locale::getDefault(), status);
+
+ name=symbol->getEraNames(cnt);
+
+ logln((UnicodeString)"size = " + cnt);
+
+ for (int32_t i=0; i<cnt; ++i)
+ {
+ logln(name[i]);
+ }
+
+ delete symbol;
+}
+
+/**
+ * Test the API of DateFormatSymbols; primarily a simple get/set set.
+ */
+void IntlTestDateFormatSymbols::TestSymbols(/* char *par */)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ DateFormatSymbols fr(Locale::getFrench(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Couldn't create French DateFormatSymbols " + (UnicodeString)u_errorName(status));
+ }
+
+ status = U_ZERO_ERROR;
+ DateFormatSymbols fr2(Locale::getFrench(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Couldn't create French DateFormatSymbols " + (UnicodeString)u_errorName(status));
+ }
+
+ status = U_ZERO_ERROR;
+ DateFormatSymbols en(Locale::getEnglish(), status);
+ if(U_FAILURE(status)) {
+ errln("ERROR: Couldn't create English DateFormatSymbols " + (UnicodeString)u_errorName(status));
+ }
+
+ if(en == fr || ! (en != fr) ) {
+ errln("ERROR: English DateFormatSymbols equal to French");
+ }
+
+ // just do some VERY basic tests to make sure that get/set work
+
+ int32_t count = 0;
+ const UnicodeString *eras = en.getEras(count);
+ if(count == 0) {
+ errln("ERROR: 0 english eras.. exitting..\n");
+ return;
+ }
+
+ fr.setEras(eras, count);
+ if( *en.getEras(count) != *fr.getEras(count)) {
+ errln("ERROR: setEras() failed");
+ }
+
+ const UnicodeString *months = en.getMonths(count);
+ fr.setMonths(months, count);
+ if( *en.getMonths(count) != *fr.getMonths(count)) {
+ errln("ERROR: setMonths() failed");
+ }
+
+ const UnicodeString *shortMonths = en.getShortMonths(count);
+ fr.setShortMonths(shortMonths, count);
+ if( *en.getShortMonths(count) != *fr.getShortMonths(count)) {
+ errln("ERROR: setShortMonths() failed");
+ }
+
+ const UnicodeString *wideMonths = en.getMonths(count,DateFormatSymbols::FORMAT,DateFormatSymbols::WIDE);
+ fr2.setMonths(wideMonths, count, DateFormatSymbols::FORMAT,DateFormatSymbols::WIDE);
+ if( *en.getMonths(count,DateFormatSymbols::FORMAT,DateFormatSymbols::WIDE) !=
+ *fr2.getMonths(count,DateFormatSymbols::FORMAT,DateFormatSymbols::WIDE )) {
+ errln("ERROR: setMonths(FORMAT,WIDE) failed");
+ }
+
+ const UnicodeString *abbrMonths = en.getMonths(count,DateFormatSymbols::FORMAT,DateFormatSymbols::ABBREVIATED);
+ fr2.setMonths(abbrMonths, count, DateFormatSymbols::FORMAT,DateFormatSymbols::ABBREVIATED);
+ if( *en.getMonths(count,DateFormatSymbols::FORMAT,DateFormatSymbols::ABBREVIATED) !=
+ *fr2.getMonths(count,DateFormatSymbols::FORMAT,DateFormatSymbols::ABBREVIATED )) {
+ errln("ERROR: setMonths(FORMAT,ABBREVIATED) failed");
+ }
+
+ const UnicodeString *narrowMonths = en.getMonths(count,DateFormatSymbols::FORMAT,DateFormatSymbols::NARROW);
+ fr.setMonths(narrowMonths, count, DateFormatSymbols::FORMAT,DateFormatSymbols::NARROW);
+ if( *en.getMonths(count,DateFormatSymbols::FORMAT,DateFormatSymbols::NARROW) !=
+ *fr.getMonths(count,DateFormatSymbols::FORMAT,DateFormatSymbols::NARROW )) {
+ errln("ERROR: setMonths(FORMAT,NARROW) failed");
+ }
+
+ const UnicodeString *standaloneWideMonths = en.getMonths(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::WIDE);
+ fr.setMonths(standaloneWideMonths, count, DateFormatSymbols::STANDALONE,DateFormatSymbols::WIDE);
+ if( *en.getMonths(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::WIDE) !=
+ *fr.getMonths(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::WIDE )) {
+ errln("ERROR: setMonths(STANDALONE,WIDE) failed");
+ }
+
+ const UnicodeString *standaloneShortMonths = en.getMonths(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::ABBREVIATED);
+ fr.setMonths(standaloneShortMonths, count, DateFormatSymbols::STANDALONE,DateFormatSymbols::ABBREVIATED);
+ if( *en.getMonths(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::ABBREVIATED) !=
+ *fr.getMonths(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::ABBREVIATED )) {
+ errln("ERROR: setMonths(STANDALONE,ABBREVIATED) failed");
+ }
+
+ const UnicodeString *standaloneNarrowMonths = en.getMonths(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::NARROW);
+ fr.setMonths(standaloneNarrowMonths, count, DateFormatSymbols::STANDALONE,DateFormatSymbols::NARROW);
+ if( *en.getMonths(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::NARROW) !=
+ *fr.getMonths(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::NARROW )) {
+ errln("ERROR: setMonths(STANDALONE,NARROW) failed");
+ }
+
+ const UnicodeString *weekdays = en.getWeekdays(count);
+ fr.setWeekdays(weekdays, count);
+ if( *en.getWeekdays(count) != *fr.getWeekdays(count)) {
+ errln("ERROR: setWeekdays() failed");
+ }
+
+ const UnicodeString *shortWeekdays = en.getShortWeekdays(count);
+ fr.setShortWeekdays(shortWeekdays, count);
+ if( *en.getShortWeekdays(count) != *fr.getShortWeekdays(count)) {
+ errln("ERROR: setShortWeekdays() failed");
+ }
+
+ const UnicodeString *wideWeekdays = en.getWeekdays(count,DateFormatSymbols::FORMAT,DateFormatSymbols::WIDE);
+ fr2.setWeekdays(wideWeekdays, count, DateFormatSymbols::FORMAT,DateFormatSymbols::WIDE);
+ if( *en.getWeekdays(count,DateFormatSymbols::FORMAT,DateFormatSymbols::WIDE) !=
+ *fr2.getWeekdays(count,DateFormatSymbols::FORMAT,DateFormatSymbols::WIDE )) {
+ errln("ERROR: setWeekdays(FORMAT,WIDE) failed");
+ }
+
+ const UnicodeString *abbrWeekdays = en.getWeekdays(count,DateFormatSymbols::FORMAT,DateFormatSymbols::ABBREVIATED);
+ fr2.setWeekdays(abbrWeekdays, count, DateFormatSymbols::FORMAT,DateFormatSymbols::ABBREVIATED);
+ if( *en.getWeekdays(count,DateFormatSymbols::FORMAT,DateFormatSymbols::ABBREVIATED) !=
+ *fr2.getWeekdays(count,DateFormatSymbols::FORMAT,DateFormatSymbols::ABBREVIATED )) {
+ errln("ERROR: setWeekdays(FORMAT,ABBREVIATED) failed");
+ }
+
+ const UnicodeString *narrowWeekdays = en.getWeekdays(count,DateFormatSymbols::FORMAT,DateFormatSymbols::NARROW);
+ fr.setWeekdays(narrowWeekdays, count, DateFormatSymbols::FORMAT,DateFormatSymbols::NARROW);
+ if( *en.getWeekdays(count,DateFormatSymbols::FORMAT,DateFormatSymbols::NARROW) !=
+ *fr.getWeekdays(count,DateFormatSymbols::FORMAT,DateFormatSymbols::NARROW )) {
+ errln("ERROR: setWeekdays(FORMAT,NARROW) failed");
+ }
+
+ const UnicodeString *standaloneWideWeekdays = en.getWeekdays(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::WIDE);
+ fr.setWeekdays(standaloneWideWeekdays, count, DateFormatSymbols::STANDALONE,DateFormatSymbols::WIDE);
+ if( *en.getWeekdays(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::WIDE) !=
+ *fr.getWeekdays(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::WIDE )) {
+ errln("ERROR: setWeekdays(STANDALONE,WIDE) failed");
+ }
+
+ const UnicodeString *standaloneShortWeekdays = en.getWeekdays(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::ABBREVIATED);
+ fr.setWeekdays(standaloneShortWeekdays, count, DateFormatSymbols::STANDALONE,DateFormatSymbols::ABBREVIATED);
+ if( *en.getWeekdays(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::ABBREVIATED) !=
+ *fr.getWeekdays(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::ABBREVIATED )) {
+ errln("ERROR: setWeekdays(STANDALONE,ABBREVIATED) failed");
+ }
+
+ const UnicodeString *standaloneNarrowWeekdays = en.getWeekdays(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::NARROW);
+ fr.setWeekdays(standaloneNarrowWeekdays, count, DateFormatSymbols::STANDALONE,DateFormatSymbols::NARROW);
+ if( *en.getWeekdays(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::NARROW) !=
+ *fr.getWeekdays(count,DateFormatSymbols::STANDALONE,DateFormatSymbols::NARROW )) {
+ errln("ERROR: setWeekdays(STANDALONE,NARROW) failed");
+ }
+
+ const UnicodeString *wideQuarters = en.getQuarters(count,DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ fr2.setQuarters(wideQuarters, count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
+ if( *en.getQuarters(count,DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE) !=
+ *fr2.getQuarters(count,DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE )) {
+ errln("ERROR: setQuarters(FORMAT, WIDE) failed");
+ }
+
+ const UnicodeString *abbrQuarters = en.getQuarters(count,DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ fr2.setQuarters(abbrQuarters, count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
+ if( *en.getQuarters(count,DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED) !=
+ *fr2.getQuarters(count,DateFormatSymbols::FORMAT ,DateFormatSymbols::ABBREVIATED )) {
+ errln("ERROR: setQuarters(FORMAT, ABBREVIATED) failed");
+ }
+
+ const UnicodeString *standaloneWideQuarters = en.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ fr.setQuarters(standaloneWideQuarters, count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
+ if( *en.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE) !=
+ *fr.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE )) {
+ errln("ERROR: setQuarters(STANDALONE, WIDE) failed");
+ }
+
+ const UnicodeString *standaloneShortQuarters = en.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ fr.setQuarters(standaloneShortQuarters, count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
+ if( *en.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED) !=
+ *fr.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED )) {
+ errln("ERROR: setQuarters(STANDALONE, ABBREVIATED) failed");
+ }
+
+ const UnicodeString *ampms = en.getAmPmStrings(count);
+ fr.setAmPmStrings(ampms, count);
+ if( *en.getAmPmStrings(count) != *fr.getAmPmStrings(count)) {
+ errln("ERROR: setAmPmStrings() failed");
+ }
+
+ int32_t rowCount = 0, columnCount = 0;
+ const UnicodeString **strings = en.getZoneStrings(rowCount, columnCount);
+ fr.setZoneStrings(strings, rowCount, columnCount);
+ const UnicodeString **strings1 = fr.getZoneStrings(rowCount, columnCount);
+ for(int32_t i = 0; i < rowCount; i++) {
+ for(int32_t j = 0; j < columnCount; j++) {
+ if( strings[i][j] != strings1[i][j] ) {
+ errln("ERROR: setZoneStrings() failed");
+ }
+ }
+ }
+
+ UnicodeString localPattern, pat1, pat2;
+ localPattern = en.getLocalPatternChars(localPattern);
+ fr.setLocalPatternChars(localPattern);
+ if( en.getLocalPatternChars(pat1) != fr.getLocalPatternChars(pat2)) {
+ errln("ERROR: setLocalPatternChars() failed");
+ }
+
+
+ status = U_ZERO_ERROR;
+ DateFormatSymbols foo(status);
+ DateFormatSymbols bar(foo);
+
+ en = fr;
+
+ if(en != fr) {
+ errln("ERROR: Assignment operator failed");
+ }
+ if(foo != bar) {
+ errln("ERROR: Copy Constructor failed");
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsdtfmsy.h b/Build/source/libs/icu/icu-xetex/test/intltest/tsdtfmsy.h
new file mode 100644
index 00000000000..d289ba4f751
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsdtfmsy.h
@@ -0,0 +1,39 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _INTLTESTDATEFORMATSYMBOLS
+#define _INTLTESTDATEFORMATSYMBOLS
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+/**
+ * Tests for DateFormatSymbols
+ **/
+class IntlTestDateFormatSymbols: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+private:
+ /**
+ * Test the API of DateFormatSymbols; primarily a simple get/set set.
+ */
+ void TestSymbols(/* char *par */);
+ /**
+ * Test getMonths.
+ */
+ void TestGetMonths(void);
+ void TestGetMonths2(void);
+
+ void TestGetWeekdays2(void);
+ void TestGetEraNames(void);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsmthred.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tsmthred.cpp
new file mode 100644
index 00000000000..3dd8e3da980
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsmthred.cpp
@@ -0,0 +1,1585 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1999-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#if defined(hpux)
+# ifndef _INCLUDE_POSIX_SOURCE
+# define _INCLUDE_POSIX_SOURCE
+# endif
+#endif
+
+/* Needed by z/OS to get usleep */
+#if !defined(_XOPEN_SOURCE_EXTENDED)
+#define _XOPEN_SOURCE_EXTENDED 1
+#endif
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "umutex.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "uparse.h"
+#include "unicode/resbund.h"
+#include "unicode/udata.h"
+#include "unicode/uloc.h"
+#include "unicode/locid.h"
+#include "putilimp.h"
+#if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY)
+#define POSIX 1
+#endif
+
+#if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX)
+
+#define HAVE_IMP
+
+#if (ICU_USE_THREADS == 1)
+#include <pthread.h>
+#endif
+
+#if defined(__hpux) && defined(HPUX_CMA)
+# if defined(read) // read being defined as cma_read causes trouble with iostream::read
+# undef read
+# endif
+#endif
+
+/* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__
+#endif
+
+#include <signal.h>
+
+/* Define _XPG4_2 for Solaris and friends. */
+#ifndef _XPG4_2
+#define _XPG4_2
+#endif
+
+/* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
+#ifndef __USE_XOPEN_EXTENDED
+#define __USE_XOPEN_EXTENDED
+#endif
+
+/* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
+#ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
+#define _INCLUDE_XOPEN_SOURCE_EXTENDED
+#endif
+
+#include <unistd.h>
+
+#endif
+/* HPUX */
+#ifdef sleep
+#undef sleep
+#endif
+
+
+
+#include "tsmthred.h"
+
+#define TSMTHREAD_FAIL(msg) errln("%s at file %s, line %d", msg, __FILE__, __LINE__)
+#define TSMTHREAD_ASSERT(expr) {if (!(expr)) {TSMTHREAD_FAIL("Fail");}}
+
+MultithreadTest::MultithreadTest()
+{
+}
+
+MultithreadTest::~MultithreadTest()
+{
+}
+
+
+
+#if (ICU_USE_THREADS==0)
+void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
+ const char* &name, char* /*par*/ ) {
+ if (exec) logln("TestSuite MultithreadTest: ");
+
+ if(index == 0)
+ name = "NO_THREADED_TESTS";
+ else
+ name = "";
+
+ if(exec) { logln("MultithreadTest - test DISABLED. ICU_USE_THREADS set to 0, check your configuration if this is a problem..");
+ }
+}
+#else
+
+
+
+// Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
+// Note: A LOT OF THE FUNCTIONS IN THIS FILE SHOULD LIVE ELSEWHERE!!!!!
+// -srl
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h> // tolower, toupper
+
+#include "unicode/putil.h"
+
+/* for mthreadtest*/
+#include "unicode/numfmt.h"
+#include "unicode/choicfmt.h"
+#include "unicode/msgfmt.h"
+#include "unicode/locid.h"
+#include "unicode/ucol.h"
+#include "unicode/calendar.h"
+#include "ucaconf.h"
+
+//-----------------------------------------------------------------------------------
+//
+// class SimpleThread Of course we need a thread class first..
+// This wrapper has a ported implementation.
+//
+//-----------------------------------------------------------------------------------
+class SimpleThread
+{
+public:
+ SimpleThread();
+ virtual ~SimpleThread();
+ int32_t start(void); // start the thread
+ UBool isRunning(); // return true if a started thread has exited.
+
+ virtual void run(void) = 0; // Override this to provide the code to run
+ // in the thread.
+ void *fImplementation;
+
+public:
+ static void sleep(int32_t millis); // probably shouldn't go here but oh well.
+ static void errorFunc(); // Empty function, provides a single convenient place
+ // to break on errors.
+};
+
+void SimpleThread::errorFunc() {
+ // *(char *)0 = 3; // Force entry into a debugger via a crash;
+}
+
+
+
+
+#ifdef U_WINDOWS
+#define HAVE_IMP
+
+# define VC_EXTRALEAN
+# define WIN32_LEAN_AND_MEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+#include <windows.h>
+#include <process.h>
+
+
+
+//-----------------------------------------------------------------------------------
+//
+// class SimpleThread Windows Implementation
+//
+//-----------------------------------------------------------------------------------
+struct Win32ThreadImplementation
+{
+ HANDLE fHandle;
+ unsigned int fThreadID;
+};
+
+
+extern "C" unsigned int __stdcall SimpleThreadProc(void *arg)
+{
+ ((SimpleThread*)arg)->run();
+ return 0;
+}
+
+SimpleThread::SimpleThread()
+:fImplementation(0)
+{
+ Win32ThreadImplementation *imp = new Win32ThreadImplementation;
+ imp->fHandle = 0;
+ fImplementation = imp;
+}
+
+SimpleThread::~SimpleThread()
+{
+ // Destructor. Because we start the thread running with _beginthreadex(),
+ // we own the Windows HANDLE for the thread and must
+ // close it here.
+ Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
+ if (imp != 0) {
+ if (imp->fHandle != 0) {
+ CloseHandle(imp->fHandle);
+ imp->fHandle = 0;
+ }
+ }
+ delete (Win32ThreadImplementation*)fImplementation;
+}
+
+int32_t SimpleThread::start()
+{
+ Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
+ if(imp->fHandle != NULL) {
+ // The thread appears to have already been started.
+ // This is probably an error on the part of our caller.
+ return -1;
+ }
+
+ imp->fHandle = (HANDLE) _beginthreadex(
+ NULL, // Security
+ 0x20000, // Stack Size
+ SimpleThreadProc, // Function to Run
+ (void *)this, // Arg List
+ 0, // initflag. Start running, not suspended
+ &imp->fThreadID // thraddr
+ );
+
+ if (imp->fHandle == 0) {
+ // An error occured
+ int err = errno;
+ if (err == 0) {
+ err = -1;
+ }
+ return err;
+ }
+ return 0;
+}
+
+
+UBool SimpleThread::isRunning() {
+ //
+ // Test whether the thread associated with the SimpleThread object is
+ // still actually running.
+ //
+ // NOTE: on Win64 on Itanium processors, a crashes
+ // occur if the main thread of a process exits concurrently with some
+ // other thread(s) exiting. To avoid the possibility, we wait until the
+ // OS indicates that all threads have terminated, rather than waiting
+ // only until the end of the user's Run function has been reached.
+ //
+ // I don't know whether the crashes represent a Windows bug, or whether
+ // main() programs are supposed to have to wait for their threads.
+ //
+ Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
+
+ bool success;
+ DWORD threadExitCode;
+
+ if (imp->fHandle == 0) {
+ // No handle, thread must not be running.
+ return FALSE;
+ }
+ success = GetExitCodeThread(imp->fHandle, &threadExitCode) != 0;
+ if (! success) {
+ // Can't get status, thread must not be running.
+ return FALSE;
+ }
+ return (threadExitCode == STILL_ACTIVE);
+}
+
+
+void SimpleThread::sleep(int32_t millis)
+{
+ ::Sleep(millis);
+}
+
+//-----------------------------------------------------------------------------------
+//
+// class SimpleThread NULL Implementation
+//
+//-----------------------------------------------------------------------------------
+#elif defined XP_MAC
+
+// since the Mac has no preemptive threading (at least on MacOS 8), only
+// cooperative threading, threads are a no-op. We have no yield() calls
+// anywhere in the ICU, so we are guaranteed to be thread-safe.
+
+#define HAVE_IMP
+
+SimpleThread::SimpleThread()
+{}
+
+SimpleThread::~SimpleThread()
+{}
+
+int32_t
+SimpleThread::start()
+{ return 0; }
+
+void
+SimpleThread::run()
+{}
+
+void
+SimpleThread::sleep(int32_t millis)
+{}
+
+UBool
+SimpleThread::isRunning() {
+ return FALSE;
+}
+
+#endif
+
+
+//-----------------------------------------------------------------------------------
+//
+// class SimpleThread POSIX implementation
+//
+// A note on the POSIX vs the Windows implementations of this class..
+// On Windows, the main thread must verify that other threads have finished
+// before exiting, or crashes occasionally occur. (Seen on Itanium Win64 only)
+// The function SimpleThread::isRunning() is used for this purpose.
+//
+// On POSIX, there is NO reliable non-blocking mechanism to determine
+// whether a thread has exited. pthread_kill(thread, 0) almost works,
+// but the system can recycle thread ids immediately, so seeing that a
+// thread exists with this call could mean that the original thread has
+// finished and a new one started with the same ID. Useless.
+//
+// So we need to do the check with user code, by setting a flag just before
+// the thread function returns. A technique that is guaranteed to fail
+// on Windows, because it indicates that the thread is done before all
+// system level cleanup has happened.
+//
+//-----------------------------------------------------------------------------------
+#if defined(POSIX)||defined(U_SOLARIS)||defined(U_AIX)||defined(U_HPUX)
+#define HAVE_IMP
+
+struct PosixThreadImplementation
+{
+ pthread_t fThread;
+ UBool fRunning;
+ UBool fRan; /* True if the thread was successfully started */
+};
+
+extern "C" void* SimpleThreadProc(void *arg)
+{
+ // This is the code that is run in the new separate thread.
+ SimpleThread *This = (SimpleThread *)arg;
+ This->run(); // Run the user code.
+
+ // The user function has returned. Set the flag indicating that this thread
+ // is done. Need a mutex for memory barrier purposes only, so that other thread
+ // will reliably see that the flag has changed.
+ PosixThreadImplementation *imp = (PosixThreadImplementation*)This->fImplementation;
+ umtx_lock(NULL);
+ imp->fRunning = FALSE;
+ umtx_unlock(NULL);
+ return 0;
+}
+
+SimpleThread::SimpleThread()
+{
+ PosixThreadImplementation *imp = new PosixThreadImplementation;
+ imp->fRunning = FALSE;
+ imp->fRan = FALSE;
+ fImplementation = imp;
+}
+
+SimpleThread::~SimpleThread()
+{
+ PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
+ if (imp->fRan) {
+ pthread_join(imp->fThread, NULL);
+ }
+ delete imp;
+ fImplementation = (void *)0xdeadbeef;
+}
+
+int32_t SimpleThread::start()
+{
+ int32_t rc;
+ static pthread_attr_t attr;
+ static UBool attrIsInitialized = FALSE;
+
+ PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
+ imp->fRunning = TRUE;
+ imp->fRan = TRUE;
+
+#ifdef HPUX_CMA
+ if (attrIsInitialized == FALSE) {
+ rc = pthread_attr_create(&attr);
+ attrIsInitialized = TRUE;
+ }
+ rc = pthread_create(&(imp->fThread),attr,&SimpleThreadProc,(void*)this);
+#else
+ if (attrIsInitialized == FALSE) {
+ rc = pthread_attr_init(&attr);
+#if defined(OS390)
+ {
+ int detachstate = 0; /* jdc30: detach state of zero causes
+ threads created with this attr to be in
+ an undetached state. An undetached
+ thread will keep its resources after
+ termination. */
+ pthread_attr_setdetachstate(&attr, &detachstate);
+ }
+#else
+ // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+#endif
+ attrIsInitialized = TRUE;
+ }
+ rc = pthread_create(&(imp->fThread),&attr,&SimpleThreadProc,(void*)this);
+#endif
+
+ if (rc != 0) {
+ // some kind of error occured, the thread did not start.
+ imp->fRan = FALSE;
+ imp->fRunning = FALSE;
+ }
+
+ return rc;
+}
+
+
+UBool
+SimpleThread::isRunning() {
+ // Note: Mutex functions are used here not for synchronization,
+ // but to force memory barriors to exist, to ensure that one thread
+ // can see changes made by another when running on processors
+ // with memory models having weak coherency.
+ PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
+ umtx_lock(NULL);
+ UBool retVal = imp->fRunning;
+ umtx_unlock(NULL);
+ return retVal;
+}
+
+
+void SimpleThread::sleep(int32_t millis)
+{
+#ifdef U_SOLARIS
+ sigignore(SIGALRM);
+#endif
+
+#ifdef HPUX_CMA
+ cma_sleep(millis/100);
+#elif defined(U_HPUX) || defined(OS390)
+ millis *= 1000;
+ while(millis >= 1000000) {
+ usleep(999999);
+ millis -= 1000000;
+ }
+ if(millis > 0) {
+ usleep(millis);
+ }
+#else
+ usleep(millis * 1000);
+#endif
+}
+
+#endif
+// end POSIX
+
+
+#ifndef HAVE_IMP
+#error No implementation for threads! Cannot test.
+0 = 216; //die
+#endif
+
+
+// *************** end fluff ******************
+
+/* now begins the real test. */
+void MultithreadTest::runIndexedTest( int32_t index, UBool exec,
+ const char* &name, char* /*par*/ ) {
+ if (exec)
+ logln("TestSuite MultithreadTest: ");
+ switch (index) {
+ case 0:
+ name = "TestThreads";
+ if (exec)
+ TestThreads();
+ break;
+
+ case 1:
+ name = "TestMutex";
+ if (exec)
+ TestMutex();
+ break;
+
+ case 2:
+ name = "TestThreadedIntl";
+#if !UCONFIG_NO_FORMATTING
+ if (exec) {
+ TestThreadedIntl();
+ }
+#endif
+ break;
+
+ case 3:
+ name = "TestCollators";
+#if !UCONFIG_NO_COLLATION
+ if (exec) {
+ TestCollators();
+ }
+#endif /* #if !UCONFIG_NO_COLLATION */
+ break;
+
+ case 4:
+ name = "TestString";
+ if (exec) {
+ TestString();
+ }
+ break;
+
+ default:
+ name = "";
+ break; //needed to end loop
+ }
+}
+
+
+//-----------------------------------------------------------------------------------
+//
+// TestThreads -- see if threads really work at all.
+//
+// Set up N threads pointing at N chars. When they are started, they will
+// each sleep 1 second and then set their chars. At the end we make sure they
+// are all set.
+//
+//-----------------------------------------------------------------------------------
+#define THREADTEST_NRTHREADS 8
+
+class TestThreadsThread : public SimpleThread
+{
+public:
+ TestThreadsThread(char* whatToChange) { fWhatToChange = whatToChange; }
+ virtual void run() { SimpleThread::sleep(1000);
+ Mutex m;
+ *fWhatToChange = '*';
+ }
+private:
+ char *fWhatToChange;
+};
+
+void MultithreadTest::TestThreads()
+{
+ char threadTestChars[THREADTEST_NRTHREADS + 1];
+ SimpleThread *threads[THREADTEST_NRTHREADS];
+ int32_t numThreadsStarted = 0;
+
+ int32_t i;
+ for(i=0;i<THREADTEST_NRTHREADS;i++)
+ {
+ threadTestChars[i] = ' ';
+ threads[i] = new TestThreadsThread(&threadTestChars[i]);
+ }
+ threadTestChars[THREADTEST_NRTHREADS] = '\0';
+
+ logln("->" + UnicodeString(threadTestChars) + "<- Firing off threads.. ");
+ for(i=0;i<THREADTEST_NRTHREADS;i++)
+ {
+ if (threads[i]->start() != 0) {
+ errln("Error starting thread %d", i);
+ }
+ else {
+ numThreadsStarted++;
+ }
+ SimpleThread::sleep(100);
+ logln(" Subthread started.");
+ }
+
+ logln("Waiting for threads to be set..");
+ if (numThreadsStarted == 0) {
+ errln("No threads could be started for testing!");
+ return;
+ }
+
+ int32_t patience = 40; // seconds to wait
+
+ while(patience--)
+ {
+ int32_t count = 0;
+ umtx_lock(NULL);
+ for(i=0;i<THREADTEST_NRTHREADS;i++)
+ {
+ if(threadTestChars[i] == '*')
+ {
+ count++;
+ }
+ }
+ umtx_unlock(NULL);
+
+ if(count == THREADTEST_NRTHREADS)
+ {
+ logln("->" + UnicodeString(threadTestChars) + "<- Got all threads! cya");
+ for(i=0;i<THREADTEST_NRTHREADS;i++)
+ {
+ delete threads[i];
+ }
+ return;
+ }
+
+ logln("->" + UnicodeString(threadTestChars) + "<- Waiting..");
+ SimpleThread::sleep(500);
+ }
+
+ errln("->" + UnicodeString(threadTestChars) + "<- PATIENCE EXCEEDED!! Still missing some.");
+ for(i=0;i<THREADTEST_NRTHREADS;i++)
+ {
+ delete threads[i];
+ }
+}
+
+
+//-----------------------------------------------------------------------
+//
+// TestMutex - a simple (non-stress) test to verify that ICU mutexes
+// are actually mutexing. Does not test the use of
+// mutexes within ICU services, but rather that the
+// platform's mutex support is at least superficially there.
+//
+//----------------------------------------------------------------------
+static UMTX gTestMutexA = NULL;
+static UMTX gTestMutexB = NULL;
+
+static int gThreadsStarted = 0;
+static int gThreadsInMiddle = 0;
+static int gThreadsDone = 0;
+
+static const int TESTMUTEX_THREAD_COUNT = 4;
+
+static int safeIncr(int &var, int amt) {
+ // Thread safe (using global mutex) increment of a variable.
+ // Return the updated value.
+ // Can also be used as a safe load of a variable by incrementing it by 0.
+ Mutex m;
+ var += amt;
+ return var;
+}
+
+class TestMutexThread : public SimpleThread
+{
+public:
+ virtual void run()
+ {
+ // This is the code that each of the spawned threads runs.
+ // All of the spawned threads bunch up together at each of the two mutexes
+ // because the main holds the mutexes until they do.
+ //
+ safeIncr(gThreadsStarted, 1);
+ umtx_lock(&gTestMutexA);
+ umtx_unlock(&gTestMutexA);
+ safeIncr(gThreadsInMiddle, 1);
+ umtx_lock(&gTestMutexB);
+ umtx_unlock(&gTestMutexB);
+ safeIncr(gThreadsDone, 1);
+ }
+};
+
+void MultithreadTest::TestMutex()
+{
+ // Start up the test threads. They should all pile up waiting on
+ // gTestMutexA, which we (the main thread) hold until the test threads
+ // all get there.
+ gThreadsStarted = 0;
+ gThreadsInMiddle = 0;
+ gThreadsDone = 0;
+ umtx_lock(&gTestMutexA);
+ TestMutexThread *threads[TESTMUTEX_THREAD_COUNT];
+ int i;
+ int32_t numThreadsStarted = 0;
+ for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
+ threads[i] = new TestMutexThread;
+ if (threads[i]->start() != 0) {
+ errln("Error starting thread %d", i);
+ }
+ else {
+ numThreadsStarted++;
+ }
+ }
+ if (numThreadsStarted == 0) {
+ errln("No threads could be started for testing!");
+ return;
+ }
+
+ int patience = 0;
+ while (safeIncr(gThreadsStarted, 0) != TESTMUTEX_THREAD_COUNT) {
+ if (patience++ > 24) {
+ TSMTHREAD_FAIL("Patience Exceeded");
+ return;
+ }
+ SimpleThread::sleep(500);
+ }
+ // None of the test threads should have advanced past the first mutex.
+ TSMTHREAD_ASSERT(gThreadsInMiddle==0);
+ TSMTHREAD_ASSERT(gThreadsDone==0);
+
+ // All of the test threads have made it to the first mutex.
+ // We (the main thread) now let them advance to the second mutex,
+ // where they should all pile up again.
+ umtx_lock(&gTestMutexB);
+ umtx_unlock(&gTestMutexA);
+
+ patience = 0;
+ while (safeIncr(gThreadsInMiddle, 0) != TESTMUTEX_THREAD_COUNT) {
+ if (patience++ > 24) {
+ TSMTHREAD_FAIL("Patience Exceeded");
+ return;
+ }
+ SimpleThread::sleep(500);
+ }
+ TSMTHREAD_ASSERT(gThreadsDone==0);
+
+ // All test threads made it to the second mutex.
+ // Now let them proceed from there. They will all terminate.
+ umtx_unlock(&gTestMutexB);
+ patience = 0;
+ while (safeIncr(gThreadsDone, 0) != TESTMUTEX_THREAD_COUNT) {
+ if (patience++ > 24) {
+ TSMTHREAD_FAIL("Patience Exceeded");
+ return;
+ }
+ SimpleThread::sleep(500);
+ }
+
+ // All threads made it by both mutexes.
+ // Destroy the test mutexes.
+ umtx_destroy(&gTestMutexA);
+ umtx_destroy(&gTestMutexB);
+ gTestMutexA=NULL;
+ gTestMutexB=NULL;
+
+ for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
+ delete threads[i];
+ }
+
+}
+
+
+//-------------------------------------------------------------------------------------------
+//
+// class ThreadWithStatus - a thread that we can check the status and error condition of
+//
+//-------------------------------------------------------------------------------------------
+class ThreadWithStatus : public SimpleThread
+{
+public:
+ UBool getError() { return (fErrors > 0); }
+ UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
+ virtual ~ThreadWithStatus(){}
+protected:
+ ThreadWithStatus() : fErrors(0) {}
+ void error(const UnicodeString &error) {
+ fErrors++; fErrorString = error;
+ SimpleThread::errorFunc();
+ }
+ void error() { error("An error occured."); }
+private:
+ int32_t fErrors;
+ UnicodeString fErrorString;
+};
+
+
+
+//-------------------------------------------------------------------------------------------
+//
+// TestMultithreadedIntl. Test ICU Formatting n a multi-threaded environment
+//
+//-------------------------------------------------------------------------------------------
+
+
+// * Show exactly where the string's differences lie.
+UnicodeString showDifference(const UnicodeString& expected, const UnicodeString& result)
+{
+ UnicodeString res;
+ res = expected + "<Expected\n";
+ if(expected.length() != result.length())
+ res += " [ Different lengths ] \n";
+ else
+ {
+ for(int32_t i=0;i<expected.length();i++)
+ {
+ if(expected[i] == result[i])
+ {
+ res += " ";
+ }
+ else
+ {
+ res += "|";
+ }
+ }
+ res += "<Differences";
+ res += "\n";
+ }
+ res += result + "<Result\n";
+
+ return res;
+}
+
+
+
+
+//-------------------------------------------------------------------------------------------
+//
+// FormatThreadTest - a thread that tests performing a number of numberformats.
+//
+//-------------------------------------------------------------------------------------------
+
+const int kFormatThreadIterations = 20; // # of iterations per thread
+const int kFormatThreadThreads = 10; // # of threads to spawn
+const int kFormatThreadPatience = 60; // time in seconds to wait for all threads
+
+#if !UCONFIG_NO_FORMATTING
+
+
+
+struct FormatThreadTestData
+{
+ double number;
+ UnicodeString string;
+ FormatThreadTestData(double a, const UnicodeString& b) : number(a),string(b) {}
+} ;
+
+
+// "Someone from {2} is receiving a #{0} error - {1}. Their telephone call is costing {3 number,currency}."
+
+void formatErrorMessage(UErrorCode &realStatus, const UnicodeString& pattern, const Locale& theLocale,
+ UErrorCode inStatus0, /* statusString 1 */ const Locale &inCountry2, double currency3, // these numbers are the message arguments.
+ UnicodeString &result)
+{
+ if(U_FAILURE(realStatus))
+ return; // you messed up
+
+ UnicodeString errString1(u_errorName(inStatus0));
+
+ UnicodeString countryName2;
+ inCountry2.getDisplayCountry(theLocale,countryName2);
+
+ Formattable myArgs[] = {
+ Formattable((int32_t)inStatus0), // inStatus0 {0}
+ Formattable(errString1), // statusString1 {1}
+ Formattable(countryName2), // inCountry2 {2}
+ Formattable(currency3)// currency3 {3,number,currency}
+ };
+
+ MessageFormat *fmt = new MessageFormat("MessageFormat's API is broken!!!!!!!!!!!",realStatus);
+ fmt->setLocale(theLocale);
+ fmt->applyPattern(pattern, realStatus);
+
+ if (U_FAILURE(realStatus)) {
+ delete fmt;
+ return;
+ }
+
+ FieldPosition ignore = 0;
+ fmt->format(myArgs,4,result,ignore,realStatus);
+
+ delete fmt;
+}
+
+
+UBool U_CALLCONV isAcceptable(void *, const char *, const char *, const UDataInfo *) {
+ return TRUE;
+}
+
+//static UMTX debugMutex = NULL;
+//static UMTX gDebugMutex;
+
+
+class FormatThreadTest : public ThreadWithStatus
+{
+public:
+ int fNum;
+ int fTraceInfo;
+
+ FormatThreadTest() // constructor is NOT multithread safe.
+ : ThreadWithStatus(),
+ fNum(0),
+ fTraceInfo(0),
+ fOffset(0)
+ // the locale to use
+ {
+ static int32_t fgOffset = 0;
+ fgOffset += 3;
+ fOffset = fgOffset;
+ }
+
+
+ virtual void run()
+ {
+ fTraceInfo = 1;
+ NumberFormat *formatter = NULL;
+ NumberFormat *percentFormatter = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+
+#if 0
+ // debugging code,
+ for (int i=0; i<4000; i++) {
+ status = U_ZERO_ERROR;
+ UDataMemory *data1 = udata_openChoice(0, "res", "en_US", isAcceptable, 0, &status);
+ UDataMemory *data2 = udata_openChoice(0, "res", "fr", isAcceptable, 0, &status);
+ udata_close(data1);
+ udata_close(data2);
+ if (U_FAILURE(status)) {
+ error("udata_openChoice failed.\n");
+ break;
+ }
+ }
+ return;
+#endif
+
+#if 0
+ // debugging code,
+ int m;
+ for (m=0; m<4000; m++) {
+ status = U_ZERO_ERROR;
+ UResourceBundle *res = NULL;
+ const char *localeName = NULL;
+
+ Locale loc = Locale::getEnglish();
+
+ localeName = loc.getName();
+ // localeName = "en";
+
+ // ResourceBundle bund = ResourceBundle(0, loc, status);
+ //umtx_lock(&gDebugMutex);
+ res = ures_open(NULL, localeName, &status);
+ //umtx_unlock(&gDebugMutex);
+
+ //umtx_lock(&gDebugMutex);
+ ures_close(res);
+ //umtx_unlock(&gDebugMutex);
+
+ if (U_FAILURE(status)) {
+ error("Resource bundle construction failed.\n");
+ break;
+ }
+ }
+ return;
+#endif
+
+ // Keep this data here to avoid static initialization.
+ FormatThreadTestData kNumberFormatTestData[] =
+ {
+ FormatThreadTestData((double)5.0, UnicodeString("5", "")),
+ FormatThreadTestData( 6.0, UnicodeString("6", "")),
+ FormatThreadTestData( 20.0, UnicodeString("20", "")),
+ FormatThreadTestData( 8.0, UnicodeString("8", "")),
+ FormatThreadTestData( 8.3, UnicodeString("8.3", "")),
+ FormatThreadTestData( 12345, UnicodeString("12,345", "")),
+ FormatThreadTestData( 81890.23, UnicodeString("81,890.23", "")),
+ };
+ int32_t kNumberFormatTestDataLength = (int32_t)(sizeof(kNumberFormatTestData) /
+ sizeof(kNumberFormatTestData[0]));
+
+ // Keep this data here to avoid static initialization.
+ FormatThreadTestData kPercentFormatTestData[] =
+ {
+ FormatThreadTestData((double)5.0, CharsToUnicodeString("500\\u00a0%")),
+ FormatThreadTestData( 1.0, CharsToUnicodeString("100\\u00a0%")),
+ FormatThreadTestData( 0.26, CharsToUnicodeString("26\\u00a0%")),
+ FormatThreadTestData(
+ 16384.99, CharsToUnicodeString("1\\u00a0638\\u00a0499\\u00a0%")), // U+00a0 = NBSP
+ FormatThreadTestData(
+ 81890.23, CharsToUnicodeString("8\\u00a0189\\u00a0023\\u00a0%")),
+ };
+ int32_t kPercentFormatTestDataLength =
+ (int32_t)(sizeof(kPercentFormatTestData) / sizeof(kPercentFormatTestData[0]));
+ int32_t iteration;
+
+ status = U_ZERO_ERROR;
+ formatter = NumberFormat::createInstance(Locale::getEnglish(),status);
+ if(U_FAILURE(status)) {
+ error("Error on NumberFormat::createInstance()");
+ goto cleanupAndReturn;
+ }
+
+ percentFormatter = NumberFormat::createPercentInstance(Locale::getFrench(),status);
+ if(U_FAILURE(status)) {
+ error("Error on NumberFormat::createPercentInstance()");
+ goto cleanupAndReturn;
+ }
+
+ for(iteration = 0;!getError() && iteration<kFormatThreadIterations;iteration++)
+ {
+
+ int32_t whichLine = (iteration + fOffset)%kNumberFormatTestDataLength;
+
+ UnicodeString output;
+
+ formatter->format(kNumberFormatTestData[whichLine].number, output);
+
+ if(0 != output.compare(kNumberFormatTestData[whichLine].string)) {
+ error("format().. expected " + kNumberFormatTestData[whichLine].string
+ + " got " + output);
+ goto cleanupAndReturn;
+ }
+
+ // Now check percent.
+ output.remove();
+ whichLine = (iteration + fOffset)%kPercentFormatTestDataLength;
+
+ percentFormatter->format(kPercentFormatTestData[whichLine].number, output);
+ if(0 != output.compare(kPercentFormatTestData[whichLine].string))
+ {
+ error("percent format().. \n" +
+ showDifference(kPercentFormatTestData[whichLine].string,output));
+ goto cleanupAndReturn;
+ }
+
+ // Test message error
+ const int kNumberOfMessageTests = 3;
+ UErrorCode statusToCheck;
+ UnicodeString patternToCheck;
+ Locale messageLocale;
+ Locale countryToCheck;
+ double currencyToCheck;
+
+ UnicodeString expected;
+
+ // load the cases.
+ switch((iteration+fOffset) % kNumberOfMessageTests)
+ {
+ default:
+ case 0:
+ statusToCheck= U_FILE_ACCESS_ERROR;
+ patternToCheck= "0:Someone from {2} is receiving a #{0}"
+ " error - {1}. Their telephone call is costing "
+ "{3,number,currency}."; // number,currency
+ messageLocale= Locale("en","US");
+ countryToCheck= Locale("","HR");
+ currencyToCheck= 8192.77;
+ expected= "0:Someone from Croatia is receiving a #4 error - "
+ "U_FILE_ACCESS_ERROR. Their telephone call is costing $8,192.77.";
+ break;
+ case 1:
+ statusToCheck= U_INDEX_OUTOFBOUNDS_ERROR;
+ patternToCheck= "1:A customer in {2} is receiving a #{0} error - {1}. Their telephone call is costing {3,number,currency}."; // number,currency
+ messageLocale= Locale("de","DE@currency=DEM");
+ countryToCheck= Locale("","BF");
+ currencyToCheck= 2.32;
+ expected= "1:A customer in Burkina Faso is receiving a #8 error - U_INDEX_OUTOFBOUNDS_ERROR. Their telephone call is costing 2,32 DM.";
+ break;
+ case 2:
+ statusToCheck= U_MEMORY_ALLOCATION_ERROR;
+ patternToCheck= "2:user in {2} is receiving a #{0} error - {1}. "
+ "They insist they just spent {3,number,currency} "
+ "on memory."; // number,currency
+ messageLocale= Locale("de","AT@currency=ATS"); // Austrian German
+ countryToCheck= Locale("","US"); // hmm
+ currencyToCheck= 40193.12;
+ expected= CharsToUnicodeString(
+ "2:user in Vereinigte Staaten is receiving a #7 error"
+ " - U_MEMORY_ALLOCATION_ERROR. They insist they just spent"
+ " \\u00f6S 40.193,12 on memory.");
+ break;
+ }
+
+ UnicodeString result;
+ UErrorCode status = U_ZERO_ERROR;
+ formatErrorMessage(status,patternToCheck,messageLocale,statusToCheck,
+ countryToCheck,currencyToCheck,result);
+ if(U_FAILURE(status))
+ {
+ UnicodeString tmp(u_errorName(status));
+ error("Failure on message format, pattern=" + patternToCheck +
+ ", error = " + tmp);
+ goto cleanupAndReturn;
+ }
+
+ if(result != expected)
+ {
+ error("PatternFormat: \n" + showDifference(expected,result));
+ goto cleanupAndReturn;
+ }
+ } /* end of for loop */
+
+cleanupAndReturn:
+ delete formatter;
+ delete percentFormatter;
+
+ // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
+ fTraceInfo = 2;
+ }
+
+private:
+ int32_t fOffset; // where we are testing from.
+};
+
+// ** The actual test function.
+
+void MultithreadTest::TestThreadedIntl()
+{
+ int i;
+ UnicodeString theErr;
+ UBool haveDisplayedInfo[kFormatThreadThreads];
+ static const int32_t PATIENCE_SECONDS = 45;
+
+ //
+ // Create and start the test threads
+ //
+ logln("Spawning: %d threads * %d iterations each.",
+ kFormatThreadThreads, kFormatThreadIterations);
+ FormatThreadTest *tests = new FormatThreadTest[kFormatThreadThreads];
+ for(int32_t j = 0; j < kFormatThreadThreads; j++) {
+ tests[j].fNum = j;
+ int32_t threadStatus = tests[j].start();
+ if (threadStatus != 0) {
+ errln("System Error %d starting thread number %d.", threadStatus, j);
+ SimpleThread::errorFunc();
+ goto cleanupAndReturn;
+ }
+ haveDisplayedInfo[j] = FALSE;
+ }
+
+
+ // Spin, waiting for the test threads to finish.
+ UBool stillRunning;
+ UDate startTime, endTime;
+ startTime = Calendar::getNow();
+ do {
+ /* Spin until the test threads complete. */
+ stillRunning = FALSE;
+ endTime = Calendar::getNow();
+ if (((int32_t)(endTime - startTime)/U_MILLIS_PER_SECOND) > PATIENCE_SECONDS) {
+ errln("Patience exceeded. Test is taking too long.");
+ return;
+ }
+ /*
+ The following sleep must be here because the *BSD operating systems
+ have a brain dead thread scheduler. They starve the child threads from
+ CPU time.
+ */
+ SimpleThread::sleep(1); // yield
+ for(i=0;i<kFormatThreadThreads;i++) {
+ if (tests[i].isRunning()) {
+ stillRunning = TRUE;
+ } else if (haveDisplayedInfo[i] == FALSE) {
+ logln("Thread # %d is complete..", i);
+ if(tests[i].getError(theErr)) {
+ errln(UnicodeString("#") + i + ": " + theErr);
+ SimpleThread::errorFunc();
+ }
+ haveDisplayedInfo[i] = TRUE;
+ }
+ }
+ } while (stillRunning);
+
+ //
+ // All threads have finished.
+ //
+cleanupAndReturn:
+ delete [] tests;
+}
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+
+
+
+
+//-------------------------------------------------------------------------------------------
+//
+// Collation threading test
+//
+//-------------------------------------------------------------------------------------------
+#if !UCONFIG_NO_COLLATION
+
+#define kCollatorThreadThreads 10 // # of threads to spawn
+#define kCollatorThreadPatience kCollatorThreadThreads*30
+
+struct Line {
+ UChar buff[25];
+ int32_t buflen;
+} ;
+
+class CollatorThreadTest : public ThreadWithStatus
+{
+private:
+ const UCollator *coll;
+ const Line *lines;
+ int32_t noLines;
+public:
+ CollatorThreadTest() : ThreadWithStatus(),
+ coll(NULL),
+ lines(NULL),
+ noLines(0)
+ {
+ };
+ void setCollator(UCollator *c, Line *l, int32_t nl)
+ {
+ coll = c;
+ lines = l;
+ noLines = nl;
+ }
+ virtual void run() {
+ //sleep(10000);
+ int32_t line = 0;
+
+ uint8_t sk1[1024], sk2[1024];
+ uint8_t *oldSk = NULL, *newSk = sk1;
+ int32_t resLen = 0, oldLen = 0;
+ int32_t i = 0;
+
+ for(i = 0; i < noLines; i++) {
+ resLen = ucol_getSortKey(coll, lines[i].buff, lines[i].buflen, newSk, 1024);
+
+ int32_t res = 0, cmpres = 0, cmpres2 = 0;
+
+ if(oldSk != NULL) {
+ res = strcmp((char *)oldSk, (char *)newSk);
+ cmpres = ucol_strcoll(coll, lines[i-1].buff, lines[i-1].buflen, lines[i].buff, lines[i].buflen);
+ cmpres2 = ucol_strcoll(coll, lines[i].buff, lines[i].buflen, lines[i-1].buff, lines[i-1].buflen);
+ //cmpres = res;
+ //cmpres2 = -cmpres;
+
+ if(cmpres != -cmpres2) {
+ error("Compare result not symmetrical on line "+ line);
+ break;
+ }
+
+ if(((res&0x80000000) != (cmpres&0x80000000)) || (res == 0 && cmpres != 0) || (res != 0 && cmpres == 0)) {
+ error(UnicodeString("Difference between ucol_strcoll and sortkey compare on line ")+ UnicodeString(line));
+ break;
+ }
+
+ if(res > 0) {
+ error(UnicodeString("Line %i is not greater or equal than previous line ")+ UnicodeString(i));
+ break;
+ } else if(res == 0) { /* equal */
+ res = u_strcmpCodePointOrder(lines[i-1].buff, lines[i].buff);
+ if (res == 0) {
+ error(UnicodeString("Probable error in test file on line %i (comparing identical strings)")+ UnicodeString(i));
+ break;
+ } else if (res > 0) {
+ error(UnicodeString("Sortkeys are identical, but code point comapare gives >0 on line ")+ UnicodeString(i));
+ break;
+ }
+ }
+ }
+
+ oldSk = newSk;
+ oldLen = resLen;
+
+ newSk = (newSk == sk1)?sk2:sk1;
+ }
+ }
+
+};
+
+void MultithreadTest::TestCollators()
+{
+
+ UErrorCode status = U_ZERO_ERROR;
+ FILE *testFile = NULL;
+ char testDataPath[1024];
+ strcpy(testDataPath, IntlTest::getSourceTestData(status));
+ if (U_FAILURE(status)) {
+ errln("ERROR: could not open test data %s", u_errorName(status));
+ return;
+ }
+ strcat(testDataPath, "CollationTest_");
+
+ const char* type = "NON_IGNORABLE";
+
+ const char *ext = ".txt";
+ if(testFile) {
+ fclose(testFile);
+ }
+ char buffer[1024];
+ strcpy(buffer, testDataPath);
+ strcat(buffer, type);
+ size_t bufLen = strlen(buffer);
+
+ // we try to open 3 files:
+ // path/CollationTest_type.txt
+ // path/CollationTest_type_SHORT.txt
+ // path/CollationTest_type_STUB.txt
+ // we are going to test with the first one that we manage to open.
+
+ strcpy(buffer+bufLen, ext);
+
+ testFile = fopen(buffer, "rb");
+
+ if(testFile == 0) {
+ strcpy(buffer+bufLen, "_SHORT");
+ strcat(buffer, ext);
+ testFile = fopen(buffer, "rb");
+
+ if(testFile == 0) {
+ strcpy(buffer+bufLen, "_STUB");
+ strcat(buffer, ext);
+ testFile = fopen(buffer, "rb");
+
+ if (testFile == 0) {
+ *(buffer+bufLen) = 0;
+ errln("ERROR: could not open any of the conformance test files, tried opening base %s", buffer);
+ return;
+ } else {
+ infoln(
+ "INFO: Working with the stub file.\n"
+ "If you need the full conformance test, please\n"
+ "download the appropriate data files from:\n"
+ "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
+ }
+ }
+ }
+
+ Line *lines = new Line[200000];
+ memset(lines, 0, sizeof(Line)*200000);
+ int32_t lineNum = 0;
+
+ UChar bufferU[1024];
+ int32_t buflen = 0;
+ uint32_t first = 0;
+ uint32_t offset = 0;
+
+ while (fgets(buffer, 1024, testFile) != NULL) {
+ offset = 0;
+ if(*buffer == 0 || strlen(buffer) < 3 || buffer[0] == '#') {
+ continue;
+ }
+ offset = u_parseString(buffer, bufferU, 1024, &first, &status);
+ buflen = offset;
+ bufferU[offset++] = 0;
+ lines[lineNum].buflen = buflen;
+ //lines[lineNum].buff = new UChar[buflen+1];
+ u_memcpy(lines[lineNum].buff, bufferU, buflen);
+ lineNum++;
+ }
+ fclose(testFile);
+ if(U_FAILURE(status)) {
+ errln("Couldn't read the test file!");
+ return;
+ }
+
+ UCollator *coll = ucol_open("root", &status);
+ if(U_FAILURE(status)) {
+ errln("Couldn't open UCA collator");
+ return;
+ }
+ ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
+ ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_OFF, &status);
+ ucol_setAttribute(coll, UCOL_CASE_LEVEL, UCOL_OFF, &status);
+ ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_TERTIARY, &status);
+ ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, &status);
+
+ int32_t noSpawned = 0;
+ int32_t spawnResult = 0;
+ CollatorThreadTest *tests;
+ tests = new CollatorThreadTest[kCollatorThreadThreads];
+
+ logln(UnicodeString("Spawning: ") + kCollatorThreadThreads + " threads * " + kFormatThreadIterations + " iterations each.");
+ int32_t j = 0;
+ for(j = 0; j < kCollatorThreadThreads; j++) {
+ //logln("Setting collator %i", j);
+ tests[j].setCollator(coll, lines, lineNum);
+ }
+ for(j = 0; j < kCollatorThreadThreads; j++) {
+ log("%i ", j);
+ spawnResult = tests[j].start();
+ if(spawnResult != 0) {
+ infoln("THREAD INFO: Couldn't spawn more than %i threads", noSpawned);
+ break;
+ }
+ noSpawned++;
+ }
+ logln("Spawned all");
+ if (noSpawned == 0) {
+ errln("No threads could be spawned.");
+ return;
+ }
+
+ for(int32_t patience = kCollatorThreadPatience;patience > 0; patience --)
+ {
+ logln("Waiting...");
+
+ int32_t i;
+ int32_t terrs = 0;
+ int32_t completed =0;
+
+ for(i=0;i<kCollatorThreadThreads;i++)
+ {
+ if (tests[i].isRunning() == FALSE)
+ {
+ completed++;
+
+ //logln(UnicodeString("Test #") + i + " is complete.. ");
+
+ UnicodeString theErr;
+ if(tests[i].getError(theErr))
+ {
+ terrs++;
+ errln(UnicodeString("#") + i + ": " + theErr);
+ }
+ // print out the error, too, if any.
+ }
+ }
+ logln("Completed %i tests", completed);
+
+ if(completed == noSpawned)
+ {
+ logln("Done! All %i tests are finished", noSpawned);
+
+ if(terrs)
+ {
+ errln("There were errors.");
+ SimpleThread::errorFunc();
+ }
+ ucol_close(coll);
+ delete[] tests;
+ //for(i = 0; i < lineNum; i++) {
+ //delete[] lines[i].buff;
+ //}
+ delete[] lines;
+
+ return;
+ }
+
+ SimpleThread::sleep(900);
+ }
+ errln("patience exceeded. ");
+ SimpleThread::errorFunc();
+ ucol_close(coll);
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+
+
+
+//-------------------------------------------------------------------------------------------
+//
+// StringThreadTest2
+//
+//-------------------------------------------------------------------------------------------
+
+const int kStringThreadIterations = 2500;// # of iterations per thread
+const int kStringThreadThreads = 10; // # of threads to spawn
+const int kStringThreadPatience = 120; // time in seconds to wait for all threads
+
+
+class StringThreadTest2 : public ThreadWithStatus
+{
+public:
+ int fNum;
+ int fTraceInfo;
+ const UnicodeString *fSharedString;
+
+ StringThreadTest2(const UnicodeString *sharedString, int num) // constructor is NOT multithread safe.
+ : ThreadWithStatus(),
+ fNum(num),
+ fTraceInfo(0),
+ fSharedString(sharedString)
+ {
+ };
+
+
+ virtual void run()
+ {
+ fTraceInfo = 1;
+ int loopCount = 0;
+
+ for (loopCount = 0; loopCount < kStringThreadIterations; loopCount++) {
+ if (*fSharedString != "This is the original test string.") {
+ error("Original string is corrupt.");
+ break;
+ }
+ UnicodeString s1 = *fSharedString;
+ s1 += "cat this";
+ UnicodeString s2(s1);
+ UnicodeString s3 = *fSharedString;
+ s2 = s3;
+ s3.truncate(12);
+ s2.truncate(0);
+ }
+
+ // while (fNum == 4) {SimpleThread::sleep(10000);} // Force a failure by preventing thread from finishing
+ fTraceInfo = 2;
+ }
+
+};
+
+// ** The actual test function.
+
+void MultithreadTest::TestString()
+{
+ int patience;
+ int terrs = 0;
+ int j;
+
+ UnicodeString *testString = new UnicodeString("This is the original test string.");
+
+ StringThreadTest2 *tests[kStringThreadThreads];
+ for(j = 0; j < kStringThreadThreads; j++) {
+ tests[j] = new StringThreadTest2(testString, j);
+ }
+
+ logln(UnicodeString("Spawning: ") + kStringThreadThreads + " threads * " + kStringThreadIterations + " iterations each.");
+ for(j = 0; j < kStringThreadThreads; j++) {
+ int32_t threadStatus = tests[j]->start();
+ if (threadStatus != 0) {
+ errln("System Error %d starting thread number %d.", threadStatus, j);
+ SimpleThread::errorFunc();
+ goto cleanupAndReturn;
+ }
+ }
+
+ for(patience = kStringThreadPatience;patience > 0; patience --)
+ {
+ logln("Waiting...");
+
+ int32_t i;
+ terrs = 0;
+ int32_t completed =0;
+
+ for(i=0;i<kStringThreadThreads;i++) {
+ if (tests[i]->isRunning() == FALSE)
+ {
+ completed++;
+
+ logln(UnicodeString("Test #") + i + " is complete.. ");
+
+ UnicodeString theErr;
+ if(tests[i]->getError(theErr))
+ {
+ terrs++;
+ errln(UnicodeString("#") + i + ": " + theErr);
+ }
+ // print out the error, too, if any.
+ }
+ }
+
+ if(completed == kStringThreadThreads)
+ {
+ logln("Done!");
+ if(terrs) {
+ errln("There were errors.");
+ }
+ break;
+ }
+
+ SimpleThread::sleep(900);
+ }
+
+ if (patience <= 0) {
+ errln("patience exceeded. ");
+ // while (TRUE) {SimpleThread::sleep(10000);} // TODO: for debugging. Sleep forever on failure.
+ terrs++;
+ }
+
+ if (terrs > 0) {
+ SimpleThread::errorFunc();
+ }
+
+cleanupAndReturn:
+ if (terrs == 0) {
+ /*
+ Don't clean up if there are errors. This prevents crashes if the
+ threads are still running and using this data. This will only happen
+ if there is an error with the test, ICU, or the machine is too slow.
+ It's better to leak than crash.
+ */
+ for(j = 0; j < kStringThreadThreads; j++) {
+ delete tests[j];
+ }
+ delete testString;
+ }
+}
+
+
+
+
+
+#endif // ICU_USE_THREADS
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsmthred.h b/Build/source/libs/icu/icu-xetex/test/intltest/tsmthred.h
new file mode 100644
index 00000000000..f2f990608f9
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsmthred.h
@@ -0,0 +1,46 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2004, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#ifndef MULTITHREADTEST_H
+#define MULTITHREADTEST_H
+
+#include "intltest.h"
+#include "mutex.h"
+
+
+
+/**
+ * Tests actual threading
+ **/
+class MultithreadTest : public IntlTest
+{
+public:
+ MultithreadTest();
+ virtual ~MultithreadTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ /**
+ * test that threads even work
+ **/
+ void TestThreads(void);
+ /**
+ * test that mutexes work
+ **/
+ void TestMutex(void);
+#if !UCONFIG_NO_FORMATTING
+ /**
+ * test that intl functions work in a multithreaded context
+ **/
+ void TestThreadedIntl(void);
+#endif
+ void TestCollators(void);
+ void TestString();
+};
+
+#endif
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsnmfmt.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tsnmfmt.cpp
new file mode 100644
index 00000000000..57d49ecce4c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsnmfmt.cpp
@@ -0,0 +1,441 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2004, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/decimfmt.h"
+#include "tsnmfmt.h"
+#include "putilimp.h"
+#include <float.h>
+#include <stdlib.h>
+
+IntlTestNumberFormat::~IntlTestNumberFormat() {}
+
+static const char * formattableTypeName(Formattable::Type t)
+{
+ switch(t) {
+ case Formattable::kDate: return "kDate";
+ case Formattable::kDouble: return "kDouble";
+ case Formattable::kLong: return "kLong";
+ case Formattable::kString: return "kString";
+ case Formattable::kArray: return "kArray";
+ case Formattable::kInt64: return "kInt64";
+ default: return "??unknown??";
+ }
+}
+
+/**
+ * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
+ * NumberFormat.
+ */
+void IntlTestNumberFormat::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+
+ if (exec) logln((UnicodeString)"TestSuite NumberFormat");
+ switch (index) {
+ case 0: name = "createInstance";
+ if (exec)
+ {
+ logln(name);
+ fStatus = U_ZERO_ERROR;
+ fFormat = NumberFormat::createInstance(fStatus);
+ testFormat(/*par*/);
+ }
+ break;
+
+ case 1: name = "DefaultLocale";
+ if (exec) testLocale(/*par, */Locale::getDefault(), name);
+ break;
+
+ case 2: name = "testAvailableLocales";
+ if (exec) {
+ logln(name);
+ testAvailableLocales(/*par*/);
+ }
+ break;
+
+ case 3: name = "monsterTest";
+ if (exec) {
+ logln(name);
+ monsterTest(/*par*/);
+ }
+ break;
+
+ default: name = ""; break;
+ }
+}
+
+void
+IntlTestNumberFormat::testLocale(/* char* par, */const Locale& locale, const UnicodeString& localeName)
+{
+ const char* name;
+
+ fLocale = locale;
+ name = "Number test";
+ logln((UnicodeString)name + " (" + localeName + ")");
+ fStatus = U_ZERO_ERROR;
+ fFormat = NumberFormat::createInstance(locale, fStatus);
+ testFormat(/* par */);
+
+ name = "Currency test";
+ logln((UnicodeString)name + " (" + localeName + ")");
+ fStatus = U_ZERO_ERROR;
+ fFormat = NumberFormat::createCurrencyInstance(locale, fStatus);
+ testFormat(/* par */);
+
+ name = "Percent test";
+ logln((UnicodeString)name + " (" + localeName + ")");
+ fStatus = U_ZERO_ERROR;
+ fFormat = NumberFormat::createPercentInstance(locale, fStatus);
+ testFormat(/* par */);
+}
+
+double IntlTestNumberFormat::randDouble()
+{
+ // Assume 8-bit (or larger) rand values. Also assume
+ // that the system rand() function is very poor, which it always is.
+ // Call srand(currentTime) in intltest to make it truly random.
+ double d;
+ uint32_t i;
+ char* poke = (char*)&d;
+ do {
+ for (i=0; i < sizeof(double); ++i)
+ {
+ poke[i] = (char)(rand() & 0xFF);
+ }
+ } while (uprv_isNaN(d) || uprv_isInfinite(d)
+ || !((-DBL_MAX < d && d < DBL_MAX) || (d < -DBL_MIN && DBL_MIN < d)));
+
+ return d;
+}
+
+/*
+ * Return a random uint32_t
+ **/
+uint32_t IntlTestNumberFormat::randLong()
+{
+ // Assume 8-bit (or larger) rand values. Also assume
+ // that the system rand() function is very poor, which it always is.
+ // Call srand(currentTime) in intltest to make it truly random.
+ uint32_t d;
+ uint32_t i;
+ char* poke = (char*)&d;
+ for (i=0; i < sizeof(uint32_t); ++i)
+ {
+ poke[i] = (char)(rand() & 0xFF);
+ }
+ return d;
+}
+
+
+/* Make sure that we don't get something too large and multiply into infinity.
+ @param smallerThanMax the requested maximum value smaller than DBL_MAX */
+double IntlTestNumberFormat::getSafeDouble(double smallerThanMax) {
+ double it;
+ double high = (DBL_MAX/smallerThanMax)/10.0;
+ double low = -high;
+ do {
+ it = randDouble();
+ } while (low > it || it > high);
+ return it;
+}
+
+void
+IntlTestNumberFormat::testFormat(/* char* par */)
+{
+ if (U_FAILURE(fStatus))
+ {
+ errln((UnicodeString)"**** FAIL: createXxxInstance failed.");
+ if (fFormat != 0)
+ errln("**** FAIL: Non-null format returned by createXxxInstance upon failure.");
+ delete fFormat;
+ fFormat = 0;
+ return;
+ }
+
+ if (fFormat == 0)
+ {
+ errln((UnicodeString)"**** FAIL: Null format returned by createXxxInstance.");
+ return;
+ }
+
+ UnicodeString str;
+
+ // Assume it's a DecimalFormat and get some info
+ DecimalFormat *s = (DecimalFormat*)fFormat;
+ logln((UnicodeString)" Pattern " + s->toPattern(str));
+
+#if defined(OS390) || defined(OS400)
+ tryIt(-2.02147304840132e-68);
+ tryIt(3.88057859588817e-68); // Test rounding when only some digits are shown because exponent is close to -maxfrac
+ tryIt(-2.64651110485945e+65); // Overflows to +INF when shown as a percent
+ tryIt(9.29526819488338e+64); // Ok -- used to fail?
+#else
+ tryIt(-2.02147304840132e-100);
+ tryIt(3.88057859588817e-096); // Test rounding when only some digits are shown because exponent is close to -maxfrac
+ tryIt(-2.64651110485945e+306); // Overflows to +INF when shown as a percent
+ tryIt(9.29526819488338e+250); // Ok -- used to fail?
+#endif
+
+ // These PASS now, with the sprintf/atof based format-parse.
+
+ // These fail due to round-off
+ // The least significant digit drops by one during each format-parse cycle.
+ // Both numbers DON'T have a round-off problem when multiplied by 100! (shown as %)
+#ifdef OS390
+ tryIt(-9.18228054496402e+64);
+ tryIt(-9.69413034454191e+64);
+#else
+ tryIt(-9.18228054496402e+255);
+ tryIt(-9.69413034454191e+273);
+#endif
+
+#ifndef OS390
+ tryIt(1.234e-200);
+ tryIt(-2.3e-168);
+
+ tryIt(uprv_getNaN());
+ tryIt(uprv_getInfinity());
+ tryIt(-uprv_getInfinity());
+#endif
+
+ tryIt((int32_t)251887531);
+ tryIt(5e-20 / 9);
+ tryIt(5e20 / 9);
+ tryIt(1.234e-50);
+ tryIt(9.99999999999996);
+ tryIt(9.999999999999996);
+
+ tryIt((int32_t)INT32_MIN);
+ tryIt((int32_t)INT32_MAX);
+ tryIt((double)INT32_MIN);
+ tryIt((double)INT32_MAX);
+ tryIt((double)INT32_MIN - 1.0);
+ tryIt((double)INT32_MAX + 1.0);
+
+ tryIt(5.0 / 9.0 * 1e-20);
+ tryIt(4.0 / 9.0 * 1e-20);
+ tryIt(5.0 / 9.0 * 1e+20);
+ tryIt(4.0 / 9.0 * 1e+20);
+
+ tryIt(2147483647.);
+ tryIt((int32_t)0);
+ tryIt(0.0);
+ tryIt((int32_t)1);
+ tryIt((int32_t)10);
+ tryIt((int32_t)100);
+ tryIt((int32_t)-1);
+ tryIt((int32_t)-10);
+ tryIt((int32_t)-100);
+ tryIt((int32_t)-1913860352);
+
+ for (int32_t z=0; z<10; ++z)
+ {
+ double d = randFraction() * 2e10 - 1e10;
+ tryIt(d);
+ }
+
+ double it = getSafeDouble(100000.0);
+
+ tryIt(0.0);
+ tryIt(it);
+ tryIt((int32_t)0);
+ tryIt(uprv_floor(it));
+ tryIt((int32_t)randLong());
+
+ // try again
+ it = getSafeDouble(100.0);
+ tryIt(it);
+ tryIt(uprv_floor(it));
+ tryIt((int32_t)randLong());
+
+ // try again with very large numbers
+ it = getSafeDouble(100000000000.0);
+ tryIt(it);
+
+ // try again with very large numbers
+ // and without going outside of the int32_t range
+ it = randFraction() * INT32_MAX;
+ tryIt(it);
+ tryIt((int32_t)uprv_floor(it));
+
+ delete fFormat;
+}
+
+void
+IntlTestNumberFormat::tryIt(double aNumber)
+{
+ const int32_t DEPTH = 10;
+ Formattable number[DEPTH];
+ UnicodeString string[DEPTH];
+
+ int32_t numberMatch = 0;
+ int32_t stringMatch = 0;
+ UnicodeString errMsg;
+ int32_t i;
+ for (i=0; i<DEPTH; ++i)
+ {
+ errMsg.truncate(0); // if non-empty, we failed this iteration
+ UErrorCode status = U_ZERO_ERROR;
+ string[i] = "(n/a)"; // "format was never done" value
+ if (i == 0) {
+ number[i].setDouble(aNumber);
+ } else {
+ fFormat->parse(string[i-1], number[i], status);
+ if (U_FAILURE(status)) {
+ number[i].setDouble(1234.5); // "parse failed" value
+ errMsg = "**** FAIL: Parse of " + prettify(string[i-1]) + " failed.";
+ --i; // don't show empty last line: "1234.5 F> (n/a) P>"
+ break;
+ }
+ }
+ // Convert from long to double
+ if (number[i].getType() == Formattable::kLong)
+ number[i].setDouble(number[i].getLong());
+ else if (number[i].getType() == Formattable::kInt64)
+ number[i].setDouble((double)number[i].getInt64());
+ else if (number[i].getType() != Formattable::kDouble)
+ {
+ errMsg = ("**** FAIL: Parse of " + prettify(string[i-1])
+ + " returned non-numeric Formattable, type " + UnicodeString(formattableTypeName(number[i].getType()))
+ + ", Locale=" + UnicodeString(fLocale.getName())
+ + ", longValue=" + number[i].getLong());
+ break;
+ }
+ string[i].truncate(0);
+ fFormat->format(number[i].getDouble(), string[i]);
+ if (i > 0)
+ {
+ if (numberMatch == 0 && number[i] == number[i-1])
+ numberMatch = i;
+ else if (numberMatch > 0 && number[i] != number[i-1])
+ {
+ errMsg = ("**** FAIL: Numeric mismatch after match.");
+ break;
+ }
+ if (stringMatch == 0 && string[i] == string[i-1])
+ stringMatch = i;
+ else if (stringMatch > 0 && string[i] != string[i-1])
+ {
+ errMsg = ("**** FAIL: String mismatch after match.");
+ break;
+ }
+ }
+ if (numberMatch > 0 && stringMatch > 0)
+ break;
+ }
+ if (i == DEPTH)
+ --i;
+
+ if (stringMatch > 2 || numberMatch > 2)
+ {
+ errMsg = ("**** FAIL: No string and/or number match within 2 iterations.");
+ }
+
+ if (errMsg.length() != 0)
+ {
+ for (int32_t k=0; k<=i; ++k)
+ {
+ logln((UnicodeString)"" + k + ": " + number[k].getDouble() + " F> " +
+ prettify(string[k]) + " P> ");
+ }
+ errln(errMsg);
+ }
+}
+
+void
+IntlTestNumberFormat::tryIt(int32_t aNumber)
+{
+ Formattable number(aNumber);
+ UnicodeString stringNum;
+ UErrorCode status = U_ZERO_ERROR;
+
+ fFormat->format(number, stringNum, status);
+ if (U_FAILURE(status))
+ {
+ errln("**** FAIL: Formatting " + aNumber);
+ return;
+ }
+ fFormat->parse(stringNum, number, status);
+ if (U_FAILURE(status))
+ {
+ errln("**** FAIL: Parse of " + prettify(stringNum) + " failed.");
+ return;
+ }
+ if (number.getType() != Formattable::kLong)
+ {
+ errln("**** FAIL: Parse of " + prettify(stringNum)
+ + " returned non-long Formattable, type " + UnicodeString(formattableTypeName(number.getType()))
+ + ", Locale=" + UnicodeString(fLocale.getName())
+ + ", doubleValue=" + number.getDouble()
+ + ", longValue=" + number.getLong()
+ + ", origValue=" + aNumber
+ );
+ }
+ if (number.getLong() != aNumber) {
+ errln("**** FAIL: Parse of " + prettify(stringNum) + " failed. Got:" + number.getLong()
+ + " Expected:" + aNumber);
+ }
+}
+
+void IntlTestNumberFormat::testAvailableLocales(/* char* par */)
+{
+ int32_t count = 0;
+ const Locale* locales = NumberFormat::getAvailableLocales(count);
+ logln((UnicodeString)"" + count + " available locales");
+ if (locales && count)
+ {
+ UnicodeString name;
+ UnicodeString all;
+ for (int32_t i=0; i<count; ++i)
+ {
+ if (i!=0)
+ all += ", ";
+ all += locales[i].getName();
+ }
+ logln(all);
+ }
+ else
+ errln((UnicodeString)"**** FAIL: Zero available locales or null array pointer");
+}
+
+void IntlTestNumberFormat::monsterTest(/* char* par */)
+{
+ const char *SEP = "============================================================\n";
+ int32_t count;
+ const Locale* allLocales = NumberFormat::getAvailableLocales(count);
+ Locale* locales = (Locale*)allLocales;
+ Locale quickLocales[6];
+ if (allLocales && count)
+ {
+ if (quick && count > 6) {
+ logln("quick test: testing just 6 locales!");
+ count = 6;
+ locales = quickLocales;
+ locales[0] = allLocales[0];
+ locales[1] = allLocales[1];
+ locales[2] = allLocales[2];
+ // In a quick test, make sure we test locales that use
+ // currency prefix, currency suffix, and choice currency
+ // logic. Otherwise bugs in these areas can slip through.
+ locales[3] = Locale("ar", "AE", "");
+ locales[4] = Locale("cs", "CZ", "");
+ locales[5] = Locale("en", "IN", "");
+ }
+ for (int32_t i=0; i<count; ++i)
+ {
+ UnicodeString name(locales[i].getName(), "");
+ logln(SEP);
+ testLocale(/* par, */locales[i], name);
+ }
+ }
+
+ logln(SEP);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsnmfmt.h b/Build/source/libs/icu/icu-xetex/test/intltest/tsnmfmt.h
new file mode 100644
index 00000000000..076a464467d
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsnmfmt.h
@@ -0,0 +1,89 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _INTLTESTNUMBERFORMAT
+#define _INTLTESTNUMBERFORMAT
+
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+#include "intltest.h"
+
+
+/**
+ * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of
+ * NumberFormat.
+ */
+class IntlTestNumberFormat: public IntlTest {
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+private:
+
+ /**
+ * call tryIt with many variations, called by testLocale
+ **/
+ void testFormat(/* char* par */);
+ /**
+ * perform tests using aNumber and fFormat, called in many variations
+ **/
+ void tryIt(double aNumber);
+ /**
+ * perform tests using aNumber and fFormat, called in many variations
+ **/
+ void tryIt(int32_t aNumber);
+ /**
+ * test NumberFormat::getAvailableLocales
+ **/
+ void testAvailableLocales(/* char* par */);
+ /**
+ * call testLocale for all locales
+ **/
+ void monsterTest(/* char *par */);
+ /**
+ * call testFormat for currency, percent and plain number instances
+ **/
+ void testLocale(/* char *par, */const Locale& locale, const UnicodeString& localeName);
+
+ NumberFormat* fFormat;
+ UErrorCode fStatus;
+ Locale fLocale;
+
+public:
+
+ virtual ~IntlTestNumberFormat();
+
+ /*
+ * Return a random double that isn't too large.
+ */
+ static double getSafeDouble(double smallerThanMax);
+
+ /*
+ * Return a random double
+ **/
+ static double randDouble();
+
+ /*
+ * Return a random uint32_t
+ **/
+ static uint32_t randLong();
+
+ /**
+ * Return a random double 0 <= x < 1.0
+ **/
+ static double randFraction()
+ {
+ return (double)randLong() / (double)0xFFFFFFFF;
+ }
+
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsputil.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tsputil.cpp
new file mode 100644
index 00000000000..1f4b66ee218
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsputil.cpp
@@ -0,0 +1,565 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "tsputil.h"
+
+#include <float.h> // DBL_MAX, DBL_MIN
+#include "putilimp.h"
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
+
+void
+PUtilTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ //if (exec) logln("TestSuite PUtilTest: ");
+ switch (index) {
+ CASE(0, testMaxMin)
+ CASE(1, testNaN)
+ CASE(2, testPositiveInfinity)
+ CASE(3, testNegativeInfinity)
+ CASE(4, testZero)
+ CASE(5, testU_INLINE)
+// CASE(, testIEEEremainder)
+
+ default: name = ""; break; //needed to end loop
+ }
+}
+
+#if 0
+void
+PUtilTest::testIEEEremainder()
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double nan = uprv_getNaN();
+ double pzero = 0.0;
+ double nzero = 0.0;
+
+ nzero *= -1;
+
+ // simple remainder checks
+ remainderTest(7.0, 2.5, -0.5);
+ remainderTest(7.0, -2.5, -0.5);
+#ifndef OS390
+ // ### TODO:
+ // The following tests fails on S/390 with IEEE support in release builds;
+ // debug builds work.
+ // The functioning of ChoiceFormat is not affected by this bug.
+ remainderTest(-7.0, 2.5, 0.5);
+ remainderTest(-7.0, -2.5, 0.5);
+#endif
+ remainderTest(5.0, 3.0, -1.0);
+
+ // this should work
+ //remainderTest(43.7, 2.5, 1.25);
+
+ /*
+
+ // infinity and real
+ remainderTest(pinf, 1.0, 1.25);
+ remainderTest(1.0, pinf, 1.0);
+ remainderTest(ninf, 1.0, 1.25);
+ remainderTest(1.0, ninf, 1.0);
+
+ // test infinity and nan
+ remainderTest(ninf, pinf, 1.25);
+ remainderTest(ninf, nan, 1.25);
+ remainderTest(pinf, nan, 1.25);
+
+ // test infinity and zero
+ remainderTest(pinf, pzero, 1.25);
+ remainderTest(pinf, nzero, 1.25);
+ remainderTest(ninf, pzero, 1.25);
+ remainderTest(ninf, nzero, 1.25);
+*/
+}
+
+void
+PUtilTest::remainderTest(double x, double y, double exp)
+{
+ double result = uprv_IEEEremainder(x,y);
+
+ if( uprv_isNaN(result) &&
+ ! ( uprv_isNaN(x) || uprv_isNaN(y))) {
+ errln(UnicodeString("FAIL: got NaN as result without NaN as argument"));
+ errln(UnicodeString(" IEEEremainder(") + x + ", " + y + ") is " + result + ", expected " + exp);
+ }
+ else if(result != exp)
+ errln(UnicodeString("FAIL: IEEEremainder(") + x + ", " + y + ") is " + result + ", expected " + exp);
+ else
+ logln(UnicodeString("OK: IEEEremainder(") + x + ", " + y + ") is " + result);
+
+}
+#endif
+
+void
+PUtilTest::testMaxMin()
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double nan = uprv_getNaN();
+ double pzero = 0.0;
+ double nzero = 0.0;
+
+ nzero *= -1;
+
+ // +Inf with -Inf
+ maxMinTest(pinf, ninf, pinf, TRUE);
+ maxMinTest(pinf, ninf, ninf, FALSE);
+
+ // +Inf with +0 and -0
+ maxMinTest(pinf, pzero, pinf, TRUE);
+ maxMinTest(pinf, pzero, pzero, FALSE);
+ maxMinTest(pinf, nzero, pinf, TRUE);
+ maxMinTest(pinf, nzero, nzero, FALSE);
+
+ // -Inf with +0 and -0
+ maxMinTest(ninf, pzero, pzero, TRUE);
+ maxMinTest(ninf, pzero, ninf, FALSE);
+ maxMinTest(ninf, nzero, nzero, TRUE);
+ maxMinTest(ninf, nzero, ninf, FALSE);
+
+ // NaN with +Inf and -Inf
+ maxMinTest(pinf, nan, nan, TRUE);
+ maxMinTest(pinf, nan, nan, FALSE);
+ maxMinTest(ninf, nan, nan, TRUE);
+ maxMinTest(ninf, nan, nan, FALSE);
+
+ // NaN with NaN
+ maxMinTest(nan, nan, nan, TRUE);
+ maxMinTest(nan, nan, nan, FALSE);
+
+ // NaN with +0 and -0
+ maxMinTest(nan, pzero, nan, TRUE);
+ maxMinTest(nan, pzero, nan, FALSE);
+ maxMinTest(nan, nzero, nan, TRUE);
+ maxMinTest(nan, nzero, nan, FALSE);
+
+ // +Inf with DBL_MAX and DBL_MIN
+ maxMinTest(pinf, DBL_MAX, pinf, TRUE);
+ maxMinTest(pinf, -DBL_MAX, pinf, TRUE);
+ maxMinTest(pinf, DBL_MIN, pinf, TRUE);
+ maxMinTest(pinf, -DBL_MIN, pinf, TRUE);
+ maxMinTest(pinf, DBL_MIN, DBL_MIN, FALSE);
+ maxMinTest(pinf, -DBL_MIN, -DBL_MIN, FALSE);
+ maxMinTest(pinf, DBL_MAX, DBL_MAX, FALSE);
+ maxMinTest(pinf, -DBL_MAX, -DBL_MAX, FALSE);
+
+ // -Inf with DBL_MAX and DBL_MIN
+ maxMinTest(ninf, DBL_MAX, DBL_MAX, TRUE);
+ maxMinTest(ninf, -DBL_MAX, -DBL_MAX, TRUE);
+ maxMinTest(ninf, DBL_MIN, DBL_MIN, TRUE);
+ maxMinTest(ninf, -DBL_MIN, -DBL_MIN, TRUE);
+ maxMinTest(ninf, DBL_MIN, ninf, FALSE);
+ maxMinTest(ninf, -DBL_MIN, ninf, FALSE);
+ maxMinTest(ninf, DBL_MAX, ninf, FALSE);
+ maxMinTest(ninf, -DBL_MAX, ninf, FALSE);
+
+ // +0 with DBL_MAX and DBL_MIN
+ maxMinTest(pzero, DBL_MAX, DBL_MAX, TRUE);
+ maxMinTest(pzero, -DBL_MAX, pzero, TRUE);
+ maxMinTest(pzero, DBL_MIN, DBL_MIN, TRUE);
+ maxMinTest(pzero, -DBL_MIN, pzero, TRUE);
+ maxMinTest(pzero, DBL_MIN, pzero, FALSE);
+ maxMinTest(pzero, -DBL_MIN, -DBL_MIN, FALSE);
+ maxMinTest(pzero, DBL_MAX, pzero, FALSE);
+ maxMinTest(pzero, -DBL_MAX, -DBL_MAX, FALSE);
+
+ // -0 with DBL_MAX and DBL_MIN
+ maxMinTest(nzero, DBL_MAX, DBL_MAX, TRUE);
+ maxMinTest(nzero, -DBL_MAX, nzero, TRUE);
+ maxMinTest(nzero, DBL_MIN, DBL_MIN, TRUE);
+ maxMinTest(nzero, -DBL_MIN, nzero, TRUE);
+ maxMinTest(nzero, DBL_MIN, nzero, FALSE);
+ maxMinTest(nzero, -DBL_MIN, -DBL_MIN, FALSE);
+ maxMinTest(nzero, DBL_MAX, nzero, FALSE);
+ maxMinTest(nzero, -DBL_MAX, -DBL_MAX, FALSE);
+}
+
+void
+PUtilTest::maxMinTest(double a, double b, double exp, UBool max)
+{
+ double result = 0.0;
+
+ if(max)
+ result = uprv_fmax(a, b);
+ else
+ result = uprv_fmin(a, b);
+
+ UBool nanResultOK = (uprv_isNaN(a) || uprv_isNaN(b));
+
+ if(uprv_isNaN(result) && ! nanResultOK) {
+ errln(UnicodeString("FAIL: got NaN as result without NaN as argument"));
+ if(max)
+ errln(UnicodeString(" max(") + a + ", " + b + ") is " + result + ", expected " + exp);
+ else
+ errln(UnicodeString(" min(") + a + ", " + b + ") is " + result + ", expected " + exp);
+ }
+ else if(result != exp && ! (uprv_isNaN(result) || uprv_isNaN(exp)))
+ if(max)
+ errln(UnicodeString("FAIL: max(") + a + ", " + b + ") is " + result + ", expected " + exp);
+ else
+ errln(UnicodeString("FAIL: min(") + a + ", " + b + ") is " + result + ", expected " + exp);
+ else {
+ if (verbose) {
+ if(max)
+ logln(UnicodeString("OK: max(") + a + ", " + b + ") is " + result);
+ else
+ logln(UnicodeString("OK: min(") + a + ", " + b + ") is " + result);
+ }
+ }
+}
+//==============================
+
+// NaN is weird- comparisons with NaN _always_ return false, with the
+// exception of !=, which _always_ returns true
+void
+PUtilTest::testNaN(void)
+{
+ logln("NaN tests may show that the expected NaN!=NaN etc. is not true on some");
+ logln("platforms; however, ICU does not rely on them because it defines");
+ logln("and uses uprv_isNaN(). Therefore, most failing NaN tests only report warnings.");
+
+ PUtilTest::testIsNaN();
+ PUtilTest::NaNGT();
+ PUtilTest::NaNLT();
+ PUtilTest::NaNGTE();
+ PUtilTest::NaNLTE();
+ PUtilTest::NaNE();
+ PUtilTest::NaNNE();
+
+ logln("End of NaN tests.");
+}
+
+//==============================
+
+void
+PUtilTest::testPositiveInfinity(void)
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double ten = 10.0;
+
+ if(uprv_isInfinite(pinf) != TRUE) {
+ errln("FAIL: isInfinite(+Infinity) returned FALSE, should be TRUE.");
+ }
+
+ if(uprv_isPositiveInfinity(pinf) != TRUE) {
+ errln("FAIL: isPositiveInfinity(+Infinity) returned FALSE, should be TRUE.");
+ }
+
+ if(uprv_isNegativeInfinity(pinf) != FALSE) {
+ errln("FAIL: isNegativeInfinity(+Infinity) returned TRUE, should be FALSE.");
+ }
+
+ if(pinf > DBL_MAX != TRUE) {
+ errln("FAIL: +Infinity > DBL_MAX returned FALSE, should be TRUE.");
+ }
+
+ if(pinf > DBL_MIN != TRUE) {
+ errln("FAIL: +Infinity > DBL_MIN returned FALSE, should be TRUE.");
+ }
+
+ if(pinf > ninf != TRUE) {
+ errln("FAIL: +Infinity > -Infinity returned FALSE, should be TRUE.");
+ }
+
+ if(pinf > ten != TRUE) {
+ errln("FAIL: +Infinity > 10.0 returned FALSE, should be TRUE.");
+ }
+}
+
+//==============================
+
+void
+PUtilTest::testNegativeInfinity(void)
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double ten = 10.0;
+
+ if(uprv_isInfinite(ninf) != TRUE) {
+ errln("FAIL: isInfinite(-Infinity) returned FALSE, should be TRUE.");
+ }
+
+ if(uprv_isNegativeInfinity(ninf) != TRUE) {
+ errln("FAIL: isNegativeInfinity(-Infinity) returned FALSE, should be TRUE.");
+ }
+
+ if(uprv_isPositiveInfinity(ninf) != FALSE) {
+ errln("FAIL: isPositiveInfinity(-Infinity) returned TRUE, should be FALSE.");
+ }
+
+ if(ninf < DBL_MAX != TRUE) {
+ errln("FAIL: -Infinity < DBL_MAX returned FALSE, should be TRUE.");
+ }
+
+ if(ninf < DBL_MIN != TRUE) {
+ errln("FAIL: -Infinity < DBL_MIN returned FALSE, should be TRUE.");
+ }
+
+ if(ninf < pinf != TRUE) {
+ errln("FAIL: -Infinity < +Infinity returned FALSE, should be TRUE.");
+ }
+
+ if(ninf < ten != TRUE) {
+ errln("FAIL: -Infinity < 10.0 returned FALSE, should be TRUE.");
+ }
+}
+
+//==============================
+
+// notes about zero:
+// -0.0 == 0.0 == TRUE
+// -0.0 < 0.0 == FALSE
+// generating -0.0 must be done at runtime. compiler apparently ignores sign?
+void
+PUtilTest::testZero(void)
+{
+ // volatile is used to fake out the compiler optimizer. We really want to divide by 0.
+ volatile double pzero = 0.0;
+ volatile double nzero = 0.0;
+
+ nzero *= -1;
+
+ if(pzero == nzero != TRUE) {
+ errln("FAIL: 0.0 == -0.0 returned FALSE, should be TRUE.");
+ }
+
+ if(pzero > nzero != FALSE) {
+ errln("FAIL: 0.0 > -0.0 returned TRUE, should be FALSE.");
+ }
+
+ if(pzero >= nzero != TRUE) {
+ errln("FAIL: 0.0 >= -0.0 returned FALSE, should be TRUE.");
+ }
+
+ if(pzero < nzero != FALSE) {
+ errln("FAIL: 0.0 < -0.0 returned TRUE, should be FALSE.");
+ }
+
+ if(pzero <= nzero != TRUE) {
+ errln("FAIL: 0.0 <= -0.0 returned FALSE, should be TRUE.");
+ }
+#ifndef OS400 /* OS/400 will generate divide by zero exception MCH1214 */
+ if(uprv_isInfinite(1/pzero) != TRUE) {
+ errln("FAIL: isInfinite(1/0.0) returned FALSE, should be TRUE.");
+ }
+
+ if(uprv_isInfinite(1/nzero) != TRUE) {
+ errln("FAIL: isInfinite(1/-0.0) returned FALSE, should be TRUE.");
+ }
+
+ if(uprv_isPositiveInfinity(1/pzero) != TRUE) {
+ errln("FAIL: isPositiveInfinity(1/0.0) returned FALSE, should be TRUE.");
+ }
+
+ if(uprv_isNegativeInfinity(1/nzero) != TRUE) {
+ errln("FAIL: isNegativeInfinity(1/-0.0) returned FALSE, should be TRUE.");
+ }
+#endif
+}
+
+//==============================
+
+void
+PUtilTest::testIsNaN(void)
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double nan = uprv_getNaN();
+ double ten = 10.0;
+
+ if(uprv_isNaN(nan) == FALSE) {
+ errln("FAIL: isNaN() returned FALSE for NaN.");
+ }
+
+ if(uprv_isNaN(pinf) == TRUE) {
+ errln("FAIL: isNaN() returned TRUE for +Infinity.");
+ }
+
+ if(uprv_isNaN(ninf) == TRUE) {
+ errln("FAIL: isNaN() returned TRUE for -Infinity.");
+ }
+
+ if(uprv_isNaN(ten) == TRUE) {
+ errln("FAIL: isNaN() returned TRUE for 10.0.");
+ }
+}
+
+//==============================
+
+void
+PUtilTest::NaNGT(void)
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double nan = uprv_getNaN();
+ double ten = 10.0;
+
+ if(nan > nan != FALSE) {
+ logln("WARNING: NaN > NaN returned TRUE, should be FALSE");
+ }
+
+ if(nan > pinf != FALSE) {
+ logln("WARNING: NaN > +Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan > ninf != FALSE) {
+ logln("WARNING: NaN > -Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan > ten != FALSE) {
+ logln("WARNING: NaN > 10.0 returned TRUE, should be FALSE");
+ }
+}
+
+//==============================
+
+void
+PUtilTest::NaNLT(void)
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double nan = uprv_getNaN();
+ double ten = 10.0;
+
+ if(nan < nan != FALSE) {
+ logln("WARNING: NaN < NaN returned TRUE, should be FALSE");
+ }
+
+ if(nan < pinf != FALSE) {
+ logln("WARNING: NaN < +Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan < ninf != FALSE) {
+ logln("WARNING: NaN < -Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan < ten != FALSE) {
+ logln("WARNING: NaN < 10.0 returned TRUE, should be FALSE");
+ }
+}
+
+//==============================
+
+void
+PUtilTest::NaNGTE(void)
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double nan = uprv_getNaN();
+ double ten = 10.0;
+
+ if(nan >= nan != FALSE) {
+ logln("WARNING: NaN >= NaN returned TRUE, should be FALSE");
+ }
+
+ if(nan >= pinf != FALSE) {
+ logln("WARNING: NaN >= +Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan >= ninf != FALSE) {
+ logln("WARNING: NaN >= -Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan >= ten != FALSE) {
+ logln("WARNING: NaN >= 10.0 returned TRUE, should be FALSE");
+ }
+}
+
+//==============================
+
+void
+PUtilTest::NaNLTE(void)
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double nan = uprv_getNaN();
+ double ten = 10.0;
+
+ if(nan <= nan != FALSE) {
+ logln("WARNING: NaN <= NaN returned TRUE, should be FALSE");
+ }
+
+ if(nan <= pinf != FALSE) {
+ logln("WARNING: NaN <= +Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan <= ninf != FALSE) {
+ logln("WARNING: NaN <= -Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan <= ten != FALSE) {
+ logln("WARNING: NaN <= 10.0 returned TRUE, should be FALSE");
+ }
+}
+
+//==============================
+
+void
+PUtilTest::NaNE(void)
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double nan = uprv_getNaN();
+ double ten = 10.0;
+
+ if(nan == nan != FALSE) {
+ logln("WARNING: NaN == NaN returned TRUE, should be FALSE");
+ }
+
+ if(nan == pinf != FALSE) {
+ logln("WARNING: NaN == +Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan == ninf != FALSE) {
+ logln("WARNING: NaN == -Infinity returned TRUE, should be FALSE");
+ }
+
+ if(nan == ten != FALSE) {
+ logln("WARNING: NaN == 10.0 returned TRUE, should be FALSE");
+ }
+}
+
+//==============================
+
+void
+PUtilTest::NaNNE(void)
+{
+ double pinf = uprv_getInfinity();
+ double ninf = -uprv_getInfinity();
+ double nan = uprv_getNaN();
+ double ten = 10.0;
+
+ if(nan != nan != TRUE) {
+ logln("WARNING: NaN != NaN returned FALSE, should be TRUE");
+ }
+
+ if(nan != pinf != TRUE) {
+ logln("WARNING: NaN != +Infinity returned FALSE, should be TRUE");
+ }
+
+ if(nan != ninf != TRUE) {
+ logln("WARNING: NaN != -Infinity returned FALSE, should be TRUE");
+ }
+
+ if(nan != ten != TRUE) {
+ logln("WARNING: NaN != 10.0 returned FALSE, should be TRUE");
+ }
+}
+
+U_INLINE int32_t inlineTriple(int32_t x) {
+ return 3*x;
+}
+
+// "code" coverage test for Jitterbug 4515 RFE: in C++, use U_INLINE=inline
+void
+PUtilTest::testU_INLINE() {
+ if(inlineTriple(2)!=6 || inlineTriple(-55)!=-165) {
+ errln("inlineTriple() failed");
+ }
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tsputil.h b/Build/source/libs/icu/icu-xetex/test/intltest/tsputil.h
new file mode 100644
index 00000000000..77cd52b2b31
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tsputil.h
@@ -0,0 +1,47 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#ifndef _PUTILTEST_
+#define _PUTILTEST_
+
+#include "intltest.h"
+
+/**
+ * Test putil.h
+ **/
+class PUtilTest : public IntlTest {
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+
+// void testIEEEremainder(void);
+ void testMaxMin(void);
+
+private:
+// void remainderTest(double x, double y, double exp);
+ void maxMinTest(double a, double b, double exp, UBool max);
+
+ // the actual tests; methods return the number of errors
+ void testNaN(void);
+ void testPositiveInfinity(void);
+ void testNegativeInfinity(void);
+ void testZero(void);
+ void testU_INLINE();
+
+ // subtests of testNaN
+ void testIsNaN(void);
+ void NaNGT(void);
+ void NaNLT(void);
+ void NaNGTE(void);
+ void NaNLTE(void);
+ void NaNE(void);
+ void NaNNE(void);
+
+};
+
+#endif
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tstnorm.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tstnorm.cpp
new file mode 100644
index 00000000000..cadc0252232
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tstnorm.cpp
@@ -0,0 +1,1798 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/uchar.h"
+#include "unicode/normlzr.h"
+#include "unicode/uniset.h"
+#include "unicode/usetiter.h"
+#include "unicode/schriter.h"
+#include "cstring.h"
+#include "unormimp.h"
+#include "tstnorm.h"
+
+#define LENGTHOF(array) ((int32_t)(sizeof(array)/sizeof((array)[0])))
+#define ARRAY_LENGTH(array) LENGTHOF(array)
+
+#define CASE(id,test) case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln((UnicodeString)""); \
+ test(); \
+ } \
+ break
+
+static UErrorCode status = U_ZERO_ERROR;
+
+void BasicNormalizerTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ CASE(0,TestDecomp);
+ CASE(1,TestCompatDecomp);
+ CASE(2,TestCanonCompose);
+ CASE(3,TestCompatCompose);
+ CASE(4,TestPrevious);
+ CASE(5,TestHangulDecomp);
+ CASE(6,TestHangulCompose);
+ CASE(7,TestTibetan);
+ CASE(8,TestCompositionExclusion);
+ CASE(9,TestZeroIndex);
+ CASE(10,TestVerisign);
+ CASE(11,TestPreviousNext);
+ CASE(12,TestNormalizerAPI);
+ CASE(13,TestConcatenate);
+ CASE(14,FindFoldFCDExceptions);
+ CASE(15,TestCompare);
+ CASE(16,TestSkippable);
+ default: name = ""; break;
+ }
+}
+
+/**
+ * Convert Java-style strings with \u Unicode escapes into UnicodeString objects
+ */
+static UnicodeString str(const char *input)
+{
+ UnicodeString str(input, ""); // Invariant conversion
+ return str.unescape();
+}
+
+
+BasicNormalizerTest::BasicNormalizerTest()
+{
+ // canonTest
+ // Input Decomposed Composed
+
+ canonTests[0][0] = str("cat"); canonTests[0][1] = str("cat"); canonTests[0][2] = str("cat");
+
+ canonTests[1][0] = str("\\u00e0ardvark"); canonTests[1][1] = str("a\\u0300ardvark"); canonTests[1][2] = str("\\u00e0ardvark");
+
+ canonTests[2][0] = str("\\u1e0a"); canonTests[2][1] = str("D\\u0307"); canonTests[2][2] = str("\\u1e0a"); // D-dot_above
+
+ canonTests[3][0] = str("D\\u0307"); canonTests[3][1] = str("D\\u0307"); canonTests[3][2] = str("\\u1e0a"); // D dot_above
+
+ canonTests[4][0] = str("\\u1e0c\\u0307"); canonTests[4][1] = str("D\\u0323\\u0307"); canonTests[4][2] = str("\\u1e0c\\u0307"); // D-dot_below dot_above
+
+ canonTests[5][0] = str("\\u1e0a\\u0323"); canonTests[5][1] = str("D\\u0323\\u0307"); canonTests[5][2] = str("\\u1e0c\\u0307"); // D-dot_above dot_below
+
+ canonTests[6][0] = str("D\\u0307\\u0323"); canonTests[6][1] = str("D\\u0323\\u0307"); canonTests[6][2] = str("\\u1e0c\\u0307"); // D dot_below dot_above
+
+ canonTests[7][0] = str("\\u1e10\\u0307\\u0323"); canonTests[7][1] = str("D\\u0327\\u0323\\u0307"); canonTests[7][2] = str("\\u1e10\\u0323\\u0307"); // D dot_below cedilla dot_above
+
+ canonTests[8][0] = str("D\\u0307\\u0328\\u0323"); canonTests[8][1] = str("D\\u0328\\u0323\\u0307"); canonTests[8][2] = str("\\u1e0c\\u0328\\u0307"); // D dot_above ogonek dot_below
+
+ canonTests[9][0] = str("\\u1E14"); canonTests[9][1] = str("E\\u0304\\u0300"); canonTests[9][2] = str("\\u1E14"); // E-macron-grave
+
+ canonTests[10][0] = str("\\u0112\\u0300"); canonTests[10][1] = str("E\\u0304\\u0300"); canonTests[10][2] = str("\\u1E14"); // E-macron + grave
+
+ canonTests[11][0] = str("\\u00c8\\u0304"); canonTests[11][1] = str("E\\u0300\\u0304"); canonTests[11][2] = str("\\u00c8\\u0304"); // E-grave + macron
+
+ canonTests[12][0] = str("\\u212b"); canonTests[12][1] = str("A\\u030a"); canonTests[12][2] = str("\\u00c5"); // angstrom_sign
+
+ canonTests[13][0] = str("\\u00c5"); canonTests[13][1] = str("A\\u030a"); canonTests[13][2] = str("\\u00c5"); // A-ring
+
+ canonTests[14][0] = str("\\u00C4ffin"); canonTests[14][1] = str("A\\u0308ffin"); canonTests[14][2] = str("\\u00C4ffin");
+
+ canonTests[15][0] = str("\\u00C4\\uFB03n"); canonTests[15][1] = str("A\\u0308\\uFB03n"); canonTests[15][2] = str("\\u00C4\\uFB03n");
+
+ canonTests[16][0] = str("Henry IV"); canonTests[16][1] = str("Henry IV"); canonTests[16][2] = str("Henry IV");
+
+ canonTests[17][0] = str("Henry \\u2163"); canonTests[17][1] = str("Henry \\u2163"); canonTests[17][2] = str("Henry \\u2163");
+
+ canonTests[18][0] = str("\\u30AC"); canonTests[18][1] = str("\\u30AB\\u3099"); canonTests[18][2] = str("\\u30AC"); // ga (Katakana)
+
+ canonTests[19][0] = str("\\u30AB\\u3099"); canonTests[19][1] = str("\\u30AB\\u3099"); canonTests[19][2] = str("\\u30AC"); // ka + ten
+
+ canonTests[20][0] = str("\\uFF76\\uFF9E"); canonTests[20][1] = str("\\uFF76\\uFF9E"); canonTests[20][2] = str("\\uFF76\\uFF9E"); // hw_ka + hw_ten
+
+ canonTests[21][0] = str("\\u30AB\\uFF9E"); canonTests[21][1] = str("\\u30AB\\uFF9E"); canonTests[21][2] = str("\\u30AB\\uFF9E"); // ka + hw_ten
+
+ canonTests[22][0] = str("\\uFF76\\u3099"); canonTests[22][1] = str("\\uFF76\\u3099"); canonTests[22][2] = str("\\uFF76\\u3099"); // hw_ka + ten
+
+ canonTests[23][0] = str("A\\u0300\\u0316"); canonTests[23][1] = str("A\\u0316\\u0300"); canonTests[23][2] = str("\\u00C0\\u0316");
+
+ /* compatTest */
+ // Input Decomposed Composed
+ compatTests[0][0] = str("cat"); compatTests[0][1] = str("cat"); compatTests[0][2] = str("cat") ;
+
+ compatTests[1][0] = str("\\uFB4f"); compatTests[1][1] = str("\\u05D0\\u05DC"); compatTests[1][2] = str("\\u05D0\\u05DC"); // Alef-Lamed vs. Alef, Lamed
+
+ compatTests[2][0] = str("\\u00C4ffin"); compatTests[2][1] = str("A\\u0308ffin"); compatTests[2][2] = str("\\u00C4ffin") ;
+
+ compatTests[3][0] = str("\\u00C4\\uFB03n"); compatTests[3][1] = str("A\\u0308ffin"); compatTests[3][2] = str("\\u00C4ffin") ; // ffi ligature -> f + f + i
+
+ compatTests[4][0] = str("Henry IV"); compatTests[4][1] = str("Henry IV"); compatTests[4][2] = str("Henry IV") ;
+
+ compatTests[5][0] = str("Henry \\u2163"); compatTests[5][1] = str("Henry IV"); compatTests[5][2] = str("Henry IV") ;
+
+ compatTests[6][0] = str("\\u30AC"); compatTests[6][1] = str("\\u30AB\\u3099"); compatTests[6][2] = str("\\u30AC") ; // ga (Katakana)
+
+ compatTests[7][0] = str("\\u30AB\\u3099"); compatTests[7][1] = str("\\u30AB\\u3099"); compatTests[7][2] = str("\\u30AC") ; // ka + ten
+
+ compatTests[8][0] = str("\\uFF76\\u3099"); compatTests[8][1] = str("\\u30AB\\u3099"); compatTests[8][2] = str("\\u30AC") ; // hw_ka + ten
+
+ /* These two are broken in Unicode 2.1.2 but fixed in 2.1.5 and later */
+ compatTests[9][0] = str("\\uFF76\\uFF9E"); compatTests[9][1] = str("\\u30AB\\u3099"); compatTests[9][2] = str("\\u30AC") ; // hw_ka + hw_ten
+
+ compatTests[10][0] = str("\\u30AB\\uFF9E"); compatTests[10][1] = str("\\u30AB\\u3099"); compatTests[10][2] = str("\\u30AC") ; // ka + hw_ten
+
+ /* Hangul Canonical */
+ // Input Decomposed Composed
+ hangulCanon[0][0] = str("\\ud4db"); hangulCanon[0][1] = str("\\u1111\\u1171\\u11b6"); hangulCanon[0][2] = str("\\ud4db") ;
+
+ hangulCanon[1][0] = str("\\u1111\\u1171\\u11b6"), hangulCanon[1][1] = str("\\u1111\\u1171\\u11b6"), hangulCanon[1][2] = str("\\ud4db");
+}
+
+BasicNormalizerTest::~BasicNormalizerTest()
+{
+}
+
+void BasicNormalizerTest::TestPrevious()
+{
+ Normalizer* norm = new Normalizer("", UNORM_NFD);
+
+ logln("testing decomp...");
+ uint32_t i;
+ for (i = 0; i < ARRAY_LENGTH(canonTests); i++) {
+ backAndForth(norm, canonTests[i][0]);
+ }
+
+ logln("testing compose...");
+ norm->setMode(UNORM_NFC);
+ for (i = 0; i < ARRAY_LENGTH(canonTests); i++) {
+ backAndForth(norm, canonTests[i][0]);
+ }
+
+ delete norm;
+}
+
+void BasicNormalizerTest::TestDecomp()
+{
+ Normalizer* norm = new Normalizer("", UNORM_NFD);
+ iterateTest(norm, canonTests, ARRAY_LENGTH(canonTests), 1);
+ staticTest(UNORM_NFD, 0, canonTests, ARRAY_LENGTH(canonTests), 1);
+ delete norm;
+}
+
+void BasicNormalizerTest::TestCompatDecomp()
+{
+ Normalizer* norm = new Normalizer("", UNORM_NFKD);
+ iterateTest(norm, compatTests, ARRAY_LENGTH(compatTests), 1);
+
+ staticTest(UNORM_NFKD, 0,
+ compatTests, ARRAY_LENGTH(compatTests), 1);
+ delete norm;
+}
+
+void BasicNormalizerTest::TestCanonCompose()
+{
+ Normalizer* norm = new Normalizer("", UNORM_NFC);
+ iterateTest(norm, canonTests, ARRAY_LENGTH(canonTests), 2);
+
+ staticTest(UNORM_NFC, 0, canonTests,
+ ARRAY_LENGTH(canonTests), 2);
+ delete norm;
+}
+
+void BasicNormalizerTest::TestCompatCompose()
+{
+ Normalizer* norm = new Normalizer("", UNORM_NFKC);
+ iterateTest(norm, compatTests, ARRAY_LENGTH(compatTests), 2);
+
+ staticTest(UNORM_NFKC, 0,
+ compatTests, ARRAY_LENGTH(compatTests), 2);
+ delete norm;
+}
+
+
+//-------------------------------------------------------------------------------
+
+void BasicNormalizerTest::TestHangulCompose()
+{
+ // Make sure that the static composition methods work
+ logln("Canonical composition...");
+ staticTest(UNORM_NFC, 0, hangulCanon, ARRAY_LENGTH(hangulCanon), 2);
+ logln("Compatibility composition...");
+
+ // Now try iterative composition....
+ logln("Static composition...");
+ Normalizer* norm = new Normalizer("", UNORM_NFC);
+ iterateTest(norm, hangulCanon, ARRAY_LENGTH(hangulCanon), 2);
+ norm->setMode(UNORM_NFKC);
+
+ // And finally, make sure you can do it in reverse too
+ logln("Reverse iteration...");
+ norm->setMode(UNORM_NFC);
+ for (uint32_t i = 0; i < ARRAY_LENGTH(hangulCanon); i++) {
+ backAndForth(norm, hangulCanon[i][0]);
+ }
+ delete norm;
+}
+
+void BasicNormalizerTest::TestHangulDecomp()
+{
+ // Make sure that the static decomposition methods work
+ logln("Canonical decomposition...");
+ staticTest(UNORM_NFD, 0, hangulCanon, ARRAY_LENGTH(hangulCanon), 1);
+ logln("Compatibility decomposition...");
+
+ // Now the iterative decomposition methods...
+ logln("Iterative decomposition...");
+ Normalizer* norm = new Normalizer("", UNORM_NFD);
+ iterateTest(norm, hangulCanon, ARRAY_LENGTH(hangulCanon), 1);
+ norm->setMode(UNORM_NFKD);
+
+ // And finally, make sure you can do it in reverse too
+ logln("Reverse iteration...");
+ norm->setMode(UNORM_NFD);
+ for (uint32_t i = 0; i < ARRAY_LENGTH(hangulCanon); i++) {
+ backAndForth(norm, hangulCanon[i][0]);
+ }
+ delete norm;
+}
+
+/**
+ * The Tibetan vowel sign AA, 0f71, was messed up prior to Unicode version 2.1.9.
+ */
+void BasicNormalizerTest::TestTibetan(void) {
+ UnicodeString decomp[1][3];
+ decomp[0][0] = str("\\u0f77");
+ decomp[0][1] = str("\\u0f77");
+ decomp[0][2] = str("\\u0fb2\\u0f71\\u0f80");
+
+ UnicodeString compose[1][3];
+ compose[0][0] = str("\\u0fb2\\u0f71\\u0f80");
+ compose[0][1] = str("\\u0fb2\\u0f71\\u0f80");
+ compose[0][2] = str("\\u0fb2\\u0f71\\u0f80");
+
+ staticTest(UNORM_NFD, 0, decomp, ARRAY_LENGTH(decomp), 1);
+ staticTest(UNORM_NFKD, 0, decomp, ARRAY_LENGTH(decomp), 2);
+ staticTest(UNORM_NFC, 0, compose, ARRAY_LENGTH(compose), 1);
+ staticTest(UNORM_NFKC, 0, compose, ARRAY_LENGTH(compose), 2);
+}
+
+/**
+ * Make sure characters in the CompositionExclusion.txt list do not get
+ * composed to.
+ */
+void BasicNormalizerTest::TestCompositionExclusion(void) {
+ // This list is generated from CompositionExclusion.txt.
+ // Update whenever the normalizer tables are updated. Note
+ // that we test all characters listed, even those that can be
+ // derived from the Unicode DB and are therefore commented
+ // out.
+ // ### TODO read composition exclusion from source/data/unidata file
+ // and test against that
+ UnicodeString EXCLUDED = str(
+ "\\u0340\\u0341\\u0343\\u0344\\u0374\\u037E\\u0387\\u0958"
+ "\\u0959\\u095A\\u095B\\u095C\\u095D\\u095E\\u095F\\u09DC"
+ "\\u09DD\\u09DF\\u0A33\\u0A36\\u0A59\\u0A5A\\u0A5B\\u0A5E"
+ "\\u0B5C\\u0B5D\\u0F43\\u0F4D\\u0F52\\u0F57\\u0F5C\\u0F69"
+ "\\u0F73\\u0F75\\u0F76\\u0F78\\u0F81\\u0F93\\u0F9D\\u0FA2"
+ "\\u0FA7\\u0FAC\\u0FB9\\u1F71\\u1F73\\u1F75\\u1F77\\u1F79"
+ "\\u1F7B\\u1F7D\\u1FBB\\u1FBE\\u1FC9\\u1FCB\\u1FD3\\u1FDB"
+ "\\u1FE3\\u1FEB\\u1FEE\\u1FEF\\u1FF9\\u1FFB\\u1FFD\\u2000"
+ "\\u2001\\u2126\\u212A\\u212B\\u2329\\u232A\\uF900\\uFA10"
+ "\\uFA12\\uFA15\\uFA20\\uFA22\\uFA25\\uFA26\\uFA2A\\uFB1F"
+ "\\uFB2A\\uFB2B\\uFB2C\\uFB2D\\uFB2E\\uFB2F\\uFB30\\uFB31"
+ "\\uFB32\\uFB33\\uFB34\\uFB35\\uFB36\\uFB38\\uFB39\\uFB3A"
+ "\\uFB3B\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46"
+ "\\uFB47\\uFB48\\uFB49\\uFB4A\\uFB4B\\uFB4C\\uFB4D\\uFB4E"
+ );
+ for (int32_t i=0; i<EXCLUDED.length(); ++i) {
+ UnicodeString a(EXCLUDED.charAt(i));
+ UnicodeString b;
+ UnicodeString c;
+ Normalizer::normalize(a, UNORM_NFKD, 0, b, status);
+ Normalizer::normalize(b, UNORM_NFC, 0, c, status);
+ if (c == a) {
+ errln("FAIL: " + hex(a) + " x DECOMP_COMPAT => " +
+ hex(b) + " x COMPOSE => " +
+ hex(c));
+ } else if (verbose) {
+ logln("Ok: " + hex(a) + " x DECOMP_COMPAT => " +
+ hex(b) + " x COMPOSE => " +
+ hex(c));
+ }
+ }
+}
+
+/**
+ * Test for a problem that showed up just before ICU 1.6 release
+ * having to do with combining characters with an index of zero.
+ * Such characters do not participate in any canonical
+ * decompositions. However, having an index of zero means that
+ * they all share one typeMask[] entry, that is, they all have to
+ * map to the same canonical class, which is not the case, in
+ * reality.
+ */
+void BasicNormalizerTest::TestZeroIndex(void) {
+ const char* DATA[] = {
+ // Expect col1 x COMPOSE_COMPAT => col2
+ // Expect col2 x DECOMP => col3
+ "A\\u0316\\u0300", "\\u00C0\\u0316", "A\\u0316\\u0300",
+ "A\\u0300\\u0316", "\\u00C0\\u0316", "A\\u0316\\u0300",
+ "A\\u0327\\u0300", "\\u00C0\\u0327", "A\\u0327\\u0300",
+ "c\\u0321\\u0327", "c\\u0321\\u0327", "c\\u0321\\u0327",
+ "c\\u0327\\u0321", "\\u00E7\\u0321", "c\\u0327\\u0321",
+ };
+ int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+
+ for (int32_t i=0; i<DATA_length; i+=3) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString a(DATA[i], "");
+ a = a.unescape();
+ UnicodeString b;
+ Normalizer::normalize(a, UNORM_NFKC, 0, b, status);
+ UnicodeString exp(DATA[i+1], "");
+ exp = exp.unescape();
+ if (b == exp) {
+ logln((UnicodeString)"Ok: " + hex(a) + " x COMPOSE_COMPAT => " + hex(b));
+ } else {
+ errln((UnicodeString)"FAIL: " + hex(a) + " x COMPOSE_COMPAT => " + hex(b) +
+ ", expect " + hex(exp));
+ }
+ Normalizer::normalize(b, UNORM_NFD, 0, a, status);
+ exp = UnicodeString(DATA[i+2], "").unescape();
+ if (a == exp) {
+ logln((UnicodeString)"Ok: " + hex(b) + " x DECOMP => " + hex(a));
+ } else {
+ errln((UnicodeString)"FAIL: " + hex(b) + " x DECOMP => " + hex(a) +
+ ", expect " + hex(exp));
+ }
+ }
+}
+
+/**
+ * Run a few specific cases that are failing for Verisign.
+ */
+void BasicNormalizerTest::TestVerisign(void) {
+ /*
+ > Their input:
+ > 05B8 05B9 05B1 0591 05C3 05B0 05AC 059F
+ > Their output (supposedly from ICU):
+ > 05B8 05B1 05B9 0591 05C3 05B0 05AC 059F
+ > My output from charlint:
+ > 05B1 05B8 05B9 0591 05C3 05B0 05AC 059F
+
+ 05B8 05B9 05B1 0591 05C3 05B0 05AC 059F => 05B1 05B8 05B9 0591 05C3 05B0
+ 05AC 059F
+
+ U+05B8 18 E HEBREW POINT QAMATS
+ U+05B9 19 F HEBREW POINT HOLAM
+ U+05B1 11 HEBREW POINT HATAF SEGOL
+ U+0591 220 HEBREW ACCENT ETNAHTA
+ U+05C3 0 HEBREW PUNCTUATION SOF PASUQ
+ U+05B0 10 HEBREW POINT SHEVA
+ U+05AC 230 HEBREW ACCENT ILUY
+ U+059F 230 HEBREW ACCENT QARNEY PARA
+
+ U+05B1 11 HEBREW POINT HATAF SEGOL
+ U+05B8 18 HEBREW POINT QAMATS
+ U+05B9 19 HEBREW POINT HOLAM
+ U+0591 220 HEBREW ACCENT ETNAHTA
+ U+05C3 0 HEBREW PUNCTUATION SOF PASUQ
+ U+05B0 10 HEBREW POINT SHEVA
+ U+05AC 230 HEBREW ACCENT ILUY
+ U+059F 230 HEBREW ACCENT QARNEY PARA
+
+ Wrong result:
+ U+05B8 18 HEBREW POINT QAMATS
+ U+05B1 11 HEBREW POINT HATAF SEGOL
+ U+05B9 19 HEBREW POINT HOLAM
+ U+0591 220 HEBREW ACCENT ETNAHTA
+ U+05C3 0 HEBREW PUNCTUATION SOF PASUQ
+ U+05B0 10 HEBREW POINT SHEVA
+ U+05AC 230 HEBREW ACCENT ILUY
+ U+059F 230 HEBREW ACCENT QARNEY PARA
+
+
+ > Their input:
+ >0592 05B7 05BC 05A5 05B0 05C0 05C4 05AD
+ >Their output (supposedly from ICU):
+ >0592 05B0 05B7 05BC 05A5 05C0 05AD 05C4
+ >My output from charlint:
+ >05B0 05B7 05BC 05A5 0592 05C0 05AD 05C4
+
+ 0592 05B7 05BC 05A5 05B0 05C0 05C4 05AD => 05B0 05B7 05BC 05A5 0592 05C0
+ 05AD 05C4
+
+ U+0592 230 HEBREW ACCENT SEGOL
+ U+05B7 17 HEBREW POINT PATAH
+ U+05BC 21 HEBREW POINT DAGESH OR MAPIQ
+ U+05A5 220 HEBREW ACCENT MERKHA
+ U+05B0 10 HEBREW POINT SHEVA
+ U+05C0 0 HEBREW PUNCTUATION PASEQ
+ U+05C4 230 HEBREW MARK UPPER DOT
+ U+05AD 222 HEBREW ACCENT DEHI
+
+ U+05B0 10 HEBREW POINT SHEVA
+ U+05B7 17 HEBREW POINT PATAH
+ U+05BC 21 HEBREW POINT DAGESH OR MAPIQ
+ U+05A5 220 HEBREW ACCENT MERKHA
+ U+0592 230 HEBREW ACCENT SEGOL
+ U+05C0 0 HEBREW PUNCTUATION PASEQ
+ U+05AD 222 HEBREW ACCENT DEHI
+ U+05C4 230 HEBREW MARK UPPER DOT
+
+ Wrong result:
+ U+0592 230 HEBREW ACCENT SEGOL
+ U+05B0 10 HEBREW POINT SHEVA
+ U+05B7 17 HEBREW POINT PATAH
+ U+05BC 21 HEBREW POINT DAGESH OR MAPIQ
+ U+05A5 220 HEBREW ACCENT MERKHA
+ U+05C0 0 HEBREW PUNCTUATION PASEQ
+ U+05AD 222 HEBREW ACCENT DEHI
+ U+05C4 230 HEBREW MARK UPPER DOT
+ */
+ UnicodeString data[2][3];
+ data[0][0] = str("\\u05B8\\u05B9\\u05B1\\u0591\\u05C3\\u05B0\\u05AC\\u059F");
+ data[0][1] = str("\\u05B1\\u05B8\\u05B9\\u0591\\u05C3\\u05B0\\u05AC\\u059F");
+ data[0][2] = str("");
+ data[1][0] = str("\\u0592\\u05B7\\u05BC\\u05A5\\u05B0\\u05C0\\u05C4\\u05AD");
+ data[1][1] = str("\\u05B0\\u05B7\\u05BC\\u05A5\\u0592\\u05C0\\u05AD\\u05C4");
+ data[1][2] = str("");
+
+ staticTest(UNORM_NFD, 0, data, ARRAY_LENGTH(data), 1);
+ staticTest(UNORM_NFC, 0, data, ARRAY_LENGTH(data), 1);
+}
+
+//------------------------------------------------------------------------
+// Internal utilities
+//
+
+UnicodeString BasicNormalizerTest::hex(UChar ch) {
+ UnicodeString result;
+ return appendHex(ch, 4, result);
+}
+
+UnicodeString BasicNormalizerTest::hex(const UnicodeString& s) {
+ UnicodeString result;
+ for (int i = 0; i < s.length(); ++i) {
+ if (i != 0) result += (UChar)0x2c/*,*/;
+ appendHex(s[i], 4, result);
+ }
+ return result;
+}
+
+
+inline static void insert(UnicodeString& dest, int pos, UChar32 ch)
+{
+ dest.replace(pos, 0, ch);
+}
+
+void BasicNormalizerTest::backAndForth(Normalizer* iter, const UnicodeString& input)
+{
+ UChar32 ch;
+ iter->setText(input, status);
+
+ // Run through the iterator forwards and stick it into a StringBuffer
+ UnicodeString forward;
+ for (ch = iter->first(); ch != iter->DONE; ch = iter->next()) {
+ forward += ch;
+ }
+
+ // Now do it backwards
+ UnicodeString reverse;
+ for (ch = iter->last(); ch != iter->DONE; ch = iter->previous()) {
+ insert(reverse, 0, ch);
+ }
+
+ if (forward != reverse) {
+ errln("Forward/reverse mismatch for input " + hex(input)
+ + ", forward: " + hex(forward) + ", backward: " + hex(reverse));
+ }
+}
+
+void BasicNormalizerTest::staticTest(UNormalizationMode mode, int options,
+ UnicodeString tests[][3], int length,
+ int outCol)
+{
+ for (int i = 0; i < length; i++)
+ {
+ UnicodeString& input = tests[i][0];
+ UnicodeString& expect = tests[i][outCol];
+
+ logln("Normalizing '" + input + "' (" + hex(input) + ")" );
+
+ UnicodeString output;
+ Normalizer::normalize(input, mode, options, output, status);
+
+ if (output != expect) {
+ errln(UnicodeString("ERROR: case ") + i + " normalized " + hex(input) + "\n"
+ + " expected " + hex(expect) + "\n"
+ + " static got " + hex(output) );
+ }
+ }
+}
+
+void BasicNormalizerTest::iterateTest(Normalizer* iter,
+ UnicodeString tests[][3], int length,
+ int outCol)
+{
+ for (int i = 0; i < length; i++)
+ {
+ UnicodeString& input = tests[i][0];
+ UnicodeString& expect = tests[i][outCol];
+
+ logln("Normalizing '" + input + "' (" + hex(input) + ")" );
+
+ iter->setText(input, status);
+ assertEqual(input, expect, iter, UnicodeString("ERROR: case ") + i + " ");
+ }
+}
+
+void BasicNormalizerTest::assertEqual(const UnicodeString& input,
+ const UnicodeString& expected,
+ Normalizer* iter,
+ const UnicodeString& errPrefix)
+{
+ UnicodeString result;
+
+ for (UChar32 ch = iter->first(); ch != iter->DONE; ch = iter->next()) {
+ result += ch;
+ }
+ if (result != expected) {
+ errln(errPrefix + "normalized " + hex(input) + "\n"
+ + " expected " + hex(expected) + "\n"
+ + " iterate got " + hex(result) );
+ }
+}
+
+// helper class for TestPreviousNext()
+// simple UTF-32 character iterator
+class UChar32Iterator {
+public:
+ UChar32Iterator(const UChar32 *text, int32_t len, int32_t index) :
+ s(text), length(len), i(index) {}
+
+ UChar32 current() {
+ if(i<length) {
+ return s[i];
+ } else {
+ return 0xffff;
+ }
+ }
+
+ UChar32 next() {
+ if(i<length) {
+ return s[i++];
+ } else {
+ return 0xffff;
+ }
+ }
+
+ UChar32 previous() {
+ if(i>0) {
+ return s[--i];
+ } else {
+ return 0xffff;
+ }
+ }
+
+ int32_t getIndex() {
+ return i;
+ }
+private:
+ const UChar32 *s;
+ int32_t length, i;
+};
+
+void
+BasicNormalizerTest::TestPreviousNext(const UChar *src, int32_t srcLength,
+ const UChar32 *expect, int32_t expectLength,
+ const int32_t *expectIndex, // its length=expectLength+1
+ int32_t srcMiddle, int32_t expectMiddle,
+ const char *moves,
+ UNormalizationMode mode,
+ const char *name) {
+ // iterators
+ Normalizer iter(src, srcLength, mode);
+
+ // test getStaticClassID and getDynamicClassID
+ if(iter.getDynamicClassID() != Normalizer::getStaticClassID()) {
+ errln("getStaticClassID != getDynamicClassID for Normalizer.");
+ }
+
+ UChar32Iterator iter32(expect, expectLength, expectMiddle);
+
+ UChar32 c1, c2;
+ char m;
+
+ // initially set the indexes into the middle of the strings
+ iter.setIndexOnly(srcMiddle);
+
+ // move around and compare the iteration code points with
+ // the expected ones
+ const char *move=moves;
+ while((m=*move++)!=0) {
+ if(m=='-') {
+ c1=iter.previous();
+ c2=iter32.previous();
+ } else if(m=='0') {
+ c1=iter.current();
+ c2=iter32.current();
+ } else /* m=='+' */ {
+ c1=iter.next();
+ c2=iter32.next();
+ }
+
+ // compare results
+ if(c1!=c2) {
+ // copy the moves until the current (m) move, and terminate
+ char history[64];
+ uprv_strcpy(history, moves);
+ history[move-moves]=0;
+ errln("error: mismatch in Normalizer iteration (%s) at %s: "
+ "got c1=U+%04lx != expected c2=U+%04lx\n",
+ name, history, c1, c2);
+ break;
+ }
+
+ // compare indexes
+ if(iter.getIndex()!=expectIndex[iter32.getIndex()]) {
+ // copy the moves until the current (m) move, and terminate
+ char history[64];
+ uprv_strcpy(history, moves);
+ history[move-moves]=0;
+ errln("error: index mismatch in Normalizer iteration (%s) at %s: "
+ "Normalizer index %ld expected %ld\n",
+ name, history, iter.getIndex(), expectIndex[iter32.getIndex()]);
+ break;
+ }
+ }
+}
+
+void
+BasicNormalizerTest::TestPreviousNext() {
+ // src and expect strings
+ static const UChar src[]={
+ UTF16_LEAD(0x2f999), UTF16_TRAIL(0x2f999),
+ UTF16_LEAD(0x1d15f), UTF16_TRAIL(0x1d15f),
+ 0xc4,
+ 0x1ed0
+ };
+ static const UChar32 expect[]={
+ 0x831d,
+ 0x1d158, 0x1d165,
+ 0x41, 0x308,
+ 0x4f, 0x302, 0x301
+ };
+
+ // expected src indexes corresponding to expect indexes
+ static const int32_t expectIndex[]={
+ 0,
+ 2, 2,
+ 4, 4,
+ 5, 5, 5,
+ 6 // behind last character
+ };
+
+ // src and expect strings for regression test for j2911
+ static const UChar src_j2911[]={
+ UTF16_LEAD(0x2f999), UTF16_TRAIL(0x2f999),
+ 0xdd00, 0xd900, // unpaired surrogates - regression test for j2911
+ 0xc4,
+ 0x4f, 0x302, 0x301
+ };
+ static const UChar32 expect_j2911[]={
+ 0x831d,
+ 0xdd00, 0xd900, // unpaired surrogates - regression test for j2911
+ 0xc4,
+ 0x1ed0
+ };
+
+ // expected src indexes corresponding to expect indexes
+ static const int32_t expectIndex_j2911[]={
+ 0,
+ 2, 3,
+ 4,
+ 5,
+ 8 // behind last character
+ };
+
+ // initial indexes into the src and expect strings
+ // for both sets of test data
+ enum {
+ SRC_MIDDLE=4,
+ EXPECT_MIDDLE=3,
+ SRC_MIDDLE_2=2,
+ EXPECT_MIDDLE_2=1
+ };
+
+ // movement vector
+ // - for previous(), 0 for current(), + for next()
+ // for both sets of test data
+ static const char *const moves="0+0+0--0-0-+++0--+++++++0--------";
+
+ TestPreviousNext(src, LENGTHOF(src),
+ expect, LENGTHOF(expect),
+ expectIndex,
+ SRC_MIDDLE, EXPECT_MIDDLE,
+ moves, UNORM_NFD, "basic");
+
+ TestPreviousNext(src_j2911, LENGTHOF(src_j2911),
+ expect_j2911, LENGTHOF(expect_j2911),
+ expectIndex_j2911,
+ SRC_MIDDLE, EXPECT_MIDDLE,
+ moves, UNORM_NFKC, "j2911");
+
+ // try again from different "middle" indexes
+ TestPreviousNext(src, LENGTHOF(src),
+ expect, LENGTHOF(expect),
+ expectIndex,
+ SRC_MIDDLE_2, EXPECT_MIDDLE_2,
+ moves, UNORM_NFD, "basic_2");
+
+ TestPreviousNext(src_j2911, LENGTHOF(src_j2911),
+ expect_j2911, LENGTHOF(expect_j2911),
+ expectIndex_j2911,
+ SRC_MIDDLE_2, EXPECT_MIDDLE_2,
+ moves, UNORM_NFKC, "j2911_2");
+}
+
+void BasicNormalizerTest::TestConcatenate() {
+ static const char *const
+ cases[][4]={
+ /* mode, left, right, result */
+ {
+ "C",
+ "re",
+ "\\u0301sum\\u00e9",
+ "r\\u00e9sum\\u00e9"
+ },
+ {
+ "C",
+ "a\\u1100",
+ "\\u1161bcdefghijk",
+ "a\\uac00bcdefghijk"
+ },
+ /* ### TODO: add more interesting cases */
+ {
+ "D",
+ "\\u0340\\u0341\\u0343\\u0344\\u0374\\u037E\\u0387\\u0958"
+ "\\u0959\\u095A\\u095B\\u095C\\u095D\\u095E\\u095F\\u09DC"
+ "\\u09DD\\u09DF\\u0A33\\u0A36\\u0A59\\u0A5A\\u0A5B\\u0A5E"
+ "\\u0B5C\\u0B5D\\u0F43\\u0F4D\\u0F52\\u0F57\\u0F5C\\u0F69"
+ "\\u0F73\\u0F75\\u0F76\\u0F78\\u0F81\\u0F93\\u0F9D\\u0FA2"
+ "\\u0FA7\\u0FAC\\u0FB9\\u1F71\\u1F73\\u1F75\\u1F77\\u1F79"
+ "\\u1F7B\\u1F7D\\u1FBB\\u1FBE\\u1FC9\\u1FCB\\u1FD3\\u1FDB",
+
+ "\\u1FE3\\u1FEB\\u1FEE\\u1FEF\\u1FF9\\u1FFB\\u1FFD\\u2000"
+ "\\u2001\\u2126\\u212A\\u212B\\u2329\\u232A\\uF900\\uFA10"
+ "\\uFA12\\uFA15\\uFA20\\uFA22\\uFA25\\uFA26\\uFA2A\\uFB1F"
+ "\\uFB2A\\uFB2B\\uFB2C\\uFB2D\\uFB2E\\uFB2F\\uFB30\\uFB31"
+ "\\uFB32\\uFB33\\uFB34\\uFB35\\uFB36\\uFB38\\uFB39\\uFB3A"
+ "\\uFB3B\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46"
+ "\\uFB47\\uFB48\\uFB49\\uFB4A\\uFB4B\\uFB4C\\uFB4D\\uFB4E",
+
+ "\\u0340\\u0341\\u0343\\u0344\\u0374\\u037E\\u0387\\u0958"
+ "\\u0959\\u095A\\u095B\\u095C\\u095D\\u095E\\u095F\\u09DC"
+ "\\u09DD\\u09DF\\u0A33\\u0A36\\u0A59\\u0A5A\\u0A5B\\u0A5E"
+ "\\u0B5C\\u0B5D\\u0F43\\u0F4D\\u0F52\\u0F57\\u0F5C\\u0F69"
+ "\\u0F73\\u0F75\\u0F76\\u0F78\\u0F81\\u0F93\\u0F9D\\u0FA2"
+ "\\u0FA7\\u0FAC\\u0FB9\\u1F71\\u1F73\\u1F75\\u1F77\\u1F79"
+ "\\u1F7B\\u1F7D\\u1FBB\\u1FBE\\u1FC9\\u1FCB\\u1FD3\\u0399"
+ "\\u0301\\u03C5\\u0308\\u0301\\u1FEB\\u1FEE\\u1FEF\\u1FF9"
+ "\\u1FFB\\u1FFD\\u2000\\u2001\\u2126\\u212A\\u212B\\u2329"
+ "\\u232A\\uF900\\uFA10\\uFA12\\uFA15\\uFA20\\uFA22\\uFA25"
+ "\\uFA26\\uFA2A\\uFB1F\\uFB2A\\uFB2B\\uFB2C\\uFB2D\\uFB2E"
+ "\\uFB2F\\uFB30\\uFB31\\uFB32\\uFB33\\uFB34\\uFB35\\uFB36"
+ "\\uFB38\\uFB39\\uFB3A\\uFB3B\\uFB3C\\uFB3E\\uFB40\\uFB41"
+ "\\uFB43\\uFB44\\uFB46\\uFB47\\uFB48\\uFB49\\uFB4A\\uFB4B"
+ "\\uFB4C\\uFB4D\\uFB4E"
+ }
+ };
+
+ UnicodeString left, right, expect, result, r;
+ UErrorCode errorCode;
+ UNormalizationMode mode;
+ int32_t i;
+
+ /* test concatenation */
+ for(i=0; i<(int32_t)(sizeof(cases)/sizeof(cases[0])); ++i) {
+ switch(*cases[i][0]) {
+ case 'C': mode=UNORM_NFC; break;
+ case 'D': mode=UNORM_NFD; break;
+ case 'c': mode=UNORM_NFKC; break;
+ case 'd': mode=UNORM_NFKD; break;
+ default: mode=UNORM_NONE; break;
+ }
+
+ left=UnicodeString(cases[i][1], "").unescape();
+ right=UnicodeString(cases[i][2], "").unescape();
+ expect=UnicodeString(cases[i][3], "").unescape();
+
+ //result=r=UnicodeString();
+ errorCode=U_ZERO_ERROR;
+
+ r=Normalizer::concatenate(left, right, result, mode, 0, errorCode);
+ if(U_FAILURE(errorCode) || /*result!=r ||*/ result!=expect) {
+ errln("error in Normalizer::concatenate(), cases[] fails with "+
+ UnicodeString(u_errorName(errorCode))+", result==expect: expected: "+
+ hex(expect)+" =========> got: " + hex(result));
+ }
+ }
+
+ /* test error cases */
+
+ /* left.getBuffer()==result.getBuffer() */
+ result=r=expect=UnicodeString("zz", "");
+ errorCode=U_UNEXPECTED_TOKEN;
+ r=Normalizer::concatenate(left, right, result, mode, 0, errorCode);
+ if(errorCode!=U_UNEXPECTED_TOKEN || result!=r || !result.isBogus()) {
+ errln("error in Normalizer::concatenate(), violates UErrorCode protocol");
+ }
+
+ left.setToBogus();
+ errorCode=U_ZERO_ERROR;
+ r=Normalizer::concatenate(left, right, result, mode, 0, errorCode);
+ if(errorCode!=U_ILLEGAL_ARGUMENT_ERROR || result!=r || !result.isBogus()) {
+ errln("error in Normalizer::concatenate(), does not detect left.isBogus()");
+ }
+}
+
+// reference implementation of Normalizer::compare
+static int32_t
+ref_norm_compare(const UnicodeString &s1, const UnicodeString &s2, uint32_t options, UErrorCode &errorCode) {
+ UnicodeString r1, r2, t1, t2;
+ int32_t normOptions=(int32_t)(options>>UNORM_COMPARE_NORM_OPTIONS_SHIFT);
+
+ if(options&U_COMPARE_IGNORE_CASE) {
+ Normalizer::decompose(s1, FALSE, normOptions, r1, errorCode);
+ Normalizer::decompose(s2, FALSE, normOptions, r2, errorCode);
+
+ r1.foldCase(options);
+ r2.foldCase(options);
+ } else {
+ r1=s1;
+ r2=s2;
+ }
+
+ Normalizer::decompose(r1, FALSE, normOptions, t1, errorCode);
+ Normalizer::decompose(r2, FALSE, normOptions, t2, errorCode);
+
+ if(options&U_COMPARE_CODE_POINT_ORDER) {
+ return t1.compareCodePointOrder(t2);
+ } else {
+ return t1.compare(t2);
+ }
+}
+
+// test wrapper for Normalizer::compare, sets UNORM_INPUT_IS_FCD appropriately
+static int32_t
+_norm_compare(const UnicodeString &s1, const UnicodeString &s2, uint32_t options, UErrorCode &errorCode) {
+ int32_t normOptions=(int32_t)(options>>UNORM_COMPARE_NORM_OPTIONS_SHIFT);
+
+ if( UNORM_YES==Normalizer::quickCheck(s1, UNORM_FCD, normOptions, errorCode) &&
+ UNORM_YES==Normalizer::quickCheck(s2, UNORM_FCD, normOptions, errorCode)) {
+ options|=UNORM_INPUT_IS_FCD;
+ }
+
+ return Normalizer::compare(s1, s2, options, errorCode);
+}
+
+// reference implementation of UnicodeString::caseCompare
+static int32_t
+ref_case_compare(const UnicodeString &s1, const UnicodeString &s2, uint32_t options) {
+ UnicodeString t1, t2;
+
+ t1=s1;
+ t2=s2;
+
+ t1.foldCase(options);
+ t2.foldCase(options);
+
+ if(options&U_COMPARE_CODE_POINT_ORDER) {
+ return t1.compareCodePointOrder(t2);
+ } else {
+ return t1.compare(t2);
+ }
+}
+
+// reduce an integer to -1/0/1
+static inline int32_t
+_sign(int32_t value) {
+ if(value==0) {
+ return 0;
+ } else {
+ return (value>>31)|1;
+ }
+}
+
+static const char *
+_signString(int32_t value) {
+ if(value<0) {
+ return "<0";
+ } else if(value==0) {
+ return "=0";
+ } else /* value>0 */ {
+ return ">0";
+ }
+}
+
+void
+BasicNormalizerTest::TestCompare() {
+ // test Normalizer::compare and unorm_compare (thinly wrapped by the former)
+ // by comparing it with its semantic equivalent
+ // since we trust the pieces, this is sufficient
+
+ // test each string with itself and each other
+ // each time with all options
+ static const char *const
+ strings[]={
+ // some cases from NormalizationTest.txt
+ // 0..3
+ "D\\u031B\\u0307\\u0323",
+ "\\u1E0C\\u031B\\u0307",
+ "D\\u031B\\u0323\\u0307",
+ "d\\u031B\\u0323\\u0307",
+
+ // 4..6
+ "\\u00E4",
+ "a\\u0308",
+ "A\\u0308",
+
+ // Angstrom sign = A ring
+ // 7..10
+ "\\u212B",
+ "\\u00C5",
+ "A\\u030A",
+ "a\\u030A",
+
+ // 11.14
+ "a\\u059A\\u0316\\u302A\\u032Fb",
+ "a\\u302A\\u0316\\u032F\\u059Ab",
+ "a\\u302A\\u0316\\u032F\\u059Ab",
+ "A\\u059A\\u0316\\u302A\\u032Fb",
+
+ // from ICU case folding tests
+ // 15..20
+ "A\\u00df\\u00b5\\ufb03\\U0001040c\\u0131",
+ "ass\\u03bcffi\\U00010434i",
+ "\\u0061\\u0042\\u0131\\u03a3\\u00df\\ufb03\\ud93f\\udfff",
+ "\\u0041\\u0062\\u0069\\u03c3\\u0073\\u0053\\u0046\\u0066\\u0049\\ud93f\\udfff",
+ "\\u0041\\u0062\\u0131\\u03c3\\u0053\\u0073\\u0066\\u0046\\u0069\\ud93f\\udfff",
+ "\\u0041\\u0062\\u0069\\u03c3\\u0073\\u0053\\u0046\\u0066\\u0049\\ud93f\\udffd",
+
+ // U+d800 U+10001 see implementation comment in unorm_cmpEquivFold
+ // vs. U+10000 at bottom - code point order
+ // 21..22
+ "\\ud800\\ud800\\udc01",
+ "\\ud800\\udc00",
+
+ // other code point order tests from ustrtest.cpp
+ // 23..31
+ "\\u20ac\\ud801",
+ "\\u20ac\\ud800\\udc00",
+ "\\ud800",
+ "\\ud800\\uff61",
+ "\\udfff",
+ "\\uff61\\udfff",
+ "\\uff61\\ud800\\udc02",
+ "\\ud800\\udc02",
+ "\\ud84d\\udc56",
+
+ // long strings, see cnormtst.c/TestNormCoverage()
+ // equivalent if case-insensitive
+ // 32..33
+ "\\uAD8B\\uAD8B\\uAD8B\\uAD8B"
+ "\\U0001d15e\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "\\U0001d15e\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "\\U0001d15e\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "aaaaaaaaaaaaaaaaaazzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "\\uAD8B\\uAD8B\\uAD8B\\uAD8B"
+ "d\\u031B\\u0307\\u0323",
+
+ "\\u1100\\u116f\\u11aa\\uAD8B\\uAD8B\\u1100\\u116f\\u11aa"
+ "\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "\\U0001d15e\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "\\U0001d15e\\U0001d157\\U0001d165\\U0001d15e\\U0001d15e\\U0001d15e\\U0001d15e"
+ "aaaaaaaaaaAAAAAAAAZZZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+ "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
+ "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
+ "\\u1100\\u116f\\u11aa\\uAD8B\\uAD8B\\u1100\\u116f\\u11aa"
+ "\\u1E0C\\u031B\\u0307",
+
+ // some strings that may make a difference whether the compare function
+ // case-folds or decomposes first
+ // 34..41
+ "\\u0360\\u0345\\u0334",
+ "\\u0360\\u03b9\\u0334",
+
+ "\\u0360\\u1f80\\u0334",
+ "\\u0360\\u03b1\\u0313\\u03b9\\u0334",
+
+ "\\u0360\\u1ffc\\u0334",
+ "\\u0360\\u03c9\\u03b9\\u0334",
+
+ "a\\u0360\\u0345\\u0360\\u0345b",
+ "a\\u0345\\u0360\\u0345\\u0360b",
+
+ // interesting cases for canonical caseless match with turkic i handling
+ // 42..43
+ "\\u00cc",
+ "\\u0069\\u0300",
+
+ // strings with post-Unicode 3.2 normalization or normalization corrections
+ // 44..45
+ "\\u00e4\\u193b\\U0002f868",
+ "\\u0061\\u193b\\u0308\\u36fc",
+
+ // empty string
+ // 46
+ ""
+ };
+
+ UnicodeString s[100]; // at least as many items as in strings[] !
+
+ // all combinations of options
+ // UNORM_INPUT_IS_FCD is set automatically if both input strings fulfill FCD conditions
+ // set UNORM_UNICODE_3_2 in one additional combination
+ static const struct {
+ uint32_t options;
+ const char *name;
+ } opt[]={
+ { 0, "default" },
+ { U_COMPARE_CODE_POINT_ORDER, "c.p. order" },
+ { U_COMPARE_IGNORE_CASE, "ignore case" },
+ { U_COMPARE_CODE_POINT_ORDER|U_COMPARE_IGNORE_CASE, "c.p. order & ignore case" },
+ { U_COMPARE_IGNORE_CASE|U_FOLD_CASE_EXCLUDE_SPECIAL_I, "ignore case & special i" },
+ { U_COMPARE_CODE_POINT_ORDER|U_COMPARE_IGNORE_CASE|U_FOLD_CASE_EXCLUDE_SPECIAL_I, "c.p. order & ignore case & special i" },
+ { UNORM_UNICODE_3_2<<UNORM_COMPARE_NORM_OPTIONS_SHIFT, "Unicode 3.2" }
+ };
+
+ int32_t i, j, k, count=LENGTHOF(strings);
+ int32_t result, refResult;
+
+ UErrorCode errorCode;
+
+ // create the UnicodeStrings
+ for(i=0; i<count; ++i) {
+ s[i]=UnicodeString(strings[i], "").unescape();
+ }
+
+ // test them each with each other
+ for(i=0; i<count; ++i) {
+ for(j=i; j<count; ++j) {
+ for(k=0; k<LENGTHOF(opt); ++k) {
+ // test Normalizer::compare
+ errorCode=U_ZERO_ERROR;
+ result=_norm_compare(s[i], s[j], opt[k].options, errorCode);
+ refResult=ref_norm_compare(s[i], s[j], opt[k].options, errorCode);
+ if(_sign(result)!=_sign(refResult)) {
+ errln("Normalizer::compare(%d, %d, %s)%s should be %s %s",
+ i, j, opt[k].name, _signString(result), _signString(refResult),
+ U_SUCCESS(errorCode) ? "" : u_errorName(errorCode));
+ }
+
+ // test UnicodeString::caseCompare - same internal implementation function
+ if(opt[k].options&U_COMPARE_IGNORE_CASE) {
+ errorCode=U_ZERO_ERROR;
+ result=s[i].caseCompare(s[j], opt[k].options);
+ refResult=ref_case_compare(s[i], s[j], opt[k].options);
+ if(_sign(result)!=_sign(refResult)) {
+ errln("UniStr::caseCompare(%d, %d, %s)%s should be %s %s",
+ i, j, opt[k].name, _signString(result), _signString(refResult),
+ U_SUCCESS(errorCode) ? "" : u_errorName(errorCode));
+ }
+ }
+ }
+ }
+ }
+
+ // test cases with i and I to make sure Turkic works
+ static const UChar iI[]={ 0x49, 0x69, 0x130, 0x131 };
+ USerializedSet sset;
+ UnicodeSet set;
+
+ UnicodeString s1, s2;
+ UChar32 start, end;
+
+ // collect all sets into one for contiguous output
+ for(i=0; i<LENGTHOF(iI); ++i) {
+ if(unorm_getCanonStartSet(iI[i], &sset)) {
+ count=uset_getSerializedRangeCount(&sset);
+ for(j=0; j<count; ++j) {
+ uset_getSerializedRange(&sset, j, &start, &end);
+ set.add(start, end);
+ }
+ }
+ }
+
+ // test all of these precomposed characters
+ UnicodeSetIterator it(set);
+ while(it.nextRange() && !it.isString()) {
+ start=it.getCodepoint();
+ end=it.getCodepointEnd();
+ while(start<=end) {
+ s1.setTo(start);
+ errorCode=U_ZERO_ERROR;
+ Normalizer::decompose(s1, FALSE, 0, s2, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("Normalizer::decompose(U+%04x) failed: %s", start, u_errorName(errorCode));
+ return;
+ }
+
+ for(k=0; k<LENGTHOF(opt); ++k) {
+ // test Normalizer::compare
+ errorCode=U_ZERO_ERROR;
+ result=_norm_compare(s1, s2, opt[k].options, errorCode);
+ refResult=ref_norm_compare(s1, s2, opt[k].options, errorCode);
+ if(_sign(result)!=_sign(refResult)) {
+ errln("Normalizer::compare(U+%04x with its NFD, %s)%s should be %s %s",
+ start, opt[k].name, _signString(result), _signString(refResult),
+ U_SUCCESS(errorCode) ? "" : u_errorName(errorCode));
+ }
+
+ // test UnicodeString::caseCompare - same internal implementation function
+ if(opt[k].options&U_COMPARE_IGNORE_CASE) {
+ errorCode=U_ZERO_ERROR;
+ result=s1.caseCompare(s2, opt[k].options);
+ refResult=ref_case_compare(s1, s2, opt[k].options);
+ if(_sign(result)!=_sign(refResult)) {
+ errln("UniStr::caseCompare(U+%04x with its NFD, %s)%s should be %s %s",
+ start, opt[k].name, _signString(result), _signString(refResult),
+ U_SUCCESS(errorCode) ? "" : u_errorName(errorCode));
+ }
+ }
+ }
+
+ ++start;
+ }
+ }
+}
+
+// verify that case-folding does not un-FCD strings
+int32_t
+BasicNormalizerTest::countFoldFCDExceptions(uint32_t foldingOptions) {
+ UnicodeString s, fold, d;
+ UChar32 c;
+ int32_t count;
+ uint8_t cc, trailCC, foldCC, foldTrailCC;
+ UNormalizationCheckResult qcResult;
+ int8_t category;
+ UBool isNFD;
+ UErrorCode errorCode;
+
+ logln("Test if case folding may un-FCD a string (folding options %04lx)", foldingOptions);
+
+ count=0;
+ for(c=0; c<=0x10ffff; ++c) {
+ errorCode = U_ZERO_ERROR;
+ category=u_charType(c);
+ if(category==U_UNASSIGNED) {
+ continue; // skip unassigned code points
+ }
+ if(c==0xac00) {
+ c=0xd7a3; // skip Hangul - no case folding there
+ continue;
+ }
+ // skip Han blocks - no case folding there either
+ if(c==0x3400) {
+ c=0x4db5;
+ continue;
+ }
+ if(c==0x4e00) {
+ c=0x9fa5;
+ continue;
+ }
+ if(c==0x20000) {
+ c=0x2a6d6;
+ continue;
+ }
+
+ s.setTo(c);
+
+ // get leading and trailing cc for c
+ Normalizer::decompose(s, FALSE, 0, d, errorCode);
+ isNFD= s==d;
+ cc=u_getCombiningClass(d.char32At(0));
+ trailCC=u_getCombiningClass(d.char32At(d.length()-1));
+
+ // get leading and trailing cc for the case-folding of c
+ s.foldCase(foldingOptions);
+ Normalizer::decompose(s, FALSE, 0, d, errorCode);
+ foldCC=u_getCombiningClass(d.char32At(0));
+ foldTrailCC=u_getCombiningClass(d.char32At(d.length()-1));
+
+ qcResult=Normalizer::quickCheck(s, UNORM_FCD, errorCode);
+
+ if (U_FAILURE(errorCode)) {
+ ++count;
+ errln("U+%04lx: Failed with error %s", u_errorName(errorCode));
+ }
+
+ // bad:
+ // - character maps to empty string: adjacent characters may then need reordering
+ // - folding has different leading/trailing cc's, and they don't become just 0
+ // - folding itself is not FCD
+ if( qcResult!=UNORM_YES ||
+ s.isEmpty() ||
+ (cc!=foldCC && foldCC!=0) || (trailCC!=foldTrailCC && foldTrailCC!=0)
+ ) {
+ ++count;
+ errln("U+%04lx: case-folding may un-FCD a string (folding options %04lx)", c, foldingOptions);
+ errln(" cc %02x trailCC %02x foldCC(U+%04lx) %02x foldTrailCC(U+%04lx) %02x quickCheck(folded)=%d", cc, trailCC, d.char32At(0), foldCC, d.char32At(d.length()-1), foldTrailCC, qcResult);
+ continue;
+ }
+
+ // also bad:
+ // if a code point is in NFD but its case folding is not, then
+ // unorm_compare will also fail
+ if(isNFD && UNORM_YES!=Normalizer::quickCheck(s, UNORM_NFD, errorCode)) {
+ ++count;
+ errln("U+%04lx: case-folding un-NFDs this character (folding options %04lx)", c, foldingOptions);
+ }
+ }
+
+ logln("There are %ld code points for which case-folding may un-FCD a string (folding options %04lx)", count, foldingOptions);
+ return count;
+}
+
+void
+BasicNormalizerTest::FindFoldFCDExceptions() {
+ int32_t count;
+
+ count=countFoldFCDExceptions(0);
+ count+=countFoldFCDExceptions(U_FOLD_CASE_EXCLUDE_SPECIAL_I);
+ if(count>0) {
+ /*
+ * If case-folding un-FCDs any strings, then unorm_compare() must be
+ * re-implemented.
+ * It currently assumes that one can check for FCD then case-fold
+ * and then still have FCD strings for raw decomposition without reordering.
+ */
+ errln("error: There are %ld code points for which case-folding may un-FCD a string for all folding options.\n"
+ "See comment in BasicNormalizerTest::FindFoldFCDExceptions()!", count);
+ }
+}
+
+/*
+ * Hardcoded "NF* Skippable" sets, generated from
+ * Mark Davis' com.ibm.text.UCD.NFSkippable (see ICU4J CVS, module unicodetools).
+ * Run com.ibm.text.UCD.Main with the option NFSkippable.
+ *
+ * Must be updated for each Unicode version.
+ */
+static void
+initExpectedSkippables(UnicodeSet skipSets[UNORM_MODE_COUNT]) {
+ UErrorCode errorCode=U_ZERO_ERROR;
+
+ skipSets[UNORM_NFD].applyPattern(UnicodeString(
+ "[^\\u00C0-\\u00C5\\u00C7-\\u00CF\\u00D1-\\u00D6\\u00D9-\\u00DD"
+ "\\u00E0-\\u00E5\\u00E7-\\u00EF\\u00F1-\\u00F6\\u00F9-\\u00FD"
+ "\\u00FF-\\u010F\\u0112-\\u0125\\u0128-\\u0130\\u0134-\\u0137"
+ "\\u0139-\\u013E\\u0143-\\u0148\\u014C-\\u0151\\u0154-\\u0165"
+ "\\u0168-\\u017E\\u01A0\\u01A1\\u01AF\\u01B0\\u01CD-\\u01DC"
+ "\\u01DE-\\u01E3\\u01E6-\\u01F0\\u01F4\\u01F5\\u01F8-\\u021B"
+ "\\u021E\\u021F\\u0226-\\u0233\\u0300-\\u034E\\u0350-\\u036F"
+ "\\u0374\\u037E\\u0385-\\u038A\\u038C\\u038E-\\u0390\\u03AA-"
+ "\\u03B0\\u03CA-\\u03CE\\u03D3\\u03D4\\u0400\\u0401\\u0403\\u0407"
+ "\\u040C-\\u040E\\u0419\\u0439\\u0450\\u0451\\u0453\\u0457\\u045C"
+ "-\\u045E\\u0476\\u0477\\u0483-\\u0486\\u04C1\\u04C2\\u04D0-"
+ "\\u04D3\\u04D6\\u04D7\\u04DA-\\u04DF\\u04E2-\\u04E7\\u04EA-"
+ "\\u04F5\\u04F8\\u04F9\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4"
+ "\\u05C5\\u05C7\\u0610-\\u0615\\u0622-\\u0626\\u064B-\\u065E"
+ "\\u0670\\u06C0\\u06C2\\u06D3\\u06D6-\\u06DC\\u06DF-\\u06E4"
+ "\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07EB-"
+ "\\u07F3\\u0929\\u0931\\u0934\\u093C\\u094D\\u0951-\\u0954\\u0958"
+ "-\\u095F\\u09BC\\u09CB-\\u09CD\\u09DC\\u09DD\\u09DF\\u0A33"
+ "\\u0A36\\u0A3C\\u0A4D\\u0A59-\\u0A5B\\u0A5E\\u0ABC\\u0ACD\\u0B3C"
+ "\\u0B48\\u0B4B-\\u0B4D\\u0B5C\\u0B5D\\u0B94\\u0BCA-\\u0BCD"
+ "\\u0C48\\u0C4D\\u0C55\\u0C56\\u0CBC\\u0CC0\\u0CC7\\u0CC8\\u0CCA"
+ "\\u0CCB\\u0CCD\\u0D4A-\\u0D4D\\u0DCA\\u0DDA\\u0DDC-\\u0DDE"
+ "\\u0E38-\\u0E3A\\u0E48-\\u0E4B\\u0EB8\\u0EB9\\u0EC8-\\u0ECB"
+ "\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F43\\u0F4D\\u0F52\\u0F57"
+ "\\u0F5C\\u0F69\\u0F71-\\u0F76\\u0F78\\u0F7A-\\u0F7D\\u0F80-"
+ "\\u0F84\\u0F86\\u0F87\\u0F93\\u0F9D\\u0FA2\\u0FA7\\u0FAC\\u0FB9"
+ "\\u0FC6\\u1026\\u1037\\u1039\\u135F\\u1714\\u1734\\u17D2\\u17DD"
+ "\\u18A9\\u1939-\\u193B\\u1A17\\u1A18\\u1B06\\u1B08\\u1B0A\\u1B0C"
+ "\\u1B0E\\u1B12\\u1B34\\u1B3B\\u1B3D\\u1B40\\u1B41\\u1B43\\u1B44"
+ "\\u1B6B-\\u1B73\\u1DC0-\\u1DCA\\u1DFE-\\u1E99\\u1E9B\\u1EA0-"
+ "\\u1EF9\\u1F00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-"
+ "\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D"
+ "\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC1-\\u1FC4\\u1FC6-"
+ "\\u1FD3\\u1FD6-\\u1FDB\\u1FDD-\\u1FEF\\u1FF2-\\u1FF4\\u1FF6-"
+ "\\u1FFD\\u2000\\u2001\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20EF"
+ "\\u2126\\u212A\\u212B\\u219A\\u219B\\u21AE\\u21CD-\\u21CF\\u2204"
+ "\\u2209\\u220C\\u2224\\u2226\\u2241\\u2244\\u2247\\u2249\\u2260"
+ "\\u2262\\u226D-\\u2271\\u2274\\u2275\\u2278\\u2279\\u2280\\u2281"
+ "\\u2284\\u2285\\u2288\\u2289\\u22AC-\\u22AF\\u22E0-\\u22E3"
+ "\\u22EA-\\u22ED\\u2329\\u232A\\u2ADC\\u302A-\\u302F\\u304C"
+ "\\u304E\\u3050\\u3052\\u3054\\u3056\\u3058\\u305A\\u305C\\u305E"
+ "\\u3060\\u3062\\u3065\\u3067\\u3069\\u3070\\u3071\\u3073\\u3074"
+ "\\u3076\\u3077\\u3079\\u307A\\u307C\\u307D\\u3094\\u3099\\u309A"
+ "\\u309E\\u30AC\\u30AE\\u30B0\\u30B2\\u30B4\\u30B6\\u30B8\\u30BA"
+ "\\u30BC\\u30BE\\u30C0\\u30C2\\u30C5\\u30C7\\u30C9\\u30D0\\u30D1"
+ "\\u30D3\\u30D4\\u30D6\\u30D7\\u30D9\\u30DA\\u30DC\\u30DD\\u30F4"
+ "\\u30F7-\\u30FA\\u30FE\\uA806\\uAC00-\\uD7A3\\uF900-\\uFA0D"
+ "\\uFA10\\uFA12\\uFA15-\\uFA1E\\uFA20\\uFA22\\uFA25\\uFA26\\uFA2A"
+ "-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB1D-\\uFB1F\\uFB2A-"
+ "\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46"
+ "-\\uFB4E\\uFE20-\\uFE23\\U00010A0D\\U00010A0F\\U00010A38-\\U0001"
+ "0A3A\\U00010A3F\\U0001D15E-\\U0001D169\\U0001D16D-\\U0001D172"
+ "\\U0001D17B-\\U0001D182\\U0001D185-\\U0001D18B\\U0001D1AA-"
+ "\\U0001D1AD\\U0001D1BB-\\U0001D1C0\\U0001D242-\\U0001D244\\U0002"
+ "F800-\\U0002FA1D]"
+ , ""), errorCode);
+
+ skipSets[UNORM_NFC].applyPattern(UnicodeString(
+ "[^<->A-PR-Za-pr-z\\u00A8\\u00C0-\\u00CF\\u00D1-\\u00D6\\u00D8-"
+ "\\u00DD\\u00E0-\\u00EF\\u00F1-\\u00F6\\u00F8-\\u00FD\\u00FF-"
+ "\\u0103\\u0106-\\u010F\\u0112-\\u0117\\u011A-\\u0121\\u0124"
+ "\\u0125\\u0128-\\u012D\\u0130\\u0139\\u013A\\u013D\\u013E\\u0143"
+ "\\u0144\\u0147\\u0148\\u014C-\\u0151\\u0154\\u0155\\u0158-"
+ "\\u015D\\u0160\\u0161\\u0164\\u0165\\u0168-\\u0171\\u0174-"
+ "\\u017F\\u01A0\\u01A1\\u01AF\\u01B0\\u01B7\\u01CD-\\u01DC\\u01DE"
+ "-\\u01E1\\u01E6-\\u01EB\\u01F4\\u01F5\\u01F8-\\u01FB\\u0200-"
+ "\\u021B\\u021E\\u021F\\u0226-\\u0233\\u0292\\u0300-\\u034E"
+ "\\u0350-\\u036F\\u0374\\u037E\\u0387\\u0391\\u0395\\u0397\\u0399"
+ "\\u039F\\u03A1\\u03A5\\u03A9\\u03AC\\u03AE\\u03B1\\u03B5\\u03B7"
+ "\\u03B9\\u03BF\\u03C1\\u03C5\\u03C9-\\u03CB\\u03CE\\u03D2\\u0406"
+ "\\u0410\\u0413\\u0415-\\u0418\\u041A\\u041E\\u0423\\u0427\\u042B"
+ "\\u042D\\u0430\\u0433\\u0435-\\u0438\\u043A\\u043E\\u0443\\u0447"
+ "\\u044B\\u044D\\u0456\\u0474\\u0475\\u0483-\\u0486\\u04D8\\u04D9"
+ "\\u04E8\\u04E9\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5"
+ "\\u05C7\\u0610-\\u0615\\u0622\\u0623\\u0627\\u0648\\u064A-"
+ "\\u065E\\u0670\\u06C1\\u06D2\\u06D5-\\u06DC\\u06DF-\\u06E4"
+ "\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07EB-"
+ "\\u07F3\\u0928\\u0930\\u0933\\u093C\\u094D\\u0951-\\u0954\\u0958"
+ "-\\u095F\\u09BC\\u09BE\\u09C7\\u09CD\\u09D7\\u09DC\\u09DD\\u09DF"
+ "\\u0A33\\u0A36\\u0A3C\\u0A4D\\u0A59-\\u0A5B\\u0A5E\\u0ABC\\u0ACD"
+ "\\u0B3C\\u0B3E\\u0B47\\u0B4D\\u0B56\\u0B57\\u0B5C\\u0B5D\\u0B92"
+ "\\u0BBE\\u0BC6\\u0BC7\\u0BCD\\u0BD7\\u0C46\\u0C4D\\u0C55\\u0C56"
+ "\\u0CBC\\u0CBF\\u0CC2\\u0CC6\\u0CCA\\u0CCD\\u0CD5\\u0CD6\\u0D3E"
+ "\\u0D46\\u0D47\\u0D4D\\u0D57\\u0DCA\\u0DCF\\u0DD9\\u0DDC\\u0DDF"
+ "\\u0E38-\\u0E3A\\u0E48-\\u0E4B\\u0EB8\\u0EB9\\u0EC8-\\u0ECB"
+ "\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F43\\u0F4D\\u0F52\\u0F57"
+ "\\u0F5C\\u0F69\\u0F71-\\u0F76\\u0F78\\u0F7A-\\u0F7D\\u0F80-"
+ "\\u0F84\\u0F86\\u0F87\\u0F93\\u0F9D\\u0FA2\\u0FA7\\u0FAC\\u0FB9"
+ "\\u0FC6\\u1025\\u102E\\u1037\\u1039\\u1100-\\u1112\\u1161-"
+ "\\u1175\\u11A8-\\u11C2\\u135F\\u1714\\u1734\\u17D2\\u17DD\\u18A9"
+ "\\u1939-\\u193B\\u1A17\\u1A18\\u1B05\\u1B07\\u1B09\\u1B0B\\u1B0D"
+ "\\u1B11\\u1B34\\u1B35\\u1B3A\\u1B3C\\u1B3E\\u1B3F\\u1B42\\u1B44"
+ "\\u1B6B-\\u1B73\\u1DC0-\\u1DCA\\u1DFE-\\u1E03\\u1E0A-\\u1E0F"
+ "\\u1E12-\\u1E1B\\u1E20-\\u1E27\\u1E2A-\\u1E41\\u1E44-\\u1E53"
+ "\\u1E58-\\u1E7D\\u1E80-\\u1E87\\u1E8E-\\u1E91\\u1E96-\\u1E99"
+ "\\u1EA0-\\u1EF3\\u1EF6-\\u1EF9\\u1F00-\\u1F11\\u1F18\\u1F19"
+ "\\u1F20-\\u1F31\\u1F38\\u1F39\\u1F40\\u1F41\\u1F48\\u1F49\\u1F50"
+ "\\u1F51\\u1F59\\u1F60-\\u1F71\\u1F73-\\u1F75\\u1F77\\u1F79"
+ "\\u1F7B-\\u1F7D\\u1F80\\u1F81\\u1F88\\u1F89\\u1F90\\u1F91\\u1F98"
+ "\\u1F99\\u1FA0\\u1FA1\\u1FA8\\u1FA9\\u1FB3\\u1FB6\\u1FBB\\u1FBC"
+ "\\u1FBE\\u1FBF\\u1FC3\\u1FC6\\u1FC9\\u1FCB\\u1FCC\\u1FD3\\u1FDB"
+ "\\u1FE3\\u1FEB\\u1FEE\\u1FEF\\u1FF3\\u1FF6\\u1FF9\\u1FFB-\\u1FFE"
+ "\\u2000\\u2001\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20EF\\u2126"
+ "\\u212A\\u212B\\u2190\\u2192\\u2194\\u21D0\\u21D2\\u21D4\\u2203"
+ "\\u2208\\u220B\\u2223\\u2225\\u223C\\u2243\\u2245\\u2248\\u224D"
+ "\\u2261\\u2264\\u2265\\u2272\\u2273\\u2276\\u2277\\u227A-\\u227D"
+ "\\u2282\\u2283\\u2286\\u2287\\u2291\\u2292\\u22A2\\u22A8\\u22A9"
+ "\\u22AB\\u22B2-\\u22B5\\u2329\\u232A\\u2ADC\\u302A-\\u302F"
+ "\\u3046\\u304B\\u304D\\u304F\\u3051\\u3053\\u3055\\u3057\\u3059"
+ "\\u305B\\u305D\\u305F\\u3061\\u3064\\u3066\\u3068\\u306F\\u3072"
+ "\\u3075\\u3078\\u307B\\u3099\\u309A\\u309D\\u30A6\\u30AB\\u30AD"
+ "\\u30AF\\u30B1\\u30B3\\u30B5\\u30B7\\u30B9\\u30BB\\u30BD\\u30BF"
+ "\\u30C1\\u30C4\\u30C6\\u30C8\\u30CF\\u30D2\\u30D5\\u30D8\\u30DB"
+ "\\u30EF-\\u30F2\\u30FD\\uA806\\uAC00\\uAC1C\\uAC38\\uAC54\\uAC70"
+ "\\uAC8C\\uACA8\\uACC4\\uACE0\\uACFC\\uAD18\\uAD34\\uAD50\\uAD6C"
+ "\\uAD88\\uADA4\\uADC0\\uADDC\\uADF8\\uAE14\\uAE30\\uAE4C\\uAE68"
+ "\\uAE84\\uAEA0\\uAEBC\\uAED8\\uAEF4\\uAF10\\uAF2C\\uAF48\\uAF64"
+ "\\uAF80\\uAF9C\\uAFB8\\uAFD4\\uAFF0\\uB00C\\uB028\\uB044\\uB060"
+ "\\uB07C\\uB098\\uB0B4\\uB0D0\\uB0EC\\uB108\\uB124\\uB140\\uB15C"
+ "\\uB178\\uB194\\uB1B0\\uB1CC\\uB1E8\\uB204\\uB220\\uB23C\\uB258"
+ "\\uB274\\uB290\\uB2AC\\uB2C8\\uB2E4\\uB300\\uB31C\\uB338\\uB354"
+ "\\uB370\\uB38C\\uB3A8\\uB3C4\\uB3E0\\uB3FC\\uB418\\uB434\\uB450"
+ "\\uB46C\\uB488\\uB4A4\\uB4C0\\uB4DC\\uB4F8\\uB514\\uB530\\uB54C"
+ "\\uB568\\uB584\\uB5A0\\uB5BC\\uB5D8\\uB5F4\\uB610\\uB62C\\uB648"
+ "\\uB664\\uB680\\uB69C\\uB6B8\\uB6D4\\uB6F0\\uB70C\\uB728\\uB744"
+ "\\uB760\\uB77C\\uB798\\uB7B4\\uB7D0\\uB7EC\\uB808\\uB824\\uB840"
+ "\\uB85C\\uB878\\uB894\\uB8B0\\uB8CC\\uB8E8\\uB904\\uB920\\uB93C"
+ "\\uB958\\uB974\\uB990\\uB9AC\\uB9C8\\uB9E4\\uBA00\\uBA1C\\uBA38"
+ "\\uBA54\\uBA70\\uBA8C\\uBAA8\\uBAC4\\uBAE0\\uBAFC\\uBB18\\uBB34"
+ "\\uBB50\\uBB6C\\uBB88\\uBBA4\\uBBC0\\uBBDC\\uBBF8\\uBC14\\uBC30"
+ "\\uBC4C\\uBC68\\uBC84\\uBCA0\\uBCBC\\uBCD8\\uBCF4\\uBD10\\uBD2C"
+ "\\uBD48\\uBD64\\uBD80\\uBD9C\\uBDB8\\uBDD4\\uBDF0\\uBE0C\\uBE28"
+ "\\uBE44\\uBE60\\uBE7C\\uBE98\\uBEB4\\uBED0\\uBEEC\\uBF08\\uBF24"
+ "\\uBF40\\uBF5C\\uBF78\\uBF94\\uBFB0\\uBFCC\\uBFE8\\uC004\\uC020"
+ "\\uC03C\\uC058\\uC074\\uC090\\uC0AC\\uC0C8\\uC0E4\\uC100\\uC11C"
+ "\\uC138\\uC154\\uC170\\uC18C\\uC1A8\\uC1C4\\uC1E0\\uC1FC\\uC218"
+ "\\uC234\\uC250\\uC26C\\uC288\\uC2A4\\uC2C0\\uC2DC\\uC2F8\\uC314"
+ "\\uC330\\uC34C\\uC368\\uC384\\uC3A0\\uC3BC\\uC3D8\\uC3F4\\uC410"
+ "\\uC42C\\uC448\\uC464\\uC480\\uC49C\\uC4B8\\uC4D4\\uC4F0\\uC50C"
+ "\\uC528\\uC544\\uC560\\uC57C\\uC598\\uC5B4\\uC5D0\\uC5EC\\uC608"
+ "\\uC624\\uC640\\uC65C\\uC678\\uC694\\uC6B0\\uC6CC\\uC6E8\\uC704"
+ "\\uC720\\uC73C\\uC758\\uC774\\uC790\\uC7AC\\uC7C8\\uC7E4\\uC800"
+ "\\uC81C\\uC838\\uC854\\uC870\\uC88C\\uC8A8\\uC8C4\\uC8E0\\uC8FC"
+ "\\uC918\\uC934\\uC950\\uC96C\\uC988\\uC9A4\\uC9C0\\uC9DC\\uC9F8"
+ "\\uCA14\\uCA30\\uCA4C\\uCA68\\uCA84\\uCAA0\\uCABC\\uCAD8\\uCAF4"
+ "\\uCB10\\uCB2C\\uCB48\\uCB64\\uCB80\\uCB9C\\uCBB8\\uCBD4\\uCBF0"
+ "\\uCC0C\\uCC28\\uCC44\\uCC60\\uCC7C\\uCC98\\uCCB4\\uCCD0\\uCCEC"
+ "\\uCD08\\uCD24\\uCD40\\uCD5C\\uCD78\\uCD94\\uCDB0\\uCDCC\\uCDE8"
+ "\\uCE04\\uCE20\\uCE3C\\uCE58\\uCE74\\uCE90\\uCEAC\\uCEC8\\uCEE4"
+ "\\uCF00\\uCF1C\\uCF38\\uCF54\\uCF70\\uCF8C\\uCFA8\\uCFC4\\uCFE0"
+ "\\uCFFC\\uD018\\uD034\\uD050\\uD06C\\uD088\\uD0A4\\uD0C0\\uD0DC"
+ "\\uD0F8\\uD114\\uD130\\uD14C\\uD168\\uD184\\uD1A0\\uD1BC\\uD1D8"
+ "\\uD1F4\\uD210\\uD22C\\uD248\\uD264\\uD280\\uD29C\\uD2B8\\uD2D4"
+ "\\uD2F0\\uD30C\\uD328\\uD344\\uD360\\uD37C\\uD398\\uD3B4\\uD3D0"
+ "\\uD3EC\\uD408\\uD424\\uD440\\uD45C\\uD478\\uD494\\uD4B0\\uD4CC"
+ "\\uD4E8\\uD504\\uD520\\uD53C\\uD558\\uD574\\uD590\\uD5AC\\uD5C8"
+ "\\uD5E4\\uD600\\uD61C\\uD638\\uD654\\uD670\\uD68C\\uD6A8\\uD6C4"
+ "\\uD6E0\\uD6FC\\uD718\\uD734\\uD750\\uD76C\\uD788\\uF900-\\uFA0D"
+ "\\uFA10\\uFA12\\uFA15-\\uFA1E\\uFA20\\uFA22\\uFA25\\uFA26\\uFA2A"
+ "-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB1D-\\uFB1F\\uFB2A-"
+ "\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46"
+ "-\\uFB4E\\uFE20-\\uFE23\\U00010A0D\\U00010A0F\\U00010A38-\\U0001"
+ "0A3A\\U00010A3F\\U0001D15E-\\U0001D169\\U0001D16D-\\U0001D172"
+ "\\U0001D17B-\\U0001D182\\U0001D185-\\U0001D18B\\U0001D1AA-"
+ "\\U0001D1AD\\U0001D1BB-\\U0001D1C0\\U0001D242-\\U0001D244\\U0002"
+ "F800-\\U0002FA1D]"
+ , ""), errorCode);
+
+ skipSets[UNORM_NFKD].applyPattern(UnicodeString(
+ "[^\\u00A0\\u00A8\\u00AA\\u00AF\\u00B2-\\u00B5\\u00B8-\\u00BA"
+ "\\u00BC-\\u00BE\\u00C0-\\u00C5\\u00C7-\\u00CF\\u00D1-\\u00D6"
+ "\\u00D9-\\u00DD\\u00E0-\\u00E5\\u00E7-\\u00EF\\u00F1-\\u00F6"
+ "\\u00F9-\\u00FD\\u00FF-\\u010F\\u0112-\\u0125\\u0128-\\u0130"
+ "\\u0132-\\u0137\\u0139-\\u0140\\u0143-\\u0149\\u014C-\\u0151"
+ "\\u0154-\\u0165\\u0168-\\u017F\\u01A0\\u01A1\\u01AF\\u01B0"
+ "\\u01C4-\\u01DC\\u01DE-\\u01E3\\u01E6-\\u01F5\\u01F8-\\u021B"
+ "\\u021E\\u021F\\u0226-\\u0233\\u02B0-\\u02B8\\u02D8-\\u02DD"
+ "\\u02E0-\\u02E4\\u0300-\\u034E\\u0350-\\u036F\\u0374\\u037A"
+ "\\u037E\\u0384-\\u038A\\u038C\\u038E-\\u0390\\u03AA-\\u03B0"
+ "\\u03CA-\\u03CE\\u03D0-\\u03D6\\u03F0-\\u03F2\\u03F4\\u03F5"
+ "\\u03F9\\u0400\\u0401\\u0403\\u0407\\u040C-\\u040E\\u0419\\u0439"
+ "\\u0450\\u0451\\u0453\\u0457\\u045C-\\u045E\\u0476\\u0477\\u0483"
+ "-\\u0486\\u04C1\\u04C2\\u04D0-\\u04D3\\u04D6\\u04D7\\u04DA-"
+ "\\u04DF\\u04E2-\\u04E7\\u04EA-\\u04F5\\u04F8\\u04F9\\u0587"
+ "\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610"
+ "-\\u0615\\u0622-\\u0626\\u064B-\\u065E\\u0670\\u0675-\\u0678"
+ "\\u06C0\\u06C2\\u06D3\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7"
+ "\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07EB-\\u07F3"
+ "\\u0929\\u0931\\u0934\\u093C\\u094D\\u0951-\\u0954\\u0958-"
+ "\\u095F\\u09BC\\u09CB-\\u09CD\\u09DC\\u09DD\\u09DF\\u0A33\\u0A36"
+ "\\u0A3C\\u0A4D\\u0A59-\\u0A5B\\u0A5E\\u0ABC\\u0ACD\\u0B3C\\u0B48"
+ "\\u0B4B-\\u0B4D\\u0B5C\\u0B5D\\u0B94\\u0BCA-\\u0BCD\\u0C48"
+ "\\u0C4D\\u0C55\\u0C56\\u0CBC\\u0CC0\\u0CC7\\u0CC8\\u0CCA\\u0CCB"
+ "\\u0CCD\\u0D4A-\\u0D4D\\u0DCA\\u0DDA\\u0DDC-\\u0DDE\\u0E33"
+ "\\u0E38-\\u0E3A\\u0E48-\\u0E4B\\u0EB3\\u0EB8\\u0EB9\\u0EC8-"
+ "\\u0ECB\\u0EDC\\u0EDD\\u0F0C\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39"
+ "\\u0F43\\u0F4D\\u0F52\\u0F57\\u0F5C\\u0F69\\u0F71-\\u0F7D\\u0F80"
+ "-\\u0F84\\u0F86\\u0F87\\u0F93\\u0F9D\\u0FA2\\u0FA7\\u0FAC\\u0FB9"
+ "\\u0FC6\\u1026\\u1037\\u1039\\u10FC\\u135F\\u1714\\u1734\\u17D2"
+ "\\u17DD\\u18A9\\u1939-\\u193B\\u1A17\\u1A18\\u1B06\\u1B08\\u1B0A"
+ "\\u1B0C\\u1B0E\\u1B12\\u1B34\\u1B3B\\u1B3D\\u1B40\\u1B41\\u1B43"
+ "\\u1B44\\u1B6B-\\u1B73\\u1D2C-\\u1D2E\\u1D30-\\u1D3A\\u1D3C-"
+ "\\u1D4D\\u1D4F-\\u1D6A\\u1D78\\u1D9B-\\u1DCA\\u1DFE-\\u1E9B"
+ "\\u1EA0-\\u1EF9\\u1F00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45"
+ "\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-"
+ "\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FC4\\u1FC6-\\u1FD3\\u1FD6-"
+ "\\u1FDB\\u1FDD-\\u1FEF\\u1FF2-\\u1FF4\\u1FF6-\\u1FFE\\u2000-"
+ "\\u200A\\u2011\\u2017\\u2024-\\u2026\\u202F\\u2033\\u2034\\u2036"
+ "\\u2037\\u203C\\u203E\\u2047-\\u2049\\u2057\\u205F\\u2070\\u2071"
+ "\\u2074-\\u208E\\u2090-\\u2094\\u20A8\\u20D0-\\u20DC\\u20E1"
+ "\\u20E5-\\u20EF\\u2100-\\u2103\\u2105-\\u2107\\u2109-\\u2113"
+ "\\u2115\\u2116\\u2119-\\u211D\\u2120-\\u2122\\u2124\\u2126"
+ "\\u2128\\u212A-\\u212D\\u212F-\\u2131\\u2133-\\u2139\\u213B-"
+ "\\u2140\\u2145-\\u2149\\u2153-\\u217F\\u219A\\u219B\\u21AE"
+ "\\u21CD-\\u21CF\\u2204\\u2209\\u220C\\u2224\\u2226\\u222C\\u222D"
+ "\\u222F\\u2230\\u2241\\u2244\\u2247\\u2249\\u2260\\u2262\\u226D-"
+ "\\u2271\\u2274\\u2275\\u2278\\u2279\\u2280\\u2281\\u2284\\u2285"
+ "\\u2288\\u2289\\u22AC-\\u22AF\\u22E0-\\u22E3\\u22EA-\\u22ED"
+ "\\u2329\\u232A\\u2460-\\u24EA\\u2A0C\\u2A74-\\u2A76\\u2ADC"
+ "\\u2D6F\\u2E9F\\u2EF3\\u2F00-\\u2FD5\\u3000\\u302A-\\u302F"
+ "\\u3036\\u3038-\\u303A\\u304C\\u304E\\u3050\\u3052\\u3054\\u3056"
+ "\\u3058\\u305A\\u305C\\u305E\\u3060\\u3062\\u3065\\u3067\\u3069"
+ "\\u3070\\u3071\\u3073\\u3074\\u3076\\u3077\\u3079\\u307A\\u307C"
+ "\\u307D\\u3094\\u3099-\\u309C\\u309E\\u309F\\u30AC\\u30AE\\u30B0"
+ "\\u30B2\\u30B4\\u30B6\\u30B8\\u30BA\\u30BC\\u30BE\\u30C0\\u30C2"
+ "\\u30C5\\u30C7\\u30C9\\u30D0\\u30D1\\u30D3\\u30D4\\u30D6\\u30D7"
+ "\\u30D9\\u30DA\\u30DC\\u30DD\\u30F4\\u30F7-\\u30FA\\u30FE\\u30FF"
+ "\\u3131-\\u318E\\u3192-\\u319F\\u3200-\\u321E\\u3220-\\u3243"
+ "\\u3250-\\u327E\\u3280-\\u32FE\\u3300-\\u33FF\\uA806\\uAC00-"
+ "\\uD7A3\\uF900-\\uFA0D\\uFA10\\uFA12\\uFA15-\\uFA1E\\uFA20"
+ "\\uFA22\\uFA25\\uFA26\\uFA2A-\\uFA2D\\uFA30-\\uFA6A\\uFA70-"
+ "\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D-\\uFB36\\uFB38-"
+ "\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3"
+ "-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFC\\uFE10-"
+ "\\uFE19\\uFE20-\\uFE23\\uFE30-\\uFE44\\uFE47-\\uFE52\\uFE54-"
+ "\\uFE66\\uFE68-\\uFE6B\\uFE70-\\uFE72\\uFE74\\uFE76-\\uFEFC"
+ "\\uFF01-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7"
+ "\\uFFDA-\\uFFDC\\uFFE0-\\uFFE6\\uFFE8-\\uFFEE\\U00010A0D\\U00010"
+ "A0F\\U00010A38-\\U00010A3A\\U00010A3F\\U0001D15E-\\U0001D169"
+ "\\U0001D16D-\\U0001D172\\U0001D17B-\\U0001D182\\U0001D185-"
+ "\\U0001D18B\\U0001D1AA-\\U0001D1AD\\U0001D1BB-\\U0001D1C0\\U0001"
+ "D242-\\U0001D244\\U0001D400-\\U0001D454\\U0001D456-\\U0001D49C"
+ "\\U0001D49E\\U0001D49F\\U0001D4A2\\U0001D4A5\\U0001D4A6\\U0001D4"
+ "A9-\\U0001D4AC\\U0001D4AE-\\U0001D4B9\\U0001D4BB\\U0001D4BD-"
+ "\\U0001D4C3\\U0001D4C5-\\U0001D505\\U0001D507-\\U0001D50A\\U0001"
+ "D50D-\\U0001D514\\U0001D516-\\U0001D51C\\U0001D51E-\\U0001D539"
+ "\\U0001D53B-\\U0001D53E\\U0001D540-\\U0001D544\\U0001D546\\U0001"
+ "D54A-\\U0001D550\\U0001D552-\\U0001D6A5\\U0001D6A8-\\U0001D7CB"
+ "\\U0001D7CE-\\U0001D7FF\\U0002F800-\\U0002FA1D]"
+ , ""), errorCode);
+
+ skipSets[UNORM_NFKC].applyPattern(UnicodeString(
+ "[^<->A-PR-Za-pr-z\\u00A0\\u00A8\\u00AA\\u00AF\\u00B2-\\u00B5"
+ "\\u00B8-\\u00BA\\u00BC-\\u00BE\\u00C0-\\u00CF\\u00D1-\\u00D6"
+ "\\u00D8-\\u00DD\\u00E0-\\u00EF\\u00F1-\\u00F6\\u00F8-\\u00FD"
+ "\\u00FF-\\u0103\\u0106-\\u010F\\u0112-\\u0117\\u011A-\\u0121"
+ "\\u0124\\u0125\\u0128-\\u012D\\u0130\\u0132\\u0133\\u0139\\u013A"
+ "\\u013D-\\u0140\\u0143\\u0144\\u0147-\\u0149\\u014C-\\u0151"
+ "\\u0154\\u0155\\u0158-\\u015D\\u0160\\u0161\\u0164\\u0165\\u0168"
+ "-\\u0171\\u0174-\\u017F\\u01A0\\u01A1\\u01AF\\u01B0\\u01B7"
+ "\\u01C4-\\u01DC\\u01DE-\\u01E1\\u01E6-\\u01EB\\u01F1-\\u01F5"
+ "\\u01F8-\\u01FB\\u0200-\\u021B\\u021E\\u021F\\u0226-\\u0233"
+ "\\u0292\\u02B0-\\u02B8\\u02D8-\\u02DD\\u02E0-\\u02E4\\u0300-"
+ "\\u034E\\u0350-\\u036F\\u0374\\u037A\\u037E\\u0384\\u0385\\u0387"
+ "\\u0391\\u0395\\u0397\\u0399\\u039F\\u03A1\\u03A5\\u03A9\\u03AC"
+ "\\u03AE\\u03B1\\u03B5\\u03B7\\u03B9\\u03BF\\u03C1\\u03C5\\u03C9-"
+ "\\u03CB\\u03CE\\u03D0-\\u03D6\\u03F0-\\u03F2\\u03F4\\u03F5"
+ "\\u03F9\\u0406\\u0410\\u0413\\u0415-\\u0418\\u041A\\u041E\\u0423"
+ "\\u0427\\u042B\\u042D\\u0430\\u0433\\u0435-\\u0438\\u043A\\u043E"
+ "\\u0443\\u0447\\u044B\\u044D\\u0456\\u0474\\u0475\\u0483-\\u0486"
+ "\\u04D8\\u04D9\\u04E8\\u04E9\\u0587\\u0591-\\u05BD\\u05BF\\u05C1"
+ "\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u0615\\u0622\\u0623\\u0627"
+ "\\u0648\\u064A-\\u065E\\u0670\\u0675-\\u0678\\u06C1\\u06D2"
+ "\\u06D5-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED"
+ "\\u0711\\u0730-\\u074A\\u07EB-\\u07F3\\u0928\\u0930\\u0933"
+ "\\u093C\\u094D\\u0951-\\u0954\\u0958-\\u095F\\u09BC\\u09BE"
+ "\\u09C7\\u09CD\\u09D7\\u09DC\\u09DD\\u09DF\\u0A33\\u0A36\\u0A3C"
+ "\\u0A4D\\u0A59-\\u0A5B\\u0A5E\\u0ABC\\u0ACD\\u0B3C\\u0B3E\\u0B47"
+ "\\u0B4D\\u0B56\\u0B57\\u0B5C\\u0B5D\\u0B92\\u0BBE\\u0BC6\\u0BC7"
+ "\\u0BCD\\u0BD7\\u0C46\\u0C4D\\u0C55\\u0C56\\u0CBC\\u0CBF\\u0CC2"
+ "\\u0CC6\\u0CCA\\u0CCD\\u0CD5\\u0CD6\\u0D3E\\u0D46\\u0D47\\u0D4D"
+ "\\u0D57\\u0DCA\\u0DCF\\u0DD9\\u0DDC\\u0DDF\\u0E33\\u0E38-\\u0E3A"
+ "\\u0E48-\\u0E4B\\u0EB3\\u0EB8\\u0EB9\\u0EC8-\\u0ECB\\u0EDC"
+ "\\u0EDD\\u0F0C\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F43\\u0F4D"
+ "\\u0F52\\u0F57\\u0F5C\\u0F69\\u0F71-\\u0F7D\\u0F80-\\u0F84"
+ "\\u0F86\\u0F87\\u0F93\\u0F9D\\u0FA2\\u0FA7\\u0FAC\\u0FB9\\u0FC6"
+ "\\u1025\\u102E\\u1037\\u1039\\u10FC\\u1100-\\u1112\\u1161-"
+ "\\u1175\\u11A8-\\u11C2\\u135F\\u1714\\u1734\\u17D2\\u17DD\\u18A9"
+ "\\u1939-\\u193B\\u1A17\\u1A18\\u1B05\\u1B07\\u1B09\\u1B0B\\u1B0D"
+ "\\u1B11\\u1B34\\u1B35\\u1B3A\\u1B3C\\u1B3E\\u1B3F\\u1B42\\u1B44"
+ "\\u1B6B-\\u1B73\\u1D2C-\\u1D2E\\u1D30-\\u1D3A\\u1D3C-\\u1D4D"
+ "\\u1D4F-\\u1D6A\\u1D78\\u1D9B-\\u1DCA\\u1DFE-\\u1E03\\u1E0A-"
+ "\\u1E0F\\u1E12-\\u1E1B\\u1E20-\\u1E27\\u1E2A-\\u1E41\\u1E44-"
+ "\\u1E53\\u1E58-\\u1E7D\\u1E80-\\u1E87\\u1E8E-\\u1E91\\u1E96-"
+ "\\u1E9B\\u1EA0-\\u1EF3\\u1EF6-\\u1EF9\\u1F00-\\u1F11\\u1F18"
+ "\\u1F19\\u1F20-\\u1F31\\u1F38\\u1F39\\u1F40\\u1F41\\u1F48\\u1F49"
+ "\\u1F50\\u1F51\\u1F59\\u1F60-\\u1F71\\u1F73-\\u1F75\\u1F77"
+ "\\u1F79\\u1F7B-\\u1F7D\\u1F80\\u1F81\\u1F88\\u1F89\\u1F90\\u1F91"
+ "\\u1F98\\u1F99\\u1FA0\\u1FA1\\u1FA8\\u1FA9\\u1FB3\\u1FB6\\u1FBB-"
+ "\\u1FC1\\u1FC3\\u1FC6\\u1FC9\\u1FCB-\\u1FCF\\u1FD3\\u1FDB\\u1FDD"
+ "-\\u1FDF\\u1FE3\\u1FEB\\u1FED-\\u1FEF\\u1FF3\\u1FF6\\u1FF9"
+ "\\u1FFB-\\u1FFE\\u2000-\\u200A\\u2011\\u2017\\u2024-\\u2026"
+ "\\u202F\\u2033\\u2034\\u2036\\u2037\\u203C\\u203E\\u2047-\\u2049"
+ "\\u2057\\u205F\\u2070\\u2071\\u2074-\\u208E\\u2090-\\u2094"
+ "\\u20A8\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20EF\\u2100-\\u2103"
+ "\\u2105-\\u2107\\u2109-\\u2113\\u2115\\u2116\\u2119-\\u211D"
+ "\\u2120-\\u2122\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-"
+ "\\u2131\\u2133-\\u2139\\u213B-\\u2140\\u2145-\\u2149\\u2153-"
+ "\\u217F\\u2190\\u2192\\u2194\\u21D0\\u21D2\\u21D4\\u2203\\u2208"
+ "\\u220B\\u2223\\u2225\\u222C\\u222D\\u222F\\u2230\\u223C\\u2243"
+ "\\u2245\\u2248\\u224D\\u2261\\u2264\\u2265\\u2272\\u2273\\u2276"
+ "\\u2277\\u227A-\\u227D\\u2282\\u2283\\u2286\\u2287\\u2291\\u2292"
+ "\\u22A2\\u22A8\\u22A9\\u22AB\\u22B2-\\u22B5\\u2329\\u232A\\u2460"
+ "-\\u24EA\\u2A0C\\u2A74-\\u2A76\\u2ADC\\u2D6F\\u2E9F\\u2EF3"
+ "\\u2F00-\\u2FD5\\u3000\\u302A-\\u302F\\u3036\\u3038-\\u303A"
+ "\\u3046\\u304B\\u304D\\u304F\\u3051\\u3053\\u3055\\u3057\\u3059"
+ "\\u305B\\u305D\\u305F\\u3061\\u3064\\u3066\\u3068\\u306F\\u3072"
+ "\\u3075\\u3078\\u307B\\u3099-\\u309D\\u309F\\u30A6\\u30AB\\u30AD"
+ "\\u30AF\\u30B1\\u30B3\\u30B5\\u30B7\\u30B9\\u30BB\\u30BD\\u30BF"
+ "\\u30C1\\u30C4\\u30C6\\u30C8\\u30CF\\u30D2\\u30D5\\u30D8\\u30DB"
+ "\\u30EF-\\u30F2\\u30FD\\u30FF\\u3131-\\u318E\\u3192-\\u319F"
+ "\\u3200-\\u321E\\u3220-\\u3243\\u3250-\\u327E\\u3280-\\u32FE"
+ "\\u3300-\\u33FF\\uA806\\uAC00\\uAC1C\\uAC38\\uAC54\\uAC70\\uAC8C"
+ "\\uACA8\\uACC4\\uACE0\\uACFC\\uAD18\\uAD34\\uAD50\\uAD6C\\uAD88"
+ "\\uADA4\\uADC0\\uADDC\\uADF8\\uAE14\\uAE30\\uAE4C\\uAE68\\uAE84"
+ "\\uAEA0\\uAEBC\\uAED8\\uAEF4\\uAF10\\uAF2C\\uAF48\\uAF64\\uAF80"
+ "\\uAF9C\\uAFB8\\uAFD4\\uAFF0\\uB00C\\uB028\\uB044\\uB060\\uB07C"
+ "\\uB098\\uB0B4\\uB0D0\\uB0EC\\uB108\\uB124\\uB140\\uB15C\\uB178"
+ "\\uB194\\uB1B0\\uB1CC\\uB1E8\\uB204\\uB220\\uB23C\\uB258\\uB274"
+ "\\uB290\\uB2AC\\uB2C8\\uB2E4\\uB300\\uB31C\\uB338\\uB354\\uB370"
+ "\\uB38C\\uB3A8\\uB3C4\\uB3E0\\uB3FC\\uB418\\uB434\\uB450\\uB46C"
+ "\\uB488\\uB4A4\\uB4C0\\uB4DC\\uB4F8\\uB514\\uB530\\uB54C\\uB568"
+ "\\uB584\\uB5A0\\uB5BC\\uB5D8\\uB5F4\\uB610\\uB62C\\uB648\\uB664"
+ "\\uB680\\uB69C\\uB6B8\\uB6D4\\uB6F0\\uB70C\\uB728\\uB744\\uB760"
+ "\\uB77C\\uB798\\uB7B4\\uB7D0\\uB7EC\\uB808\\uB824\\uB840\\uB85C"
+ "\\uB878\\uB894\\uB8B0\\uB8CC\\uB8E8\\uB904\\uB920\\uB93C\\uB958"
+ "\\uB974\\uB990\\uB9AC\\uB9C8\\uB9E4\\uBA00\\uBA1C\\uBA38\\uBA54"
+ "\\uBA70\\uBA8C\\uBAA8\\uBAC4\\uBAE0\\uBAFC\\uBB18\\uBB34\\uBB50"
+ "\\uBB6C\\uBB88\\uBBA4\\uBBC0\\uBBDC\\uBBF8\\uBC14\\uBC30\\uBC4C"
+ "\\uBC68\\uBC84\\uBCA0\\uBCBC\\uBCD8\\uBCF4\\uBD10\\uBD2C\\uBD48"
+ "\\uBD64\\uBD80\\uBD9C\\uBDB8\\uBDD4\\uBDF0\\uBE0C\\uBE28\\uBE44"
+ "\\uBE60\\uBE7C\\uBE98\\uBEB4\\uBED0\\uBEEC\\uBF08\\uBF24\\uBF40"
+ "\\uBF5C\\uBF78\\uBF94\\uBFB0\\uBFCC\\uBFE8\\uC004\\uC020\\uC03C"
+ "\\uC058\\uC074\\uC090\\uC0AC\\uC0C8\\uC0E4\\uC100\\uC11C\\uC138"
+ "\\uC154\\uC170\\uC18C\\uC1A8\\uC1C4\\uC1E0\\uC1FC\\uC218\\uC234"
+ "\\uC250\\uC26C\\uC288\\uC2A4\\uC2C0\\uC2DC\\uC2F8\\uC314\\uC330"
+ "\\uC34C\\uC368\\uC384\\uC3A0\\uC3BC\\uC3D8\\uC3F4\\uC410\\uC42C"
+ "\\uC448\\uC464\\uC480\\uC49C\\uC4B8\\uC4D4\\uC4F0\\uC50C\\uC528"
+ "\\uC544\\uC560\\uC57C\\uC598\\uC5B4\\uC5D0\\uC5EC\\uC608\\uC624"
+ "\\uC640\\uC65C\\uC678\\uC694\\uC6B0\\uC6CC\\uC6E8\\uC704\\uC720"
+ "\\uC73C\\uC758\\uC774\\uC790\\uC7AC\\uC7C8\\uC7E4\\uC800\\uC81C"
+ "\\uC838\\uC854\\uC870\\uC88C\\uC8A8\\uC8C4\\uC8E0\\uC8FC\\uC918"
+ "\\uC934\\uC950\\uC96C\\uC988\\uC9A4\\uC9C0\\uC9DC\\uC9F8\\uCA14"
+ "\\uCA30\\uCA4C\\uCA68\\uCA84\\uCAA0\\uCABC\\uCAD8\\uCAF4\\uCB10"
+ "\\uCB2C\\uCB48\\uCB64\\uCB80\\uCB9C\\uCBB8\\uCBD4\\uCBF0\\uCC0C"
+ "\\uCC28\\uCC44\\uCC60\\uCC7C\\uCC98\\uCCB4\\uCCD0\\uCCEC\\uCD08"
+ "\\uCD24\\uCD40\\uCD5C\\uCD78\\uCD94\\uCDB0\\uCDCC\\uCDE8\\uCE04"
+ "\\uCE20\\uCE3C\\uCE58\\uCE74\\uCE90\\uCEAC\\uCEC8\\uCEE4\\uCF00"
+ "\\uCF1C\\uCF38\\uCF54\\uCF70\\uCF8C\\uCFA8\\uCFC4\\uCFE0\\uCFFC"
+ "\\uD018\\uD034\\uD050\\uD06C\\uD088\\uD0A4\\uD0C0\\uD0DC\\uD0F8"
+ "\\uD114\\uD130\\uD14C\\uD168\\uD184\\uD1A0\\uD1BC\\uD1D8\\uD1F4"
+ "\\uD210\\uD22C\\uD248\\uD264\\uD280\\uD29C\\uD2B8\\uD2D4\\uD2F0"
+ "\\uD30C\\uD328\\uD344\\uD360\\uD37C\\uD398\\uD3B4\\uD3D0\\uD3EC"
+ "\\uD408\\uD424\\uD440\\uD45C\\uD478\\uD494\\uD4B0\\uD4CC\\uD4E8"
+ "\\uD504\\uD520\\uD53C\\uD558\\uD574\\uD590\\uD5AC\\uD5C8\\uD5E4"
+ "\\uD600\\uD61C\\uD638\\uD654\\uD670\\uD68C\\uD6A8\\uD6C4\\uD6E0"
+ "\\uD6FC\\uD718\\uD734\\uD750\\uD76C\\uD788\\uF900-\\uFA0D\\uFA10"
+ "\\uFA12\\uFA15-\\uFA1E\\uFA20\\uFA22\\uFA25\\uFA26\\uFA2A-"
+ "\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-"
+ "\\uFB17\\uFB1D-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41"
+ "\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F"
+ "\\uFD92-\\uFDC7\\uFDF0-\\uFDFC\\uFE10-\\uFE19\\uFE20-\\uFE23"
+ "\\uFE30-\\uFE44\\uFE47-\\uFE52\\uFE54-\\uFE66\\uFE68-\\uFE6B"
+ "\\uFE70-\\uFE72\\uFE74\\uFE76-\\uFEFC\\uFF01-\\uFFBE\\uFFC2-"
+ "\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC\\uFFE0-"
+ "\\uFFE6\\uFFE8-\\uFFEE\\U00010A0D\\U00010A0F\\U00010A38-\\U00010"
+ "A3A\\U00010A3F\\U0001D15E-\\U0001D169\\U0001D16D-\\U0001D172"
+ "\\U0001D17B-\\U0001D182\\U0001D185-\\U0001D18B\\U0001D1AA-"
+ "\\U0001D1AD\\U0001D1BB-\\U0001D1C0\\U0001D242-\\U0001D244\\U0001"
+ "D400-\\U0001D454\\U0001D456-\\U0001D49C\\U0001D49E\\U0001D49F"
+ "\\U0001D4A2\\U0001D4A5\\U0001D4A6\\U0001D4A9-\\U0001D4AC\\U0001D"
+ "4AE-\\U0001D4B9\\U0001D4BB\\U0001D4BD-\\U0001D4C3\\U0001D4C5-"
+ "\\U0001D505\\U0001D507-\\U0001D50A\\U0001D50D-\\U0001D514\\U0001"
+ "D516-\\U0001D51C\\U0001D51E-\\U0001D539\\U0001D53B-\\U0001D53E"
+ "\\U0001D540-\\U0001D544\\U0001D546\\U0001D54A-\\U0001D550\\U0001"
+ "D552-\\U0001D6A5\\U0001D6A8-\\U0001D7CB\\U0001D7CE-\\U0001D7FF"
+ "\\U0002F800-\\U0002FA1D]"
+ , ""), errorCode);
+}
+
+U_CDECL_BEGIN
+
+// USetAdder implementation
+// Does not use uset.h to reduce code dependencies
+static void U_CALLCONV
+_set_add(USet *set, UChar32 c) {
+ uset_add(set, c);
+}
+
+static void U_CALLCONV
+_set_addRange(USet *set, UChar32 start, UChar32 end) {
+ uset_addRange(set, start, end);
+}
+
+static void U_CALLCONV
+_set_addString(USet *set, const UChar *str, int32_t length) {
+ uset_addString(set, str, length);
+}
+
+U_CDECL_END
+
+void
+BasicNormalizerTest::TestSkippable() {
+ UnicodeSet starts, diff, skipSets[UNORM_MODE_COUNT], expectSets[UNORM_MODE_COUNT];
+ UnicodeSet *startsPtr = &starts;
+ UnicodeString s, pattern;
+ UChar32 start, limit, rangeStart, rangeEnd;
+ int32_t i, range, count;
+
+ UErrorCode status;
+
+ /* build NF*Skippable sets from runtime data */
+ status=U_ZERO_ERROR;
+ USetAdder sa = {
+ (USet *)startsPtr,
+ _set_add,
+ _set_addRange,
+ _set_addString,
+ NULL // don't need remove()
+ };
+ unorm_addPropertyStarts(&sa, &status);
+ if(U_FAILURE(status)) {
+ errln("unable to load normalization data for unorm_addPropertyStarts(() - %s\n", u_errorName(status));
+ return;
+ }
+ count=starts.getRangeCount();
+
+ start=limit=0;
+ rangeStart=rangeEnd=0;
+ range=0;
+ for(;;) {
+ if(start<limit) {
+ /* get properties for start and apply them to [start..limit[ */
+ if(unorm_isNFSkippable(start, UNORM_NFD)) {
+ skipSets[UNORM_NFD].add(start, limit-1);
+ }
+ if(unorm_isNFSkippable(start, UNORM_NFKD)) {
+ skipSets[UNORM_NFKD].add(start, limit-1);
+ }
+ if(unorm_isNFSkippable(start, UNORM_NFC)) {
+ skipSets[UNORM_NFC].add(start, limit-1);
+ }
+ if(unorm_isNFSkippable(start, UNORM_NFKC)) {
+ skipSets[UNORM_NFKC].add(start, limit-1);
+ }
+ }
+
+ /* go to next range of same properties */
+ start=limit;
+ if(++limit>rangeEnd) {
+ if(range<count) {
+ limit=rangeStart=starts.getRangeStart(range);
+ rangeEnd=starts.getRangeEnd(range);
+ ++range;
+ } else if(range==count) {
+ /* additional range to complete the Unicode code space */
+ limit=rangeStart=rangeEnd=0x110000;
+ ++range;
+ } else {
+ break;
+ }
+ }
+ }
+
+ /* get expected sets from hardcoded patterns */
+ initExpectedSkippables(expectSets);
+
+ for(i=UNORM_NONE; i<UNORM_MODE_COUNT; ++i) {
+ if(skipSets[i]!=expectSets[i]) {
+ errln("error: TestSkippable skipSets[%d]!=expectedSets[%d]\n"
+ "may need to update hardcoded UnicodeSet patterns in\n"
+ "tstnorm.cpp/initExpectedSkippables(),\n"
+ "see ICU4J - unicodetools.com.ibm.text.UCD.NFSkippable\n",
+ i, i);
+
+ s=UNICODE_STRING_SIMPLE("skip-expect=");
+ (diff=skipSets[i]).removeAll(expectSets[i]).toPattern(pattern, TRUE);
+ s.append(pattern);
+
+ pattern.remove();
+ s.append(UNICODE_STRING_SIMPLE("\n\nexpect-skip="));
+ (diff=expectSets[i]).removeAll(skipSets[i]).toPattern(pattern, TRUE);
+ s.append(pattern);
+ s.append(UNICODE_STRING_SIMPLE("\n\n"));
+
+ errln(s);
+ }
+ }
+}
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tstnorm.h b/Build/source/libs/icu/icu-xetex/test/intltest/tstnorm.h
new file mode 100644
index 00000000000..b77efd6bf2a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tstnorm.h
@@ -0,0 +1,84 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * Normalizer basic tests
+ */
+
+#ifndef _TSTNORM
+#define _TSTNORM
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#include "unicode/normlzr.h"
+#include "intltest.h"
+
+class BasicNormalizerTest : public IntlTest {
+public:
+ BasicNormalizerTest();
+ virtual ~BasicNormalizerTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ void TestHangulCompose(void);
+ void TestHangulDecomp(void);
+ void TestPrevious(void);
+ void TestDecomp(void);
+ void TestCompatDecomp(void);
+ void TestCanonCompose(void);
+ void TestCompatCompose(void);
+ void TestTibetan(void);
+ void TestCompositionExclusion(void);
+ void TestZeroIndex(void);
+ void TestVerisign(void);
+ void TestPreviousNext(void);
+ void TestNormalizerAPI(void);
+ void TestConcatenate(void);
+ void TestCompare(void);
+ void FindFoldFCDExceptions();
+ void TestSkippable();
+
+private:
+ UnicodeString canonTests[24][3];
+ UnicodeString compatTests[11][3];
+ UnicodeString hangulCanon[2][3];
+
+ void
+ TestPreviousNext(const UChar *src, int32_t srcLength,
+ const UChar32 *expext, int32_t expectLength,
+ const int32_t *expectIndex, // its length=expectLength+1
+ int32_t srcMiddle, int32_t expectMiddle,
+ const char *moves,
+ UNormalizationMode mode,
+ const char *name);
+
+ int32_t countFoldFCDExceptions(uint32_t foldingOptions);
+
+ //------------------------------------------------------------------------
+ // Internal utilities
+ //
+ void backAndForth(Normalizer* iter, const UnicodeString& input);
+
+ void staticTest(UNormalizationMode mode, int options,
+ UnicodeString tests[][3], int length, int outCol);
+
+ void iterateTest(Normalizer* iter, UnicodeString tests[][3], int length, int outCol);
+
+ void assertEqual(const UnicodeString& input,
+ const UnicodeString& expected,
+ Normalizer* result,
+ const UnicodeString& errPrefix);
+
+ static UnicodeString hex(UChar ch);
+ static UnicodeString hex(const UnicodeString& str);
+
+};
+
+#endif /* #if !UCONFIG_NO_NORMALIZATION */
+
+#endif // _TSTNORM
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tstnrapi.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tstnrapi.cpp
new file mode 100644
index 00000000000..6499fefe2d0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tstnrapi.cpp
@@ -0,0 +1,187 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+#include "unicode/uchar.h"
+#include "unicode/normlzr.h"
+#include "unicode/uniset.h"
+#include "unicode/usetiter.h"
+#include "unicode/schriter.h"
+#include "unormimp.h"
+#include "tstnorm.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+static UErrorCode status = U_ZERO_ERROR;
+
+// test APIs that are not otherwise used - improve test coverage
+void
+BasicNormalizerTest::TestNormalizerAPI() {
+ // instantiate a Normalizer from a CharacterIterator
+ UnicodeString s=UnicodeString("a\\u0308\\uac00\\U0002f800", "").unescape();
+ s.append(s); // make s a bit longer and more interesting
+ StringCharacterIterator iter(s);
+ Normalizer norm(iter, UNORM_NFC);
+ if(norm.next()!=0xe4) {
+ errln("error in Normalizer(CharacterIterator).next()");
+ }
+
+ // test copy constructor
+ Normalizer copy(norm);
+ if(copy.next()!=0xac00) {
+ errln("error in Normalizer(Normalizer(CharacterIterator)).next()");
+ }
+
+ // test clone(), ==, and hashCode()
+ Normalizer *clone=copy.clone();
+ if(*clone!=copy) {
+ errln("error in Normalizer(Normalizer(CharacterIterator)).clone()!=copy");
+ }
+ // clone must have the same hashCode()
+ if(clone->hashCode()!=copy.hashCode()) {
+ errln("error in Normalizer(Normalizer(CharacterIterator)).clone()->hashCode()!=copy.hashCode()");
+ }
+ if(clone->next()!=0x4e3d) {
+ errln("error in Normalizer(Normalizer(CharacterIterator)).clone()->next()");
+ }
+ // position changed, must change hashCode()
+ if(clone->hashCode()==copy.hashCode()) {
+ errln("error in Normalizer(Normalizer(CharacterIterator)).clone()->next().hashCode()==copy.hashCode()");
+ }
+ delete clone;
+ clone=0;
+
+ // test compose() and decompose()
+ UnicodeString tel, nfkc, nfkd;
+ tel=UnicodeString(1, (UChar32)0x2121, 10);
+ tel.insert(1, (UChar)0x301);
+
+ UErrorCode errorCode=U_ZERO_ERROR;
+ Normalizer::compose(tel, TRUE, 0, nfkc, errorCode);
+ Normalizer::decompose(tel, TRUE, 0, nfkd, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("error in Normalizer::(de)compose(): %s", u_errorName(errorCode));
+ } else if(
+ nfkc!=UnicodeString("TE\\u0139TELTELTELTELTELTELTELTELTEL", "").unescape() ||
+ nfkd!=UnicodeString("TEL\\u0301TELTELTELTELTELTELTELTELTEL", "").unescape()
+ ) {
+ errln("error in Normalizer::(de)compose(): wrong result(s)");
+ }
+
+ // test setIndex()
+ norm.setIndexOnly(3);
+ if(norm.current()!=0x4e3d) {
+ errln("error in Normalizer(CharacterIterator).setIndex(3)");
+ }
+
+ // test setText(CharacterIterator) and getText()
+ UnicodeString out, out2;
+ errorCode=U_ZERO_ERROR;
+ copy.setText(iter, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("error Normalizer::setText() failed: %s", u_errorName(errorCode));
+ } else {
+ copy.getText(out);
+ iter.getText(out2);
+ if( out!=out2 ||
+ copy.startIndex()!=iter.startIndex() ||
+ copy.endIndex()!=iter.endIndex()
+ ) {
+ errln("error in Normalizer::setText() or Normalizer::getText()");
+ }
+ }
+
+ // test setText(UChar *), getUMode() and setMode()
+ errorCode=U_ZERO_ERROR;
+ copy.setText(s.getBuffer()+1, s.length()-1, errorCode);
+ copy.setMode(UNORM_NFD);
+ if(copy.getUMode()!=UNORM_NFD) {
+ errln("error in Normalizer::setMode() or Normalizer::getUMode()");
+ }
+ if(copy.next()!=0x308 || copy.next()!=0x1100) {
+ errln("error in Normalizer::setText(UChar *) or Normalizer::setMode()");
+ }
+
+ // test setText(UChar *, length=-1)
+ errorCode=U_ZERO_ERROR;
+
+ // NUL-terminate s
+ s.append((UChar)0); // append NUL
+ s.truncate(s.length()-1); // undo length change
+
+ copy.setText(s.getBuffer()+1, -1, errorCode);
+ if(copy.endIndex()!=s.length()-1) {
+ errln("error in Normalizer::setText(UChar *, -1)");
+ }
+
+ // test setOption() and getOption()
+ copy.setOption(0xaa0000, TRUE);
+ copy.setOption(0x20000, FALSE);
+ if(!copy.getOption(0x880000) || copy.getOption(0x20000)) {
+ errln("error in Normalizer::setOption() or Normalizer::getOption()");
+ }
+
+ // test last()/previous() with an internal buffer overflow
+ errorCode=U_ZERO_ERROR;
+ copy.setText(UnicodeString(1000, (UChar32)0x308, 1000), errorCode);
+ if(copy.last()!=0x308) {
+ errln("error in Normalizer(1000*U+0308).last()");
+ }
+
+ // test UNORM_NONE
+ norm.setMode(UNORM_NONE);
+ if(norm.first()!=0x61 || norm.next()!=0x308 || norm.last()!=0x2f800) {
+ errln("error in Normalizer(UNORM_NONE).first()/next()/last()");
+ }
+ Normalizer::normalize(s, UNORM_NONE, 0, out, status);
+ if(out!=s) {
+ errln("error in Normalizer::normalize(UNORM_NONE)");
+ }
+
+ // test that the same string can be used as source and destination
+ s.setTo((UChar)0xe4);
+ Normalizer::normalize(s, UNORM_NFD, 0, s, status);
+ if(s.charAt(1)!=0x308) {
+ errln("error in Normalizer::normalize(UNORM_NFD, self)");
+ }
+ Normalizer::normalize(s, UNORM_NFC, 0, s, status);
+ if(s.charAt(0)!=0xe4) {
+ errln("error in Normalizer::normalize(UNORM_NFC, self)");
+ }
+ Normalizer::decompose(s, FALSE, 0, s, status);
+ if(s.charAt(1)!=0x308) {
+ errln("error in Normalizer::decompose(self)");
+ }
+ Normalizer::compose(s, FALSE, 0, s, status);
+ if(s.charAt(0)!=0xe4) {
+ errln("error in Normalizer::compose(self)");
+ }
+ Normalizer::concatenate(s, s, s, UNORM_NFC, 0, status);
+ if(s.charAt(1)!=0xe4) {
+ errln("error in Normalizer::decompose(self)");
+ }
+
+ // test internal normalization exclusion options
+ // s contains a compatibility CJK character and a Hangul syllable
+ s=UnicodeString("a\\uFACE\\uD7A3b", -1, US_INV).unescape();
+ status=U_ZERO_ERROR;
+ Normalizer::decompose(s, FALSE, UNORM_NX_HANGUL, out, status);
+ if(U_FAILURE(status) || out!=UNICODE_STRING_SIMPLE("a\\u9F9C\\uD7A3b").unescape()) {
+ errln("Normalizer::decompose(UNORM_NX_HANGUL) failed - %s", u_errorName(status));
+ }
+ status=U_ZERO_ERROR;
+ Normalizer::decompose(s, FALSE, UNORM_NX_CJK_COMPAT, out, status);
+ if(U_FAILURE(status) || out!=UNICODE_STRING_SIMPLE("a\\uFACE\\u1112\\u1175\\u11c2b").unescape()) {
+ errln("Normalizer::decompose(UNORM_NX_CJK_COMPAT) failed - %s", u_errorName(status));
+ }
+ status=U_ZERO_ERROR;
+ Normalizer::decompose(s, FALSE, UNORM_NX_CJK_COMPAT|UNORM_NX_HANGUL, out, status);
+ if(U_FAILURE(status) || out!=UNICODE_STRING_SIMPLE("a\\uFACE\\uD7A3b").unescape()) {
+ errln("Normalizer::decompose(UNORM_NX_CJK_COMPAT|UNORM_NX_HANGUL) failed - %s", u_errorName(status));
+ }
+}
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzbdtest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tzbdtest.cpp
new file mode 100644
index 00000000000..88e0fab9c7c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzbdtest.cpp
@@ -0,0 +1,513 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tzbdtest.h"
+#include "unicode/timezone.h"
+#include "unicode/simpletz.h"
+#include "unicode/gregocal.h"
+#include "putilimp.h"
+
+void TimeZoneBoundaryTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite TestTimeZoneBoundary");
+ switch (index) {
+ case 0:
+ name = "TestBoundaries";
+ if (exec) {
+ logln("TestBoundaries---"); logln("");
+ TestBoundaries();
+ }
+ break;
+ case 1:
+ name = "TestNewRules";
+ if (exec) {
+ logln("TestNewRules---"); logln("");
+ TestNewRules();
+ }
+ break;
+ case 2:
+ name = "TestStepwise";
+ if (exec) {
+ logln("TestStepwise---"); logln("");
+ TestStepwise();
+ }
+ break;
+ default: name = ""; break;
+ }
+}
+
+// *****************************************************************************
+// class TimeZoneBoundaryTest
+// *****************************************************************************
+
+TimeZoneBoundaryTest::TimeZoneBoundaryTest()
+:
+ONE_SECOND(1000),
+ONE_MINUTE(60 * ONE_SECOND),
+ONE_HOUR(60 * ONE_MINUTE),
+ONE_DAY(24 * ONE_HOUR),
+ONE_YEAR(uprv_floor(365.25 * ONE_DAY)),
+SIX_MONTHS(ONE_YEAR / 2)
+{
+}
+
+const int32_t TimeZoneBoundaryTest::MONTH_LENGTH[] = {
+ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+const UDate TimeZoneBoundaryTest::PST_1997_BEG = 860320800000.0;
+
+const UDate TimeZoneBoundaryTest::PST_1997_END = 877856400000.0;
+
+const UDate TimeZoneBoundaryTest::INTERVAL = 10;
+
+// -------------------------------------
+
+void
+TimeZoneBoundaryTest::findDaylightBoundaryUsingDate(UDate d, const char* startMode, UDate expectedBoundary)
+{
+ UnicodeString str;
+ if (dateToString(d, str).indexOf(startMode) == - 1) {
+ logln(UnicodeString("Error: ") + startMode + " not present in " + str);
+ }
+ UDate min = d;
+ UDate max = min + SIX_MONTHS;
+ while ((max - min) > INTERVAL) {
+ UDate mid = (min + max) / 2;
+ UnicodeString* s = &dateToString(mid, str);
+ if (s->indexOf(startMode) != - 1) {
+ min = mid;
+ }
+ else {
+ max = mid;
+ }
+ }
+ logln("Date Before: " + showDate(min));
+ logln("Date After: " + showDate(max));
+ UDate mindelta = expectedBoundary - min;
+ UDate maxdelta = max - expectedBoundary;
+ if (mindelta >= 0 &&
+ mindelta <= INTERVAL &&
+ maxdelta >= 0 &&
+ maxdelta <= INTERVAL) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary);
+ else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary);
+}
+
+// -------------------------------------
+
+void
+TimeZoneBoundaryTest::findDaylightBoundaryUsingTimeZone(UDate d, UBool startsInDST, UDate expectedBoundary)
+{
+ TimeZone *zone = TimeZone::createDefault();
+ findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary, zone);
+ delete zone;
+}
+
+// -------------------------------------
+
+void
+TimeZoneBoundaryTest::findDaylightBoundaryUsingTimeZone(UDate d, UBool startsInDST, UDate expectedBoundary, TimeZone* tz)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString str;
+ UDate min = d;
+ UDate max = min + SIX_MONTHS;
+ if (tz->inDaylightTime(d, status) != startsInDST) {
+ errln("FAIL: " + tz->getID(str) + " inDaylightTime(" + dateToString(d) + ") != " + (startsInDST ? "true" : "false"));
+ startsInDST = !startsInDST;
+ }
+ if (failure(status, "TimeZone::inDaylightTime")) return;
+ if (tz->inDaylightTime(max, status) == startsInDST) {
+ errln("FAIL: " + tz->getID(str) + " inDaylightTime(" + dateToString(max) + ") != " + (startsInDST ? "false" : "true"));
+ return;
+ }
+ if (failure(status, "TimeZone::inDaylightTime")) return;
+ while ((max - min) > INTERVAL) {
+ UDate mid = (min + max) / 2;
+ UBool isIn = tz->inDaylightTime(mid, status);
+ if (failure(status, "TimeZone::inDaylightTime")) return;
+ if (isIn == startsInDST) {
+ min = mid;
+ }
+ else {
+ max = mid;
+ }
+ }
+ logln(tz->getID(str) + " Before: " + showDate(min));
+ logln(tz->getID(str) + " After: " + showDate(max));
+ UDate mindelta = expectedBoundary - min;
+ UDate maxdelta = max - expectedBoundary;
+ if (mindelta >= 0 &&
+ mindelta <= INTERVAL &&
+ maxdelta >= 0 &&
+ maxdelta <= INTERVAL) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary);
+ else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary);
+}
+
+// -------------------------------------
+/*
+UnicodeString*
+TimeZoneBoundaryTest::showDate(int32_t l)
+{
+ return showDate(new Date(l));
+}
+*/
+// -------------------------------------
+
+UnicodeString
+TimeZoneBoundaryTest::showDate(UDate d)
+{
+ int32_t y, m, day, h, min, sec;
+ dateToFields(d, y, m, day, h, min, sec);
+ return UnicodeString("") + y + "/" + showNN(m + 1) + "/" +
+ showNN(day) + " " + showNN(h) + ":" + showNN(min) +
+ " \"" + dateToString(d) + "\" = " + uprv_floor(d+0.5);
+}
+
+// -------------------------------------
+
+UnicodeString
+TimeZoneBoundaryTest::showNN(int32_t n)
+{
+ UnicodeString nStr;
+ if (n < 10) {
+ nStr += UnicodeString("0", "");
+ }
+ return nStr + n;
+}
+
+// -------------------------------------
+
+void
+TimeZoneBoundaryTest::verifyDST(UDate d, TimeZone* time_zone, UBool expUseDaylightTime, UBool expInDaylightTime, UDate expZoneOffset, UDate expDSTOffset)
+{
+ UnicodeString str;
+ UErrorCode status = U_ZERO_ERROR;
+ logln("-- Verifying time " + dateToString(d) + " in zone " + time_zone->getID(str));
+ if (time_zone->inDaylightTime(d, status) == expInDaylightTime)
+ logln(UnicodeString("PASS: inDaylightTime = ") + (time_zone->inDaylightTime(d, status)?"true":"false"));
+ else
+ errln(UnicodeString("FAIL: inDaylightTime = ") + (time_zone->inDaylightTime(d, status)?"true":"false"));
+ if (failure(status, "TimeZone::inDaylightTime"))
+ return;
+ if (time_zone->useDaylightTime() == expUseDaylightTime)
+ logln(UnicodeString("PASS: useDaylightTime = ") + (time_zone->useDaylightTime()?"true":"false"));
+ else
+ errln(UnicodeString("FAIL: useDaylightTime = ") + (time_zone->useDaylightTime()?"true":"false"));
+ if (time_zone->getRawOffset() == expZoneOffset)
+ logln(UnicodeString("PASS: getRawOffset() = ") + (expZoneOffset / ONE_HOUR));
+ else
+ errln(UnicodeString("FAIL: getRawOffset() = ") + (time_zone->getRawOffset() / ONE_HOUR) + "; expected " + (expZoneOffset / ONE_HOUR));
+
+ GregorianCalendar *gc = new GregorianCalendar(time_zone->clone(), status);
+ gc->setTime(d, status);
+ if (failure(status, "GregorianCalendar::setTime")) return;
+ int32_t offset = time_zone->getOffset((uint8_t)gc->get(UCAL_ERA, status),
+ gc->get(UCAL_YEAR, status), gc->get(UCAL_MONTH, status),
+ gc->get(UCAL_DATE, status), (uint8_t)gc->get(UCAL_DAY_OF_WEEK, status),
+ ((gc->get(UCAL_HOUR_OF_DAY, status) * 60 + gc->get(UCAL_MINUTE, status)) * 60 + gc->get(UCAL_SECOND, status)) * 1000 + gc->get(UCAL_MILLISECOND, status),
+ status);
+ if (failure(status, "GregorianCalendar::get")) return;
+ if (offset == expDSTOffset) logln(UnicodeString("PASS: getOffset() = ") + (offset / ONE_HOUR));
+ else errln(UnicodeString("FAIL: getOffset() = ") + (offset / ONE_HOUR) + "; expected " + (expDSTOffset / ONE_HOUR));
+ delete gc;
+}
+
+// -------------------------------------
+/**
+ * Check that the given year/month/dom/hour maps to and from the
+ * given epochHours. This verifies the functioning of the
+ * calendar and time zone in conjunction with one another,
+ * including the calendar time->fields and fields->time and
+ * the time zone getOffset method.
+ *
+ * @param epochHours hours after Jan 1 1970 0:00 GMT.
+ */
+void TimeZoneBoundaryTest::verifyMapping(Calendar& cal, int year, int month, int dom, int hour,
+ double epochHours) {
+ double H = 3600000.0;
+ UErrorCode status = U_ZERO_ERROR;
+ cal.clear();
+ cal.set(year, month, dom, hour, 0, 0);
+ UDate e = cal.getTime(status)/ H;
+ UDate ed = (epochHours * H);
+ if (e == epochHours) {
+ logln(UnicodeString("Ok: ") + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +
+ e + " (" + ed + ")");
+ } else {
+ errln(UnicodeString("FAIL: ") + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +
+ e + " (" + (e * H) + ")" +
+ ", expected " + epochHours + " (" + ed + ")");
+ }
+ cal.setTime(ed, status);
+ if (cal.get(UCAL_YEAR, status) == year &&
+ cal.get(UCAL_MONTH, status) == month &&
+ cal.get(UCAL_DATE, status) == dom &&
+ cal.get(UCAL_MILLISECONDS_IN_DAY, status) == hour * 3600000) {
+ logln(UnicodeString("Ok: ") + epochHours + " (" + ed + ") => " +
+ cal.get(UCAL_YEAR, status) + "/" +
+ (cal.get(UCAL_MONTH, status)+1) + "/" +
+ cal.get(UCAL_DATE, status) + " " +
+ cal.get(UCAL_MILLISECOND, status)/H);
+ } else {
+ errln(UnicodeString("FAIL: ") + epochHours + " (" + ed + ") => " +
+ cal.get(UCAL_YEAR, status) + "/" +
+ (cal.get(UCAL_MONTH, status)+1) + "/" +
+ cal.get(UCAL_DATE, status) + " " +
+ cal.get(UCAL_MILLISECOND, status)/H +
+ ", expected " + year + "/" + (month+1) + "/" + dom +
+ " " + hour);
+ }
+}
+
+/**
+ * Test the behavior of SimpleTimeZone at the transition into and out of DST.
+ * Use a binary search to find boundaries.
+ */
+void
+TimeZoneBoundaryTest::TestBoundaries()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ TimeZone* pst = TimeZone::createTimeZone("PST");
+ Calendar* tempcal = Calendar::createInstance(pst, status);
+ if(U_SUCCESS(status)){
+ verifyMapping(*tempcal, 1997, Calendar::APRIL, 3, 0, 238904.0);
+ verifyMapping(*tempcal, 1997, Calendar::APRIL, 4, 0, 238928.0);
+ verifyMapping(*tempcal, 1997, Calendar::APRIL, 5, 0, 238952.0);
+ verifyMapping(*tempcal, 1997, Calendar::APRIL, 5, 23, 238975.0);
+ verifyMapping(*tempcal, 1997, Calendar::APRIL, 6, 0, 238976.0);
+ verifyMapping(*tempcal, 1997, Calendar::APRIL, 6, 1, 238977.0);
+ verifyMapping(*tempcal, 1997, Calendar::APRIL, 6, 3, 238978.0);
+ }else{
+ errln("Could not create calendar. Error: %s", u_errorName(status));
+ }
+ TimeZone* utc = TimeZone::createTimeZone("UTC");
+ Calendar* utccal = Calendar::createInstance(utc, status);
+ if(U_SUCCESS(status)){
+ verifyMapping(*utccal, 1997, Calendar::APRIL, 6, 0, 238968.0);
+ }else{
+ errln("Could not create calendar. Error: %s", u_errorName(status));
+ }
+ TimeZone* save = TimeZone::createDefault();
+ TimeZone::setDefault(*pst);
+
+ // DST changeover for PST is 4/6/1997 at 2 hours past midnight
+ // at 238978.0 epoch hours.
+ tempcal->clear();
+ tempcal->set(1997, Calendar::APRIL, 6);
+ UDate d = tempcal->getTime(status);
+
+ // i is minutes past midnight standard time
+ for (int i=-120; i<=180; i+=60)
+ {
+ UBool inDST = (i >= 120);
+ tempcal->setTime(d + i*60*1000, status);
+ verifyDST(tempcal->getTime(status),pst, TRUE, inDST, -8*ONE_HOUR,inDST ? -7*ONE_HOUR : -8*ONE_HOUR);
+ }
+ TimeZone::setDefault(*save);
+ delete save;
+ delete utccal;
+ delete tempcal;
+
+#if 1
+ {
+ logln("--- Test a ---");
+ UDate d = date(97, UCAL_APRIL, 6);
+ TimeZone *z = TimeZone::createTimeZone("PST");
+ for (int32_t i = 60; i <= 180; i += 15) {
+ UBool inDST = (i >= 120);
+ UDate e = d + i * 60 * 1000;
+ verifyDST(e, z, TRUE, inDST, - 8 * ONE_HOUR, inDST ? - 7 * ONE_HOUR: - 8 * ONE_HOUR);
+ }
+ delete z;
+ }
+#endif
+#if 1
+ {
+ logln("--- Test b ---");
+ TimeZone *tz;
+ TimeZone::setDefault(*(tz = TimeZone::createTimeZone("PST")));
+ delete tz;
+ logln("========================================");
+ findDaylightBoundaryUsingDate(date(97, 0, 1), "PST", PST_1997_BEG);
+ logln("========================================");
+ findDaylightBoundaryUsingDate(date(97, 6, 1), "PDT", PST_1997_END);
+ }
+#endif
+#if 1
+ {
+ logln("--- Test c ---");
+ logln("========================================");
+ TimeZone* z = TimeZone::createTimeZone("Australia/Adelaide");
+ findDaylightBoundaryUsingTimeZone(date(97, 0, 1), TRUE, 859653000000.0, z);
+ logln("========================================");
+ findDaylightBoundaryUsingTimeZone(date(97, 6, 1), FALSE, 877797000000.0, z);
+ delete z;
+ }
+#endif
+#if 1
+ {
+ logln("--- Test d ---");
+ logln("========================================");
+ findDaylightBoundaryUsingTimeZone(date(97, 0, 1), FALSE, PST_1997_BEG);
+ logln("========================================");
+ findDaylightBoundaryUsingTimeZone(date(97, 6, 1), TRUE, PST_1997_END);
+ }
+#endif
+#if 0
+ {
+ logln("--- Test e ---");
+ TimeZone *z = TimeZone::createDefault();
+ logln(UnicodeString("") + z->getOffset(1, 97, 3, 4, 6, 0) + " " + date(97, 3, 4));
+ logln(UnicodeString("") + z->getOffset(1, 97, 3, 5, 7, 0) + " " + date(97, 3, 5));
+ logln(UnicodeString("") + z->getOffset(1, 97, 3, 6, 1, 0) + " " + date(97, 3, 6));
+ logln(UnicodeString("") + z->getOffset(1, 97, 3, 7, 2, 0) + " " + date(97, 3, 7));
+ delete z;
+ }
+#endif
+}
+
+// -------------------------------------
+
+void
+TimeZoneBoundaryTest::testUsingBinarySearch(SimpleTimeZone* tz, UDate d, UDate expectedBoundary)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UDate min = d;
+ UDate max = min + SIX_MONTHS;
+ UBool startsInDST = tz->inDaylightTime(d, status);
+ if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
+ if (tz->inDaylightTime(max, status) == startsInDST) {
+ errln("Error: inDaylightTime(" + dateToString(max) + ") != " + ((!startsInDST)?"true":"false"));
+ }
+ if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
+ while ((max - min) > INTERVAL) {
+ UDate mid = (min + max) / 2;
+ if (tz->inDaylightTime(mid, status) == startsInDST) {
+ min = mid;
+ }
+ else {
+ max = mid;
+ }
+ if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
+ }
+ logln("Binary Search Before: " + showDate(min));
+ logln("Binary Search After: " + showDate(max));
+ UDate mindelta = expectedBoundary - min;
+ UDate maxdelta = max - expectedBoundary;
+ if (mindelta >= 0 &&
+ mindelta <= INTERVAL &&
+ maxdelta >= 0 &&
+ maxdelta <= INTERVAL) logln(UnicodeString("PASS: Expected boundary at ") + expectedBoundary);
+ else errln(UnicodeString("FAIL: Expected boundary at ") + expectedBoundary);
+}
+
+// -------------------------------------
+
+/**
+ * Test the handling of the "new" rules; that is, rules other than nth Day of week.
+ */
+void
+TimeZoneBoundaryTest::TestNewRules()
+{
+#if 1
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleTimeZone *tz;
+ logln("-----------------------------------------------------------------");
+ logln("Aug 2ndTues .. Mar 15");
+ tz = new SimpleTimeZone(- 8 * (int32_t)ONE_HOUR, "Test_1", UCAL_AUGUST, 2, UCAL_TUESDAY, 2 * (int32_t)ONE_HOUR, UCAL_MARCH, 15, 0, 2 * (int32_t)ONE_HOUR, status);
+ logln("========================================");
+ testUsingBinarySearch(tz, date(97, 0, 1), 858416400000.0);
+ logln("========================================");
+ testUsingBinarySearch(tz, date(97, 6, 1), 871380000000.0);
+ delete tz;
+ logln("-----------------------------------------------------------------");
+ logln("Apr Wed>=14 .. Sep Sun<=20");
+ tz = new SimpleTimeZone(- 8 * (int32_t)ONE_HOUR, "Test_2", UCAL_APRIL, 14, - UCAL_WEDNESDAY, 2 *(int32_t)ONE_HOUR, UCAL_SEPTEMBER, - 20, - UCAL_SUNDAY, 2 * (int32_t)ONE_HOUR, status);
+ logln("========================================");
+ testUsingBinarySearch(tz, date(97, 0, 1), 861184800000.0);
+ logln("========================================");
+ testUsingBinarySearch(tz, date(97, 6, 1), 874227600000.0);
+ delete tz;
+ }
+#endif
+}
+
+// -------------------------------------
+
+void
+TimeZoneBoundaryTest::findBoundariesStepwise(int32_t year, UDate interval, TimeZone* z, int32_t expectedChanges)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString str;
+ UDate d = date(year - 1900, UCAL_JANUARY, 1);
+ UDate time = d;
+ UDate limit = time + ONE_YEAR + ONE_DAY;
+ UBool lastState = z->inDaylightTime(d, status);
+ if (failure(status, "TimeZone::inDaylightTime")) return;
+ int32_t changes = 0;
+ logln(UnicodeString("-- Zone ") + z->getID(str) + " starts in " + year + " with DST = " + (lastState?"true":"false"));
+ logln(UnicodeString("useDaylightTime = ") + (z->useDaylightTime()?"true":"false"));
+ while (time < limit) {
+ d = time;
+ UBool state = z->inDaylightTime(d, status);
+ if (failure(status, "TimeZone::inDaylightTime")) return;
+ if (state != lastState) {
+ logln(UnicodeString(state ? "Entry ": "Exit ") + "at " + d);
+ lastState = state;++changes;
+ }
+ time += interval;
+ }
+ if (changes == 0) {
+ if (!lastState &&
+ !z->useDaylightTime()) logln("No DST");
+ else errln("FAIL: DST all year, or no DST with true useDaylightTime");
+ }
+ else if (changes != 2) {
+ errln(UnicodeString("FAIL: ") + changes + " changes seen; should see 0 or 2");
+ }
+ else if (!z->useDaylightTime()) {
+ errln("FAIL: useDaylightTime false but 2 changes seen");
+ }
+ if (changes != expectedChanges) {
+ errln(UnicodeString("FAIL: ") + changes + " changes seen; expected " + expectedChanges);
+ }
+}
+
+// -------------------------------------
+
+/**
+ * This test is problematic. It makes assumptions about the behavior
+ * of specific zones. Since ICU's zone table is based on the Olson
+ * zones (the UNIX zones), and those change from time to time, this
+ * test can fail after a zone table update. If that happens, the
+ * selected zones need to be updated to have the behavior
+ * expected. That is, they should have DST, not have DST, and have DST
+ * -- other than that this test isn't picky. 12/3/99 aliu
+ *
+ * Test the behavior of SimpleTimeZone at the transition into and out of DST.
+ * Use a stepwise march to find boundaries.
+ */
+void
+TimeZoneBoundaryTest::TestStepwise()
+{
+ TimeZone *zone = TimeZone::createTimeZone("America/New_York");
+ findBoundariesStepwise(1997, ONE_DAY, zone, 2);
+ delete zone;
+ zone = TimeZone::createTimeZone("UTC"); // updated 12/3/99 aliu
+ findBoundariesStepwise(1997, ONE_DAY, zone, 0);
+ delete zone;
+ zone = TimeZone::createTimeZone("Australia/Adelaide");
+ findBoundariesStepwise(1997, ONE_DAY, zone, 2);
+ delete zone;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzbdtest.h b/Build/source/libs/icu/icu-xetex/test/intltest/tzbdtest.h
new file mode 100644
index 00000000000..ecc867c9faf
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzbdtest.h
@@ -0,0 +1,99 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef __TimeZoneBoundaryTest__
+#define __TimeZoneBoundaryTest__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/timezone.h"
+#include "unicode/simpletz.h"
+#include "caltztst.h"
+
+/**
+ * A test which discovers the boundaries of DST programmatically and verifies
+ * that they are correct.
+ */
+class TimeZoneBoundaryTest: public CalendarTimeZoneTest {
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public: // package
+
+ TimeZoneBoundaryTest();
+
+ /**
+ * Date.toString().substring() Boundary Test
+ * Look for a DST changeover to occur within 6 months of the given Date.
+ * The initial Date.toString() should yield a string containing the
+ * startMode as a SUBSTRING. The boundary will be tested to be
+ * at the expectedBoundary value.
+ */
+
+ /**
+ * internal routines used by major test routines to perform subtests
+ **/
+ virtual void findDaylightBoundaryUsingDate(UDate d, const char* startMode, UDate expectedBoundary);
+ virtual void findDaylightBoundaryUsingTimeZone(UDate d, UBool startsInDST, UDate expectedBoundary);
+ virtual void findDaylightBoundaryUsingTimeZone(UDate d, UBool startsInDST, UDate expectedBoundary, TimeZone* tz);
+
+private:
+ //static UnicodeString* showDate(long l);
+ UnicodeString showDate(UDate d);
+ static UnicodeString showNN(int32_t n);
+
+public: // package
+ /**
+ * Given a date, a TimeZone, and expected values for inDaylightTime,
+ * useDaylightTime, zone and DST offset, verify that this is the case.
+ */
+ virtual void verifyDST(UDate d, TimeZone* time_zone, UBool expUseDaylightTime, UBool expInDaylightTime, UDate expZoneOffset, UDate expDSTOffset);
+
+ /**
+ * Test the behavior of SimpleTimeZone at the transition into and out of DST.
+ * Use a binary search to find boundaries.
+ */
+ virtual void TestBoundaries(void);
+
+ /**
+ * internal subroutine used by TestNewRules
+ **/
+ virtual void testUsingBinarySearch(SimpleTimeZone* tz, UDate d, UDate expectedBoundary);
+
+ /**
+ * Test the handling of the "new" rules; that is, rules other than nth Day of week.
+ */
+ virtual void TestNewRules(void);
+
+ /**
+ * Find boundaries by stepping.
+ */
+ virtual void findBoundariesStepwise(int32_t year, UDate interval, TimeZone* z, int32_t expectedChanges);
+
+ /**
+ * Test the behavior of SimpleTimeZone at the transition into and out of DST.
+ * Use a stepwise march to find boundaries.
+ */
+ virtual void TestStepwise(void);
+ void verifyMapping(Calendar& cal, int year, int month, int dom, int hour,
+ double epochHours) ;
+private:
+ const UDate ONE_SECOND;
+ const UDate ONE_MINUTE;
+ const UDate ONE_HOUR;
+ const UDate ONE_DAY;
+ const UDate ONE_YEAR;
+ const UDate SIX_MONTHS;
+ static const int32_t MONTH_LENGTH[];
+ static const UDate PST_1997_BEG;
+ static const UDate PST_1997_END;
+ static const UDate INTERVAL;
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TimeZoneBoundaryTest__
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzfmttst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tzfmttst.cpp
new file mode 100644
index 00000000000..6be576f82ba
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzfmttst.cpp
@@ -0,0 +1,458 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tzfmttst.h"
+
+#include "unicode/timezone.h"
+#include "unicode/simpletz.h"
+#include "unicode/calendar.h"
+#include "unicode/strenum.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/uchar.h"
+#include "unicode/basictz.h"
+#include "cstring.h"
+#include "zonemeta.h"
+
+#define DEBUG_ALL 0
+
+static const char* PATTERNS[] = {"z", "zzzz", "Z", "ZZZZ", "v", "vvvv", "V", "VVVV"};
+static const int NUM_PATTERNS = sizeof(PATTERNS)/sizeof(const char*);
+
+void
+TimeZoneFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) {
+ logln("TestSuite TimeZoneFormatTest");
+ }
+ switch (index) {
+ TESTCASE(0, TestTimeZoneRoundTrip);
+ TESTCASE(1, TestTimeRoundTrip);
+ default: name = ""; break;
+ }
+}
+
+void
+TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ SimpleTimeZone unknownZone(-31415, (UnicodeString)"Etc/Unknown");
+ int32_t badDstOffset = -1234;
+ int32_t badZoneOffset = -2345;
+
+ int32_t testDateData[][3] = {
+ {2007, 1, 15},
+ {2007, 6, 15},
+ {1990, 1, 15},
+ {1990, 6, 15},
+ {1960, 1, 15},
+ {1960, 6, 15},
+ };
+
+ Calendar *cal = Calendar::createInstance(TimeZone::createTimeZone((UnicodeString)"UTC"), status);
+ if (U_FAILURE(status)) {
+ errln("Calendar::createInstance failed");
+ return;
+ }
+
+ // Set up rule equivalency test range
+ UDate low, high;
+ cal->set(1900, UCAL_JANUARY, 1);
+ low = cal->getTime(status);
+ cal->set(2040, UCAL_JANUARY, 1);
+ high = cal->getTime(status);
+ if (U_FAILURE(status)) {
+ errln("getTime failed");
+ return;
+ }
+
+ // Set up test dates
+ UDate DATES[(sizeof(testDateData)/sizeof(int32_t))/3];
+ const int32_t nDates = (sizeof(testDateData)/sizeof(int32_t))/3;
+ cal->clear();
+ for (int32_t i = 0; i < nDates; i++) {
+ cal->set(testDateData[i][0], testDateData[i][1], testDateData[i][2]);
+ DATES[i] = cal->getTime(status);
+ if (U_FAILURE(status)) {
+ errln("getTime failed");
+ return;
+ }
+ }
+
+ // Set up test locales
+ const Locale locales1[] = {
+ Locale("en_US")
+ };
+ const Locale locales2[] = {
+ Locale("en_US"),
+ Locale("en"),
+ Locale("en_CA"),
+ Locale("fr"),
+ Locale("zh_Hant")
+ };
+
+ const Locale *LOCALES;
+ int32_t nLocales;
+ if (DEBUG_ALL) {
+ LOCALES = Locale::getAvailableLocales(nLocales);
+ } else if (quick) {
+ LOCALES = locales1;
+ nLocales = sizeof(locales1)/sizeof(Locale);
+ } else {
+ LOCALES = locales2;
+ nLocales = sizeof(locales2)/sizeof(Locale);
+ }
+
+ StringEnumeration *tzids = TimeZone::createEnumeration();
+ if (U_FAILURE(status)) {
+ errln("tzids->count failed");
+ return;
+ }
+
+ int32_t inRaw, inDst;
+ int32_t outRaw, outDst;
+
+ // Run the roundtrip test
+ for (int32_t locidx = 0; locidx < nLocales; locidx++) {
+ for (int32_t patidx = 0; patidx < NUM_PATTERNS; patidx++) {
+
+ //DEBUG static const char* PATTERNS[] = {"z", "zzzz", "Z", "ZZZZ", "v", "vvvv", "V", "VVVV"};
+ //if (patidx != 1) continue;
+
+ SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)PATTERNS[patidx], LOCALES[locidx], status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"new SimpleDateFormat failed for pattern " +
+ PATTERNS[patidx] + " for locale " + LOCALES[locidx].getName());
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ tzids->reset(status);
+ const UnicodeString *tzid;
+ while ((tzid = tzids->snext(status))) {
+ TimeZone *tz = TimeZone::createTimeZone(*tzid);
+
+ for (int32_t datidx = 0; datidx < nDates; datidx++) {
+ UnicodeString tzstr;
+ FieldPosition fpos(0);
+ // Format
+ sdf->setTimeZone(*tz);
+ sdf->format(DATES[datidx], tzstr, fpos);
+
+ // Before parse, set unknown zone to SimpleDateFormat instance
+ // just for making sure that it does not depends on the time zone
+ // originally set.
+ sdf->setTimeZone(unknownZone);
+
+ // Parse
+ ParsePosition pos(0);
+ Calendar *outcal = Calendar::createInstance(unknownZone, status);
+ if (U_FAILURE(status)) {
+ errln("Failed to create an instance of calendar for receiving parse result.");
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ outcal->set(UCAL_DST_OFFSET, badDstOffset);
+ outcal->set(UCAL_ZONE_OFFSET, badZoneOffset);
+
+ sdf->parse(tzstr, *outcal, pos);
+
+ // Check the result
+ const TimeZone &outtz = outcal->getTimeZone();
+ UnicodeString outtzid;
+ outtz.getID(outtzid);
+
+ tz->getOffset(DATES[datidx], false, inRaw, inDst, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"Failed to get offsets from time zone" + *tzid);
+ status = U_ZERO_ERROR;
+ }
+ outtz.getOffset(DATES[datidx], false, outRaw, outDst, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"Failed to get offsets from time zone" + outtzid);
+ status = U_ZERO_ERROR;
+ }
+
+ // Check if localized GMT format or RFC format is used.
+ int32_t numDigits = 0;
+ for (int n = 0; n < tzstr.length(); n++) {
+ if (u_isdigit(tzstr.charAt(n))) {
+ numDigits++;
+ }
+ }
+ if (numDigits >= 4) {
+ // Localized GMT or RFC: total offset (raw + dst) must be preserved.
+ int32_t inOffset = inRaw + inDst;
+ int32_t outOffset = outRaw + outDst;
+ if (inOffset != outOffset) {
+ errln((UnicodeString)"Offset round trip failed; tz=" + *tzid
+ + ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
+ + ", time=" + DATES[datidx] + ", str=" + tzstr
+ + ", inOffset=" + inOffset + ", outOffset=" + outOffset);
+ }
+ } else if (uprv_strcmp(PATTERNS[patidx], "z") == 0 || uprv_strcmp(PATTERNS[patidx], "zzzz") == 0
+ || uprv_strcmp(PATTERNS[patidx], "v") == 0 || uprv_strcmp(PATTERNS[patidx], "vvvv") == 0
+ || uprv_strcmp(PATTERNS[patidx], "V") == 0) {
+ // Specific or generic: raw offset must be preserved.
+ if (inRaw != outRaw) {
+ errln((UnicodeString)"Raw offset round trip failed; tz=" + *tzid
+ + ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
+ + ", time=" + DATES[datidx] + ", str=" + tzstr
+ + ", inRawOffset=" + inRaw + ", outRawOffset=" + outRaw);
+ }
+ } else { // "VVVV"
+ // Location: time zone rule must be preserved.
+ UnicodeString canonical;
+ ZoneMeta::getCanonicalID(*tzid, canonical);
+ if (outtzid != canonical) {
+ // Canonical ID did not match - check the rules
+ if (!((BasicTimeZone*)&outtz)->hasEquivalentTransitions((BasicTimeZone&)*tz, low, high, TRUE, status)) {
+ errln("Canonical round trip failed; tz=" + *tzid
+ + ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
+ + ", time=" + DATES[datidx] + ", str=" + tzstr
+ + ", outtz=" + outtzid);
+ }
+ if (U_FAILURE(status)) {
+ errln("hasEquivalentTransitions failed");
+ status = U_ZERO_ERROR;
+ }
+ }
+ }
+ delete outcal;
+ }
+ delete tz;
+ }
+ delete sdf;
+ }
+ }
+ delete cal;
+ delete tzids;
+}
+
+void
+TimeZoneFormatTest::TestTimeRoundTrip(void) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ Calendar *cal = Calendar::createInstance(TimeZone::createTimeZone((UnicodeString)"UTC"), status);
+ if (U_FAILURE(status)) {
+ errln("Calendar::createInstance failed");
+ return;
+ }
+
+ UDate START_TIME, END_TIME;
+
+ if (DEBUG_ALL) {
+ cal->set(1900, UCAL_JANUARY, 1);
+ } else {
+ cal->set(1965, UCAL_JANUARY, 1);
+ }
+ START_TIME = cal->getTime(status);
+
+ cal->set(2015, UCAL_JANUARY, 1);
+ END_TIME = cal->getTime(status);
+ if (U_FAILURE(status)) {
+ errln("getTime failed");
+ return;
+ }
+
+ // Whether each pattern is ambiguous at DST->STD local time overlap
+ UBool AMBIGUOUS_DST_DECESSION[] = {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE};
+ // Whether each pattern is ambiguous at STD->STD/DST->DST local time overlap
+ UBool AMBIGUOUS_NEGATIVE_SHIFT[] = {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE};
+
+ UnicodeString BASEPATTERN("yyyy-MM-dd'T'HH:mm:ss.SSS");
+
+ // timer for performance analysis
+ UDate timer;
+ UDate times[NUM_PATTERNS];
+ for (int32_t i = 0; i < NUM_PATTERNS; i++) {
+ times[i] = 0;
+ }
+
+ UBool REALLY_VERBOSE = FALSE;
+
+ // Set up test locales
+ const Locale locales1[] = {
+ Locale("en_US")
+ };
+ const Locale locales2[] = {
+ Locale("en_US"),
+ Locale("en"),
+ Locale("de_DE"),
+ Locale("es_ES"),
+ Locale("fr_FR"),
+ Locale("it_IT"),
+ Locale("ja_JP"),
+ Locale("ko_KR"),
+ Locale("pt_BR"),
+ Locale("zh_Hans_CN"),
+ Locale("zh_Hant_TW")
+ };
+
+ const Locale *LOCALES;
+ int32_t nLocales;
+ if (DEBUG_ALL) {
+ LOCALES = Locale::getAvailableLocales(nLocales);
+ } else if (quick) {
+ LOCALES = locales1;
+ nLocales = sizeof(locales1)/sizeof(Locale);
+ } else {
+ LOCALES = locales2;
+ nLocales = sizeof(locales2)/sizeof(Locale);
+ }
+
+ StringEnumeration *tzids = TimeZone::createEnumeration();
+ if (U_FAILURE(status)) {
+ errln("tzids->count failed");
+ return;
+ }
+
+ int32_t testCounts = 0;
+ UDate testTimes[4];
+ UBool expectedRoundTrip[4];
+ int32_t testLen = 0;
+
+ for (int32_t locidx = 0; locidx < nLocales; locidx++) {
+ logln((UnicodeString)"Locale: " + LOCALES[locidx].getName());
+
+ for (int32_t patidx = 0; patidx < NUM_PATTERNS; patidx++) {
+ logln((UnicodeString)" pattern: " + PATTERNS[patidx]);
+
+ //DEBUG static const char* PATTERNS[] = {"z", "zzzz", "Z", "ZZZZ", "v", "vvvv", "V", "VVVV"};
+ //if (patidx != 1) continue;
+
+ UnicodeString pattern(BASEPATTERN);
+ pattern.append(" ").append(PATTERNS[patidx]);
+
+ SimpleDateFormat *sdf = new SimpleDateFormat(pattern, LOCALES[locidx], status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"new SimpleDateFormat failed for pattern " +
+ pattern + " for locale " + LOCALES[locidx].getName());
+ status = U_ZERO_ERROR;
+ continue;
+ }
+
+ tzids->reset(status);
+ const UnicodeString *tzid;
+
+ timer = Calendar::getNow();
+
+ while ((tzid = tzids->snext(status))) {
+ UnicodeString canonical;
+ ZoneMeta::getCanonicalID(*tzid, canonical);
+ if (*tzid != canonical) {
+ // Skip aliases
+ continue;
+ }
+ BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
+ sdf->setTimeZone(*tz);
+
+ UDate t = START_TIME;
+ TimeZoneTransition tzt;
+ UBool tztAvail = FALSE;
+ UBool middle = TRUE;
+
+ while (t < END_TIME) {
+ if (!tztAvail) {
+ testTimes[0] = t;
+ expectedRoundTrip[0] = TRUE;
+ testLen = 1;
+ } else {
+ int32_t fromOffset = tzt.getFrom()->getRawOffset() + tzt.getFrom()->getDSTSavings();
+ int32_t toOffset = tzt.getTo()->getRawOffset() + tzt.getTo()->getDSTSavings();
+ int32_t delta = toOffset - fromOffset;
+ if (delta < 0) {
+ UBool isDstDecession = tzt.getFrom()->getDSTSavings() > 0 && tzt.getTo()->getDSTSavings() == 0;
+ testTimes[0] = t + delta - 1;
+ expectedRoundTrip[0] = TRUE;
+ testTimes[1] = t + delta;
+ expectedRoundTrip[1] = isDstDecession ?
+ !AMBIGUOUS_DST_DECESSION[patidx] : !AMBIGUOUS_NEGATIVE_SHIFT[patidx];
+ testTimes[2] = t - 1;
+ expectedRoundTrip[2] = isDstDecession ?
+ !AMBIGUOUS_DST_DECESSION[patidx] : !AMBIGUOUS_NEGATIVE_SHIFT[patidx];
+ testTimes[3] = t;
+ expectedRoundTrip[3] = TRUE;
+ testLen = 4;
+ } else {
+ testTimes[0] = t - 1;
+ expectedRoundTrip[0] = TRUE;
+ testTimes[1] = t;
+ expectedRoundTrip[1] = TRUE;
+ testLen = 2;
+ }
+ }
+ for (int32_t testidx = 0; testidx < testLen; testidx++) {
+ if (quick) {
+ // reduce regular test time
+ if (!expectedRoundTrip[testidx]) {
+ continue;
+ }
+ }
+ testCounts++;
+
+ UnicodeString text;
+ FieldPosition fpos(0);
+ sdf->format(testTimes[testidx], text, fpos);
+
+ UDate parsedDate = sdf->parse(text, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"Failed to parse " + text);
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ if (parsedDate != testTimes[testidx]) {
+ UnicodeString msg = (UnicodeString)"Time round trip failed for "
+ + "tzid=" + *tzid
+ + ", locale=" + LOCALES[locidx].getName()
+ + ", pattern=" + PATTERNS[patidx]
+ + ", text=" + text
+ + ", time=" + testTimes[testidx]
+ + ", restime=" + parsedDate
+ + ", diff=" + (parsedDate - testTimes[testidx]);
+ if (expectedRoundTrip[testidx]) {
+ errln((UnicodeString)"FAIL: " + msg);
+ } else if (REALLY_VERBOSE) {
+ logln(msg);
+ }
+ }
+ }
+ tztAvail = tz->getNextTransition(t, FALSE, tzt);
+ if (!tztAvail) {
+ break;
+ }
+ if (middle) {
+ // Test the date in the middle of two transitions.
+ t += (int64_t)((tzt.getTime() - t)/2);
+ middle = FALSE;
+ tztAvail = FALSE;
+ } else {
+ t = tzt.getTime();
+ }
+ }
+ delete tz;
+ }
+ times[patidx] += (Calendar::getNow() - timer);
+ delete sdf;
+ }
+ }
+ UDate total = 0;
+ logln("### Elapsed time by patterns ###");
+ for (int32_t i = 0; i < NUM_PATTERNS; i++) {
+ logln(UnicodeString("") + times[i] + "ms (" + PATTERNS[i] + ")");
+ total += times[i];
+ }
+ logln((UnicodeString)"Total: " + total + "ms");
+ logln((UnicodeString)"Iteration: " + testCounts);
+
+ delete cal;
+ delete tzids;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzfmttst.h b/Build/source/libs/icu/icu-xetex/test/intltest/tzfmttst.h
new file mode 100644
index 00000000000..22583309bd5
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzfmttst.h
@@ -0,0 +1,27 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef _TIMEZONEFORMATTEST_
+#define _TIMEZONEFORMATTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+class TimeZoneFormatTest : public IntlTest {
+ // IntlTest override
+ void runIndexedTest(int32_t index, UBool exec, const char*& name, char* par);
+
+ void TestTimeZoneRoundTrip(void);
+ void TestTimeRoundTrip(void);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _TIMEZONEFORMATTEST_
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzoffloc.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tzoffloc.cpp
new file mode 100644
index 00000000000..1c4c5848347
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzoffloc.cpp
@@ -0,0 +1,329 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "tzoffloc.h"
+
+#include "unicode/ucal.h"
+#include "unicode/timezone.h"
+#include "unicode/calendar.h"
+#include "unicode/dtrule.h"
+#include "unicode/tzrule.h"
+#include "unicode/rbtz.h"
+#include "unicode/simpletz.h"
+#include "unicode/tzrule.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/gregocal.h"
+
+void
+TimeZoneOffsetLocalTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) {
+ logln("TestSuite TimeZoneOffsetLocalTest");
+ }
+ switch (index) {
+ TESTCASE(0, TestGetOffsetAroundTransition);
+ default: name = ""; break;
+ }
+}
+
+/*
+ * Testing getOffset APIs around rule transition by local standard/wall time.
+ */
+void
+TimeZoneOffsetLocalTest::TestGetOffsetAroundTransition() {
+ const int32_t NUM_DATES = 10;
+ const int32_t NUM_TIMEZONES = 3;
+
+ const int32_t HOUR = 60*60*1000;
+ const int32_t MINUTE = 60*1000;
+
+ const int32_t DATES[NUM_DATES][6] = {
+ {2006, UCAL_APRIL, 2, 1, 30, 1*HOUR+30*MINUTE},
+ {2006, UCAL_APRIL, 2, 2, 00, 2*HOUR},
+ {2006, UCAL_APRIL, 2, 2, 30, 2*HOUR+30*MINUTE},
+ {2006, UCAL_APRIL, 2, 3, 00, 3*HOUR},
+ {2006, UCAL_APRIL, 2, 3, 30, 3*HOUR+30*MINUTE},
+ {2006, UCAL_OCTOBER, 29, 0, 30, 0*HOUR+30*MINUTE},
+ {2006, UCAL_OCTOBER, 29, 1, 00, 1*HOUR},
+ {2006, UCAL_OCTOBER, 29, 1, 30, 1*HOUR+30*MINUTE},
+ {2006, UCAL_OCTOBER, 29, 2, 00, 2*HOUR},
+ {2006, UCAL_OCTOBER, 29, 2, 30, 2*HOUR+30*MINUTE},
+ };
+
+ // Expected offsets by int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ // uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
+ const int32_t OFFSETS1[NUM_DATES] = {
+ // April 2, 2006
+ -8*HOUR,
+ -7*HOUR,
+ -7*HOUR,
+ -7*HOUR,
+ -7*HOUR,
+
+ // October 29, 2006
+ -7*HOUR,
+ -8*HOUR,
+ -8*HOUR,
+ -8*HOUR,
+ -8*HOUR,
+ };
+
+ // Expected offsets by void getOffset(UDate date, UBool local, int32_t& rawOffset,
+ // int32_t& dstOffset, UErrorCode& ec) with local=TRUE
+ // or void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ // int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
+ // nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
+ const int32_t OFFSETS2[NUM_DATES][2] = {
+ // April 2, 2006
+ {-8*HOUR, 0},
+ {-8*HOUR, 0},
+ {-8*HOUR, 0},
+ {-8*HOUR, 1*HOUR},
+ {-8*HOUR, 1*HOUR},
+
+ // Oct 29, 2006
+ {-8*HOUR, 1*HOUR},
+ {-8*HOUR, 0},
+ {-8*HOUR, 0},
+ {-8*HOUR, 0},
+ {-8*HOUR, 0},
+ };
+
+ // Expected offsets by void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt,
+ // int32_t duplicatedTimeOpt, int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
+ // nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
+ const int32_t OFFSETS3[][2] = {
+ // April 2, 2006
+ {-8*HOUR, 0},
+ {-8*HOUR, 1*HOUR},
+ {-8*HOUR, 1*HOUR},
+ {-8*HOUR, 1*HOUR},
+ {-8*HOUR, 1*HOUR},
+
+ // October 29, 2006
+ {-8*HOUR, 1*HOUR},
+ {-8*HOUR, 1*HOUR},
+ {-8*HOUR, 1*HOUR},
+ {-8*HOUR, 0},
+ {-8*HOUR, 0},
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ int32_t rawOffset, dstOffset;
+ TimeZone* utc = TimeZone::createTimeZone("UTC");
+ Calendar* cal = Calendar::createInstance(*utc, status);
+ if (U_FAILURE(status)) {
+ errln("Calendar::createInstance failed");
+ return;
+ }
+ cal->clear();
+
+ // Set up TimeZone objects - OlsonTimeZone, SimpleTimeZone and RuleBasedTimeZone
+ BasicTimeZone *TESTZONES[NUM_TIMEZONES];
+
+ TESTZONES[0] = (BasicTimeZone*)TimeZone::createTimeZone("America/Los_Angeles");
+ TESTZONES[1] = new SimpleTimeZone(-8*HOUR, "Simple Pacific Time",
+ UCAL_APRIL, 1, UCAL_SUNDAY, 2*HOUR,
+ UCAL_OCTOBER, -1, UCAL_SUNDAY, 2*HOUR, status);
+ if (U_FAILURE(status)) {
+ errln("SimpleTimeZone constructor failed");
+ return;
+ }
+
+ InitialTimeZoneRule *ir = new InitialTimeZoneRule(
+ "Pacific Standard Time", // Initial time Name
+ -8*HOUR, // Raw offset
+ 0*HOUR); // DST saving amount
+
+ RuleBasedTimeZone *rbPT = new RuleBasedTimeZone("Rule based Pacific Time", ir);
+
+ DateTimeRule *dtr;
+ AnnualTimeZoneRule *atzr;
+ const int32_t STARTYEAR = 2000;
+
+ dtr = new DateTimeRule(UCAL_APRIL, 1, UCAL_SUNDAY,
+ 2*HOUR, DateTimeRule::WALL_TIME); // 1st Sunday in April, at 2AM wall time
+ atzr = new AnnualTimeZoneRule("Pacific Daylight Time",
+ -8*HOUR /* rawOffset */, 1*HOUR /* dstSavings */, dtr,
+ STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
+ rbPT->addTransitionRule(atzr, status);
+ if (U_FAILURE(status)) {
+ errln("Could not add DST start rule to the RuleBasedTimeZone rbPT");
+ return;
+ }
+
+ dtr = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SUNDAY,
+ 2*HOUR, DateTimeRule::WALL_TIME); // last Sunday in October, at 2AM wall time
+ atzr = new AnnualTimeZoneRule("Pacific Standard Time",
+ -8*HOUR /* rawOffset */, 0 /* dstSavings */, dtr,
+ STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
+ rbPT->addTransitionRule(atzr, status);
+ if (U_FAILURE(status)) {
+ errln("Could not add STD start rule to the RuleBasedTimeZone rbPT");
+ return;
+ }
+
+ rbPT->complete(status);
+ if (U_FAILURE(status)) {
+ errln("complete() failed for RuleBasedTimeZone rbPT");
+ return;
+ }
+
+ TESTZONES[2] = rbPT;
+
+ // Calculate millis
+ UDate MILLIS[NUM_DATES];
+ for (int32_t i = 0; i < NUM_DATES; i++) {
+ cal->clear();
+ cal->set(DATES[i][0], DATES[i][1], DATES[i][2], DATES[i][3], DATES[i][4]);
+ MILLIS[i] = cal->getTime(status);
+ if (U_FAILURE(status)) {
+ errln("cal->getTime failed");
+ return;
+ }
+ }
+
+ SimpleDateFormat df(UnicodeString("yyyy-MM-dd HH:mm:ss"), status);
+ if (U_FAILURE(status)) {
+ errln("Failed to initialize a SimpleDateFormat");
+ }
+ df.setTimeZone(*utc);
+ UnicodeString dateStr;
+
+ // Test getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
+ // uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
+ for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
+ for (int32_t d = 0; d < NUM_DATES; d++) {
+ status = U_ZERO_ERROR;
+ int32_t offset = TESTZONES[i]->getOffset(GregorianCalendar::AD, DATES[d][0], DATES[d][1], DATES[d][2],
+ UCAL_SUNDAY, DATES[d][5], status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"getOffset(era,year,month,day,dayOfWeek,millis,status) failed for TESTZONES[" + i + "]");
+ } else if (offset != OFFSETS1[d]) {
+ dateStr.remove();
+ df.format(MILLIS[d], dateStr);
+ errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ + dateStr + "(standard) - Got: " + offset + " Expected: " + OFFSETS1[d]);
+ }
+ }
+ }
+
+ // Test getOffset(UDate date, UBool local, int32_t& rawOffset,
+ // int32_t& dstOffset, UErrorCode& ec) with local = TRUE
+ for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
+ for (int32_t m = 0; m < NUM_DATES; m++) {
+ status = U_ZERO_ERROR;
+ TESTZONES[i]->getOffset(MILLIS[m], TRUE, rawOffset, dstOffset, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"getOffset(date,local,rawOfset,dstOffset,ec) failed for TESTZONES[" + i + "]");
+ } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
+ dateStr.remove();
+ df.format(MILLIS[m], dateStr);
+ errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ + dateStr + "(wall) - Got: "
+ + rawOffset + "/" + dstOffset
+ + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
+ }
+ }
+ }
+
+ // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
+ // with nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
+ for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
+ for (int m = 0; m < NUM_DATES; m++) {
+ status = U_ZERO_ERROR;
+ TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kStandard, BasicTimeZone::kStandard,
+ rawOffset, dstOffset, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"getOffsetFromLocal with kStandard/kStandard failed for TESTZONES[" + i + "]");
+ } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
+ dateStr.remove();
+ df.format(MILLIS[m], dateStr);
+ errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ + dateStr + "(wall/kStandard/kStandard) - Got: "
+ + rawOffset + "/" + dstOffset
+ + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
+ }
+ }
+ }
+
+ // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
+ // with nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
+ for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
+ for (int m = 0; m < NUM_DATES; m++) {
+ status = U_ZERO_ERROR;
+ TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kDaylight, BasicTimeZone::kDaylight,
+ rawOffset, dstOffset, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"getOffsetFromLocal with kDaylight/kDaylight failed for TESTZONES[" + i + "]");
+ } else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) {
+ dateStr.remove();
+ df.format(MILLIS[m], dateStr);
+ errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ + dateStr + "(wall/kDaylight/kDaylight) - Got: "
+ + rawOffset + "/" + dstOffset
+ + " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]);
+ }
+ }
+ }
+
+ // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
+ // with nonExistingTimeOpt=kFormer/duplicatedTimeOpt=kLatter
+ for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
+ for (int m = 0; m < NUM_DATES; m++) {
+ status = U_ZERO_ERROR;
+ TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kFormer, BasicTimeZone::kLatter,
+ rawOffset, dstOffset, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"getOffsetFromLocal with kFormer/kLatter failed for TESTZONES[" + i + "]");
+ } else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
+ dateStr.remove();
+ df.format(MILLIS[m], dateStr);
+ errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ + dateStr + "(wall/kFormer/kLatter) - Got: "
+ + rawOffset + "/" + dstOffset
+ + " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
+ }
+ }
+ }
+
+ // Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
+ // int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
+ // with nonExistingTimeOpt=kLatter/duplicatedTimeOpt=kFormer
+ for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
+ for (int m = 0; m < NUM_DATES; m++) {
+ status = U_ZERO_ERROR;
+ TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kLatter, BasicTimeZone::kFormer,
+ rawOffset, dstOffset, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"getOffsetFromLocal with kLatter/kFormer failed for TESTZONES[" + i + "]");
+ } else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) {
+ dateStr.remove();
+ df.format(MILLIS[m], dateStr);
+ errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ + dateStr + "(wall/kLatter/kFormer) - Got: "
+ + rawOffset + "/" + dstOffset
+ + " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]);
+ }
+ }
+ }
+
+ for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
+ delete TESTZONES[i];
+ }
+ delete utc;
+ delete cal;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzoffloc.h b/Build/source/libs/icu/icu-xetex/test/intltest/tzoffloc.h
new file mode 100644
index 00000000000..7d8fa235c66
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzoffloc.h
@@ -0,0 +1,26 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef _TIMEZONEOFFSETLOCALTEST_
+#define _TIMEZONEOFFSETLOCALTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "intltest.h"
+
+class TimeZoneOffsetLocalTest : public IntlTest {
+ // IntlTest override
+ void runIndexedTest(int32_t index, UBool exec, const char*& name, char* par);
+
+ void TestGetOffsetAroundTransition(void);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _TIMEZONEOFFSETLOCALTEST_
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzregts.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tzregts.cpp
new file mode 100644
index 00000000000..b549b83c16a
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzregts.cpp
@@ -0,0 +1,1219 @@
+/********************************************************************
+ * Copyright (c) 1997-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/simpletz.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/strenum.h"
+#include "tzregts.h"
+#include "calregts.h"
+#include "cmemory.h"
+
+// *****************************************************************************
+// class TimeZoneRegressionTest
+// *****************************************************************************
+/* length of an array */
+#define ARRAY_LENGTH(array) (sizeof(array)/sizeof(array[0]))
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
+
+void
+TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest");
+ switch (index) {
+
+ CASE(0, Test4052967);
+ CASE(1, Test4073209);
+ CASE(2, Test4073215);
+ CASE(3, Test4084933);
+ CASE(4, Test4096952);
+ CASE(5, Test4109314);
+ CASE(6, Test4126678);
+ CASE(7, Test4151406);
+ CASE(8, Test4151429);
+ CASE(9, Test4154537);
+ CASE(10, Test4154542);
+ CASE(11, Test4154650);
+ CASE(12, Test4154525);
+ CASE(13, Test4162593);
+ CASE(14, TestJ186);
+ CASE(15, TestJ449);
+ CASE(16, TestJDK12API);
+ CASE(17, Test4176686);
+ CASE(18, Test4184229);
+ default: name = ""; break;
+ }
+}
+
+UBool
+TimeZoneRegressionTest::failure(UErrorCode status, const char* msg)
+{
+ if(U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * @bug 4052967
+ */
+void TimeZoneRegressionTest:: Test4052967() {
+ // {sfb} not applicable in C++ ?
+ /*logln("*** CHECK TIMEZONE AGAINST HOST OS SETTING ***");
+ logln("user.timezone:" + System.getProperty("user.timezone", "<not set>"));
+ logln(new Date().toString());
+ logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");*/
+}
+
+/**
+ * @bug 4073209
+ */
+void TimeZoneRegressionTest:: Test4073209() {
+ TimeZone *z1 = TimeZone::createTimeZone("PST");
+ TimeZone *z2 = TimeZone::createTimeZone("PST");
+ if (z1 == z2)
+ errln("Fail: TimeZone should return clones");
+ delete z1;
+ delete z2;
+}
+
+UDate TimeZoneRegressionTest::findTransitionBinary(const SimpleTimeZone& tz, UDate min, UDate max) {
+ UErrorCode status = U_ZERO_ERROR;
+ UBool startsInDST = tz.inDaylightTime(min, status);
+ if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
+ if (tz.inDaylightTime(max, status) == startsInDST) {
+ logln((UnicodeString)"Error: inDaylightTime() != " + ((!startsInDST)?"TRUE":"FALSE"));
+ return 0;
+ }
+ if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
+ while ((max - min) > 100) { // Min accuracy in ms
+ UDate mid = (min + max) / 2;
+ if (tz.inDaylightTime(mid, status) == startsInDST) {
+ min = mid;
+ } else {
+ max = mid;
+ }
+ if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
+ }
+ return (min + max) / 2;
+}
+
+UDate TimeZoneRegressionTest::findTransitionStepwise(const SimpleTimeZone& tz, UDate min, UDate max) {
+ UErrorCode status = U_ZERO_ERROR;
+ UBool startsInDST = tz.inDaylightTime(min, status);
+ if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
+ while (min < max) {
+ if (tz.inDaylightTime(min, status) != startsInDST) {
+ return min;
+ }
+ if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0;
+ min += (UDate)24*60*60*1000; // one day
+ }
+ return 0;
+}
+
+/**
+ * @bug 4073215
+ */
+// {sfb} will this work using a Calendar?
+void TimeZoneRegressionTest:: Test4073215()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString str, str2;
+ SimpleTimeZone *z = new SimpleTimeZone(0, "GMT");
+ if (z->useDaylightTime())
+ errln("Fail: Fix test to start with non-DST zone");
+ z->setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status);
+ failure(status, "z->setStartRule()");
+ z->setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status);
+ failure(status, "z->setStartRule()");
+ if (!z->useDaylightTime())
+ errln("Fail: DST not active");
+
+ GregorianCalendar cal(1997, UCAL_JANUARY, 31, status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ return;
+ }
+ failure(status, "new GregorianCalendar");
+ cal.adoptTimeZone(z);
+
+ SimpleDateFormat sdf((UnicodeString)"E d MMM yyyy G HH:mm", status);
+ if(U_FAILURE(status)) {
+ errln("Error creating date format %s", u_errorName(status));
+ return;
+ }
+ sdf.setCalendar(cal);
+ failure(status, "new SimpleDateFormat");
+
+ UDate jan31, mar1, mar31;
+
+ UBool indt = z->inDaylightTime(jan31=cal.getTime(status), status);
+ failure(status, "inDaylightTime or getTime call on Jan 31");
+ if (indt) {
+ errln("Fail: Jan 31 inDaylightTime=TRUE, exp FALSE");
+ }
+ cal.set(1997, UCAL_MARCH, 1);
+ indt = z->inDaylightTime(mar1=cal.getTime(status), status);
+ failure(status, "inDaylightTime or getTime call on Mar 1");
+ if (!indt) {
+ UnicodeString str;
+ sdf.format(cal.getTime(status), str);
+ failure(status, "getTime");
+ errln((UnicodeString)"Fail: " + str + " inDaylightTime=FALSE, exp TRUE");
+ }
+ cal.set(1997, UCAL_MARCH, 31);
+ indt = z->inDaylightTime(mar31=cal.getTime(status), status);
+ failure(status, "inDaylightTime or getTime call on Mar 31");
+ if (indt) {
+ errln("Fail: Mar 31 inDaylightTime=TRUE, exp FALSE");
+ }
+
+ /*
+ cal.set(1997, Calendar::DECEMBER, 31);
+ UDate dec31 = cal.getTime(status);
+ failure(status, "getTime");
+ UDate trans = findTransitionStepwise(*z, jan31, dec31);
+ logln((UnicodeString)"Stepwise from " +
+ sdf.format(jan31, str.remove()) + "; transition at " +
+ (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE"));
+ trans = findTransitionStepwise(*z, mar1, dec31);
+ logln((UnicodeString)"Stepwise from " +
+ sdf.format(mar1, str.remove()) + "; transition at " +
+ (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE"));
+ trans = findTransitionStepwise(*z, mar31, dec31);
+ logln((UnicodeString)"Stepwise from " +
+ sdf.format(mar31, str.remove()) + "; transition at " +
+ (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE"));
+ */
+}
+
+/**
+ * @bug 4084933
+ * The expected behavior of TimeZone around the boundaries is:
+ * (Assume transition time of 2:00 AM)
+ * day of onset 1:59 AM STD = display name 1:59 AM ST
+ * 2:00 AM STD = display name 3:00 AM DT
+ * day of end 0:59 AM STD = display name 1:59 AM DT
+ * 1:00 AM STD = display name 1:00 AM ST
+ */
+void TimeZoneRegressionTest:: Test4084933() {
+ UErrorCode status = U_ZERO_ERROR;
+ TimeZone *tz = TimeZone::createTimeZone("PST");
+
+ int32_t offset1 = tz->getOffset(1,
+ 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status);
+ int32_t offset2 = tz->getOffset(1,
+ 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000)-1, status);
+
+ int32_t offset3 = tz->getOffset(1,
+ 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000), status);
+ int32_t offset4 = tz->getOffset(1,
+ 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000)-1, status);
+
+ /*
+ * The following was added just for consistency. It shows that going *to* Daylight
+ * Savings Time (PDT) does work at 2am.
+ */
+ int32_t offset5 = tz->getOffset(1,
+ 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000), status);
+ int32_t offset6 = tz->getOffset(1,
+ 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000)-1, status);
+ int32_t offset5a = tz->getOffset(1,
+ 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000), status);
+ int32_t offset6a = tz->getOffset(1,
+ 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000)-1, status);
+ int32_t offset7 = tz->getOffset(1,
+ 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000), status);
+ int32_t offset8 = tz->getOffset(1,
+ 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000)-1, status);
+ int32_t SToffset = (int32_t)(-8 * 60*60*1000L);
+ int32_t DToffset = (int32_t)(-7 * 60*60*1000L);
+
+#define ERR_IF_FAIL(x) if(x) { errln("FAIL: TimeZone misbehaving - %s", #x); }
+
+ ERR_IF_FAIL(U_FAILURE(status))
+ ERR_IF_FAIL(offset1 != SToffset)
+ ERR_IF_FAIL(offset2 != SToffset)
+ ERR_IF_FAIL(offset3 != SToffset)
+ ERR_IF_FAIL(offset4 != DToffset)
+ ERR_IF_FAIL(offset5 != DToffset)
+ ERR_IF_FAIL(offset6 != SToffset)
+ ERR_IF_FAIL(offset5a != DToffset)
+ ERR_IF_FAIL(offset6a != DToffset)
+ ERR_IF_FAIL(offset7 != SToffset)
+ ERR_IF_FAIL(offset8 != SToffset)
+
+#undef ERR_IF_FAIL
+
+ delete tz;
+}
+
+/**
+ * @bug 4096952
+ */
+void TimeZoneRegressionTest:: Test4096952() {
+ // {sfb} serialization not applicable
+/*
+ UnicodeString ZONES [] = { UnicodeString("GMT"), UnicodeString("MET"), UnicodeString("IST") };
+ UBool pass = TRUE;
+ //try {
+ for (int32_t i=0; i < ZONES.length; ++i) {
+ TimeZone *zone = TimeZone::createTimeZone(ZONES[i]);
+ UnicodeString id;
+ if (zone->getID(id) != ZONES[i])
+ errln("Fail: Test broken; zones not instantiating");
+
+ ByteArrayOutputStream baos;
+ ObjectOutputStream ostream =
+ new ObjectOutputStream(baos = new
+ ByteArrayOutputStream());
+ ostream.writeObject(zone);
+ ostream.close();
+ baos.close();
+ ObjectInputStream istream =
+ new ObjectInputStream(new
+ ByteArrayInputStream(baos.toByteArray()));
+ TimeZone frankenZone = (TimeZone) istream.readObject();
+ //logln("Zone: " + zone);
+ //logln("FrankenZone: " + frankenZone);
+ if (!zone.equals(frankenZone)) {
+ logln("TimeZone " + zone.getID() +
+ " not equal to serialized/deserialized one");
+ pass = false;
+ }
+ }
+ if (!pass) errln("Fail: TimeZone serialization/equality bug");
+ }
+ catch (IOException e) {
+ errln("Fail: " + e);
+ e.print32_tStackTrace();
+ }
+ catch (ClassNotFoundException e) {
+ errln("Fail: " + e);
+ e.print32_tStackTrace();
+ }
+*/
+}
+
+/**
+ * @bug 4109314
+ */
+void TimeZoneRegressionTest:: Test4109314() {
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar *testCal = (GregorianCalendar*)Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete testCal;
+ return;
+ }
+ failure(status, "Calendar::createInstance");
+ TimeZone *PST = TimeZone::createTimeZone("PST");
+ /*Object[] testData = {
+ PST, new Date(98,Calendar.APRIL,4,22,0), new Date(98, Calendar.APRIL, 5,6,0),
+ PST, new Date(98,Calendar.OCTOBER,24,22,0), new Date(98,Calendar.OCTOBER,25,6,0),
+ };*/
+ UDate testData [] = {
+ CalendarRegressionTest::makeDate(98,UCAL_APRIL,4,22,0),
+ CalendarRegressionTest::makeDate(98, UCAL_APRIL,5,6,0),
+ CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,24,22,0),
+ CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,25,6,0)
+ };
+ UBool pass = TRUE;
+ for (int32_t i = 0; i < 4; i+=2) {
+ //testCal->setTimeZone((TimeZone) testData[i]);
+ testCal->setTimeZone(*PST);
+ UDate t = testData[i];
+ UDate end = testData[i+1];
+ while(testCal->getTime(status) < end) {
+ testCal->setTime(t, status);
+ if ( ! checkCalendar314(testCal, PST))
+ pass = FALSE;
+ t += 60*60*1000.0;
+ }
+ }
+ if ( ! pass)
+ errln("Fail: TZ API inconsistent");
+
+ delete testCal;
+ delete PST;
+}
+
+UBool
+TimeZoneRegressionTest::checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ // GregorianCalendar testCal = (GregorianCalendar)aCal.clone();
+
+ int32_t tzOffset, tzRawOffset;
+ float tzOffsetFloat,tzRawOffsetFloat;
+ // Here is where the user made an error. They were passing in the value of
+ // the MILLSECOND field; you need to pass in the millis in the day in STANDARD
+ // time.
+ UDate millis = testCal->get(UCAL_MILLISECOND, status) +
+ 1000.0 * (testCal->get(UCAL_SECOND, status) +
+ 60.0 * (testCal->get(UCAL_MINUTE, status) +
+ 60.0 * (testCal->get(UCAL_HOUR_OF_DAY, status)))) -
+ testCal->get(UCAL_DST_OFFSET, status);
+
+ /* Fix up millis to be in range. ASSUME THAT WE ARE NOT AT THE
+ * BEGINNING OR END OF A MONTH. We must add this code because
+ * getOffset() has been changed to be more strict about the parameters
+ * it receives -- it turns out that this test was passing in illegal
+ * values. */
+ int32_t date = testCal->get(UCAL_DATE, status);
+ int32_t dow = testCal->get(UCAL_DAY_OF_WEEK, status);
+ while(millis < 0) {
+ millis += U_MILLIS_PER_DAY;
+ --date;
+ dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 6) % 7);
+ }
+ while (millis >= U_MILLIS_PER_DAY) {
+ millis -= U_MILLIS_PER_DAY;
+ ++date;
+ dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 1) % 7);
+ }
+
+ tzOffset = testTZ->getOffset((uint8_t)testCal->get(UCAL_ERA, status),
+ testCal->get(UCAL_YEAR, status),
+ testCal->get(UCAL_MONTH, status),
+ date,
+ (uint8_t)dow,
+ (int32_t)millis,
+ status);
+ tzRawOffset = testTZ->getRawOffset();
+ tzOffsetFloat = (float)tzOffset/(float)3600000;
+ tzRawOffsetFloat = (float)tzRawOffset/(float)3600000;
+
+ UDate testDate = testCal->getTime(status);
+
+ UBool inDaylightTime = testTZ->inDaylightTime(testDate, status);
+ SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)"MM/dd/yyyy HH:mm", status);
+ sdf->setCalendar(*testCal);
+ UnicodeString inDaylightTimeString;
+
+ UBool passed;
+
+ if(inDaylightTime)
+ {
+ inDaylightTimeString = " DST ";
+ passed = (tzOffset == (tzRawOffset + 3600000));
+ }
+ else
+ {
+ inDaylightTimeString = " ";
+ passed = (tzOffset == tzRawOffset);
+ }
+
+ UnicodeString output;
+ FieldPosition pos(0);
+ output = testTZ->getID(output) + " " + sdf->format(testDate, output, pos) +
+ " Offset(" + tzOffsetFloat + ")" +
+ " RawOffset(" + tzRawOffsetFloat + ")" +
+ " " + millis/(float)3600000 + " " +
+ inDaylightTimeString;
+
+ if (passed)
+ output += " ";
+ else
+ output += "ERROR";
+
+ if (passed)
+ logln(output);
+ else
+ errln(output);
+
+ delete sdf;
+ return passed;
+}
+
+/**
+ * @bug 4126678
+ * CANNOT REPRODUDE
+ *
+ * Yet another _alleged_ bug in TimeZone::getOffset(), a method that never
+ * should have been made public. It's simply too hard to use correctly.
+ *
+ * The original test code failed to do the following:
+ * (1) Call Calendar::setTime() before getting the fields!
+ * (2) Use the right millis (as usual) for getOffset(); they were passing
+ * in the MILLIS field, instead of the STANDARD MILLIS IN DAY.
+ * When you fix these two problems, the test passes, as expected.
+ */
+void TimeZoneRegressionTest:: Test4126678()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar *cal = Calendar::createInstance(status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete cal;
+ return;
+ }
+ failure(status, "Calendar::createInstance");
+ TimeZone *tz = TimeZone::createTimeZone("PST");
+ cal->adoptTimeZone(tz);
+
+ cal->set(1998 - 1900, UCAL_APRIL, 5, 10, 0);
+ //Date dt = new Date(1998-1900, Calendar::APRIL, 5, 10, 0);
+
+ if (! tz->useDaylightTime() || U_FAILURE(status))
+ errln("We're not in Daylight Savings Time and we should be.\n");
+
+ //cal.setTime(dt);
+ int32_t era = cal->get(UCAL_ERA, status);
+ int32_t year = cal->get(UCAL_YEAR, status);
+ int32_t month = cal->get(UCAL_MONTH, status);
+ int32_t day = cal->get(UCAL_DATE, status);
+ int32_t dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status);
+ int32_t millis = cal->get(UCAL_MILLISECOND, status) +
+ (cal->get(UCAL_SECOND, status) +
+ (cal->get(UCAL_MINUTE, status) +
+ (cal->get(UCAL_HOUR, status) * 60) * 60) * 1000) -
+ cal->get(UCAL_DST_OFFSET, status);
+
+ failure(status, "cal->get");
+ int32_t offset = tz->getOffset((uint8_t)era, year, month, day, (uint8_t)dayOfWeek, millis, status);
+ int32_t raw_offset = tz->getRawOffset();
+ /* Because of better historical timezone support based on Olson data,
+ * DST is not observed in year 98. Thus, the expected result is changed.
+ * As of Mar 2007, ICU timezone transition data is represented by 32-bit.
+ * When we support 64-bit Olson transition data, the actual offset in
+ * AD 98 for America/Los_Angeles will be changed again (-7:52:58). Until
+ * then, expected result is offset == raw_offset. -Yoshito
+ */
+ /*
+ if (offset == raw_offset)
+ errln("Offsets should not match when in DST");
+ */
+ /* TODO: When ICU support the Olson LMT offset for America/Los_Angeles, we need to update
+ * the reference data.
+ */
+ if (offset != raw_offset)
+ errln("Offsets should match");
+
+ delete cal;
+}
+
+/**
+ * @bug 4151406
+ * TimeZone::getAvailableIDs(int32_t) throws exception for certain values,
+ * due to a faulty constant in TimeZone::java.
+ */
+void TimeZoneRegressionTest:: Test4151406() {
+ int32_t max = 0;
+ for (int32_t h=-28; h<=30; ++h) {
+ // h is in half-hours from GMT; rawoffset is in millis
+ int32_t rawoffset = h * 1800000;
+ int32_t hh = (h<0) ? -h : h;
+ UnicodeString hname = UnicodeString((h<0) ? "GMT-" : "GMT+") +
+ ((hh/2 < 10) ? "0" : "") +
+ (hh/2) + ':' +
+ ((hh%2==0) ? "00" : "30");
+ //try {
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t count;
+ StringEnumeration* ids = TimeZone::createEnumeration(rawoffset);
+ count = ids->count(ec);
+ if (count> max)
+ max = count;
+ if (count > 0) {
+ logln(hname + ' ' + (UnicodeString)count + (UnicodeString)" e.g. " + *ids->snext(ec));
+ } else {
+ logln(hname + ' ' + count);
+ }
+ // weiv 11/27/2002: why uprv_free? This should be a delete
+ delete ids;
+ //delete [] ids;
+ //uprv_free(ids);
+ /*} catch (Exception e) {
+ errln(hname + ' ' + "Fail: " + e);
+ }*/
+ }
+ logln("Maximum zones per offset = %d", max);
+}
+
+/**
+ * @bug 4151429
+ */
+void TimeZoneRegressionTest:: Test4151429() {
+ // {sfb} silly test in C++, since we are using an enum and not an int
+ //try {
+ /*TimeZone *tz = TimeZone::createTimeZone("GMT");
+ UnicodeString name;
+ tz->getDisplayName(TRUE, TimeZone::LONG,
+ Locale.getDefault(), name);
+ errln("IllegalArgumentException not thrown by TimeZone::getDisplayName()");*/
+ //} catch(IllegalArgumentException e) {}
+}
+
+/**
+ * @bug 4154537
+ * SimpleTimeZone::hasSameRules() doesn't work for zones with no DST
+ * and different DST parameters.
+ */
+void TimeZoneRegressionTest:: Test4154537() {
+ UErrorCode status = U_ZERO_ERROR;
+ // tz1 and tz2 have no DST and different rule parameters
+ SimpleTimeZone *tz1 = new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0, status);
+ SimpleTimeZone *tz2 = new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0, status);
+ // tza and tzA have the same rule params
+ SimpleTimeZone *tza = new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0, status);
+ SimpleTimeZone *tzA = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0, status);
+ // tzb differs from tza
+ SimpleTimeZone *tzb = new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0, status);
+
+ if(U_FAILURE(status))
+ errln("Couldn't create TimeZones");
+
+ if (tz1->useDaylightTime() || tz2->useDaylightTime() ||
+ !tza->useDaylightTime() || !tzA->useDaylightTime() ||
+ !tzb->useDaylightTime()) {
+ errln("Test is broken -- rewrite it");
+ }
+ if (!tza->hasSameRules(*tzA) || tza->hasSameRules(*tzb)) {
+ errln("Fail: hasSameRules() broken for zones with rules");
+ }
+ if (!tz1->hasSameRules(*tz2)) {
+ errln("Fail: hasSameRules() returns false for zones without rules");
+ //errln("zone 1 = " + tz1);
+ //errln("zone 2 = " + tz2);
+ }
+
+ delete tz1;
+ delete tz2;
+ delete tza;
+ delete tzA;
+ delete tzb;
+}
+
+/**
+ * @bug 4154542
+ * SimpleTimeZOne constructors, setStartRule(), and setEndRule() don't
+ * check for out-of-range arguments.
+ */
+void TimeZoneRegressionTest:: Test4154542()
+{
+ const int32_t GOOD = 1;
+ const int32_t BAD = 0;
+
+ const int32_t GOOD_MONTH = UCAL_JANUARY;
+ const int32_t GOOD_DAY = 1;
+ const int32_t GOOD_DAY_OF_WEEK = UCAL_SUNDAY;
+ const int32_t GOOD_TIME = 0;
+
+ int32_t DATA [] = {
+ GOOD, INT32_MIN, 0, INT32_MAX, INT32_MIN,
+ GOOD, UCAL_JANUARY, -5, UCAL_SUNDAY, 0,
+ GOOD, UCAL_DECEMBER, 5, UCAL_SATURDAY, 24*60*60*1000,
+ BAD, UCAL_DECEMBER, 5, UCAL_SATURDAY, 24*60*60*1000+1,
+ BAD, UCAL_DECEMBER, 5, UCAL_SATURDAY, -1,
+ BAD, UCAL_JANUARY, -6, UCAL_SUNDAY, 0,
+ BAD, UCAL_DECEMBER, 6, UCAL_SATURDAY, 24*60*60*1000,
+ GOOD, UCAL_DECEMBER, 1, 0, 0,
+ GOOD, UCAL_DECEMBER, 31, 0, 0,
+ BAD, UCAL_APRIL, 31, 0, 0,
+ BAD, UCAL_DECEMBER, 32, 0, 0,
+ BAD, UCAL_JANUARY-1, 1, UCAL_SUNDAY, 0,
+ BAD, UCAL_DECEMBER+1, 1, UCAL_SUNDAY, 0,
+ GOOD, UCAL_DECEMBER, 31, -UCAL_SUNDAY, 0,
+ GOOD, UCAL_DECEMBER, 31, -UCAL_SATURDAY, 0,
+ BAD, UCAL_DECEMBER, 32, -UCAL_SATURDAY, 0,
+ BAD, UCAL_DECEMBER, -32, -UCAL_SATURDAY, 0,
+ BAD, UCAL_DECEMBER, 31, -UCAL_SATURDAY-1, 0,
+ };
+ SimpleTimeZone *zone = new SimpleTimeZone(0, "Z");
+ for (int32_t i=0; i < 18*5; i+=5) {
+ UBool shouldBeGood = (DATA[i] == GOOD);
+ int32_t month = DATA[i+1];
+ int32_t day = DATA[i+2];
+ int32_t dayOfWeek = DATA[i+3];
+ int32_t time = DATA[i+4];
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ //Exception ex = null;
+ //try {
+ zone->setStartRule(month, day, dayOfWeek, time, status);
+ //} catch (IllegalArgumentException e) {
+ // ex = e;
+ //}
+ if (U_SUCCESS(status) != shouldBeGood) {
+ errln(UnicodeString("setStartRule(month=") + month + ", day=" + day +
+ ", dayOfWeek=" + dayOfWeek + ", time=" + time +
+ (shouldBeGood ? (") should work")
+ : ") should fail but doesn't"));
+ }
+
+ //ex = null;
+ //try {
+ status = U_ZERO_ERROR;
+ zone->setEndRule(month, day, dayOfWeek, time, status);
+ //} catch (IllegalArgumentException e) {
+ // ex = e;
+ //}
+ if (U_SUCCESS(status) != shouldBeGood) {
+ errln(UnicodeString("setEndRule(month=") + month + ", day=" + day +
+ ", dayOfWeek=" + dayOfWeek + ", time=" + time +
+ (shouldBeGood ? (") should work")
+ : ") should fail but doesn't"));
+ }
+
+ //ex = null;
+ //try {
+ // {sfb} need to look into ctor problems! (UErrorCode vs. dst signature confusion)
+ status = U_ZERO_ERROR;
+ SimpleTimeZone *temp = new SimpleTimeZone(0, "Z",
+ (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,
+ (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK,
+ GOOD_TIME,status);
+ //} catch (IllegalArgumentException e) {
+ // ex = e;
+ //}
+ if (U_SUCCESS(status) != shouldBeGood) {
+ errln(UnicodeString("SimpleTimeZone(month=") + month + ", day=" + day +
+ ", dayOfWeek=" + dayOfWeek + ", time=" + time +
+ (shouldBeGood ? (", <end>) should work")// + ex)
+ : ", <end>) should fail but doesn't"));
+ }
+
+ delete temp;
+ //ex = null;
+ //try {
+ status = U_ZERO_ERROR;
+ temp = new SimpleTimeZone(0, "Z",
+ (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK,
+ GOOD_TIME,
+ (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,status);
+ //} catch (IllegalArgumentException e) {
+ // ex = e;
+ //}
+ if (U_SUCCESS(status) != shouldBeGood) {
+ errln(UnicodeString("SimpleTimeZone(<start>, month=") + month + ", day=" + day +
+ ", dayOfWeek=" + dayOfWeek + ", time=" + time +
+ (shouldBeGood ? (") should work")// + ex)
+ : ") should fail but doesn't"));
+ }
+ delete temp;
+ }
+ delete zone;
+}
+
+
+/**
+ * @bug 4154525
+ * SimpleTimeZone accepts illegal DST savings values. These values
+ * must be non-zero. There is no upper limit at this time.
+ */
+void
+TimeZoneRegressionTest::Test4154525()
+{
+ const int32_t GOOD = 1, BAD = 0;
+
+ int32_t DATA [] = {
+ 1, GOOD,
+ 0, BAD,
+ -1, BAD,
+ 60*60*1000, GOOD,
+ INT32_MIN, BAD,
+ // Integer.MAX_VALUE, ?, // no upper limit on DST savings at this time
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ for(int32_t i = 0; i < 10; i+=2) {
+ int32_t savings = DATA[i];
+ UBool valid = DATA[i+1] == GOOD;
+ UnicodeString method;
+ for(int32_t j=0; j < 2; ++j) {
+ SimpleTimeZone *z=NULL;
+ switch (j) {
+ case 0:
+ method = "constructor";
+ z = new SimpleTimeZone(0, "id",
+ UCAL_JANUARY, 1, 0, 0,
+ UCAL_MARCH, 1, 0, 0,
+ savings, status); // <- what we're interested in
+ break;
+ case 1:
+ method = "setDSTSavings()";
+ z = new SimpleTimeZone(0, "GMT");
+ z->setDSTSavings(savings, status);
+ break;
+ }
+
+ if(U_FAILURE(status)) {
+ if(valid) {
+ errln(UnicodeString("Fail: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status));
+ }
+ else {
+ logln(UnicodeString("Pass: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status));
+ }
+ }
+ else {
+ if(valid) {
+ logln(UnicodeString("Pass: DST savings of ") + savings + " accepted by " + method);
+ }
+ else {
+ errln(UnicodeString("Fail: DST savings of ") + savings + " accepted by " + method);
+ }
+ }
+ status = U_ZERO_ERROR;
+ delete z;
+ }
+ }
+}
+
+/**
+ * @bug 4154650
+ * SimpleTimeZone.getOffset accepts illegal arguments.
+ */
+void
+TimeZoneRegressionTest::Test4154650()
+{
+ const int32_t GOOD = 1, BAD = 0;
+ const int32_t GOOD_ERA = GregorianCalendar::AD, GOOD_YEAR = 1998, GOOD_MONTH = UCAL_AUGUST;
+ const int32_t GOOD_DAY = 2, GOOD_DOW = UCAL_SUNDAY, GOOD_TIME = 16*3600000;
+
+ int32_t DATA []= {
+ GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
+
+ GOOD, GregorianCalendar::BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
+ GOOD, GregorianCalendar::AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
+ BAD, GregorianCalendar::BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
+ BAD, GregorianCalendar::AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
+
+ GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME,
+ GOOD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME,
+ BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
+ BAD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
+
+ GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 1, GOOD_DOW, GOOD_TIME,
+ GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 31, GOOD_DOW, GOOD_TIME,
+ BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 0, GOOD_DOW, GOOD_TIME,
+ BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 32, GOOD_DOW, GOOD_TIME,
+
+ GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY, GOOD_TIME,
+ GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY, GOOD_TIME,
+ BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY-1, GOOD_TIME,
+ BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY+1, GOOD_TIME,
+
+ GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0,
+ GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1,
+ BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1,
+ BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000,
+ };
+
+ int32_t dataLen = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+
+ UErrorCode status = U_ZERO_ERROR;
+ TimeZone *tz = TimeZone::createDefault();
+ for(int32_t i = 0; i < dataLen; i += 7) {
+ UBool good = DATA[i] == GOOD;
+ //IllegalArgumentException e = null;
+ //try {
+ /*int32_t offset = */
+ tz->getOffset((uint8_t)DATA[i+1], DATA[i+2], DATA[i+3],
+ DATA[i+4], (uint8_t)DATA[i+5], DATA[i+6], status);
+ //} catch (IllegalArgumentException ex) {
+ // e = ex;
+ //}
+ if(good != U_SUCCESS(status)) {
+ UnicodeString errMsg;
+ if (good) {
+ errMsg = (UnicodeString(") threw ") + u_errorName(status));
+ }
+ else {
+ errMsg = UnicodeString(") accepts invalid args", "");
+ }
+ errln(UnicodeString("Fail: getOffset(") +
+ DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " +
+ DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] +
+ errMsg);
+ }
+ status = U_ZERO_ERROR; // reset
+ }
+ delete tz;
+}
+
+/**
+ * @bug 4162593
+ * TimeZone broken at midnight. The TimeZone code fails to handle
+ * transitions at midnight correctly.
+ */
+void
+TimeZoneRegressionTest::Test4162593()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *fmt = new SimpleDateFormat("z", Locale::getUS(), status);
+ if(U_FAILURE(status)) {
+ errln("Error creating calendar %s", u_errorName(status));
+ delete fmt;
+ return;
+ }
+ const int32_t ONE_HOUR = 60*60*1000;
+
+ SimpleTimeZone *asuncion = new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/,
+ UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR,
+ UCAL_MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status);
+
+ /* Zone
+ * Starting time
+ * Transition expected between start+1H and start+2H
+ */
+ TimeZone *DATA_TZ [] = {
+ 0, 0, 0 };
+
+ int32_t DATA_INT [] [5] = {
+ // These years must be AFTER the Gregorian cutover
+ {1998, UCAL_SEPTEMBER, 30, 22, 0},
+ {2000, UCAL_FEBRUARY, 28, 22, 0},
+ {2000, UCAL_FEBRUARY, 29, 22, 0},
+ };
+
+ UBool DATA_BOOL [] = {
+ TRUE,
+ FALSE,
+ TRUE,
+ };
+
+ UnicodeString zone [4];// = new String[4];
+ DATA_TZ[0] =
+ new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/,
+ UCAL_APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR,
+ UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status);
+ DATA_TZ[1] = asuncion; DATA_TZ[2] = asuncion;
+
+ for(int32_t j = 0; j < 3; j++) {
+ TimeZone *tz = (TimeZone*)DATA_TZ[j];
+ TimeZone::setDefault(*tz);
+ fmt->setTimeZone(*tz);
+
+ // Must construct the Date object AFTER setting the default zone
+ int32_t *p = (int32_t*)DATA_INT[j];
+ UDate d = CalendarRegressionTest::makeDate(p[0], p[1], p[2], p[3], p[4]);
+ UBool transitionExpected = DATA_BOOL[j];
+
+ UnicodeString temp;
+ logln(tz->getID(temp) + ":");
+ for (int32_t i = 0; i < 4; ++i) {
+ FieldPosition pos(0);
+ zone[i].remove();
+ zone[i] = fmt->format(d+ i*ONE_HOUR, zone[i], pos);
+ logln(UnicodeString("") + i + ": " + d + " / " + zone[i]);
+ //d += (double) ONE_HOUR;
+ }
+ if(zone[0] == zone[1] &&
+ (zone[1] == zone[2]) != transitionExpected &&
+ zone[2] == zone[3]) {
+ logln(UnicodeString("Ok: transition ") + transitionExpected);
+ }
+ else {
+ errln("Fail: boundary transition incorrect");
+ }
+ }
+ delete fmt;
+ delete asuncion;
+ delete DATA_TZ[0];
+}
+
+ /**
+ * getDisplayName doesn't work with unusual savings/offsets.
+ */
+void TimeZoneRegressionTest::Test4176686() {
+ // Construct a zone that does not observe DST but
+ // that does have a DST savings (which should be ignored).
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t offset = 90 * 60000; // 1:30
+ SimpleTimeZone* z1 = new SimpleTimeZone(offset, "_std_zone_");
+ z1->setDSTSavings(45 * 60000, status); // 0:45
+
+ // Construct a zone that observes DST for the first 6 months.
+ SimpleTimeZone* z2 = new SimpleTimeZone(offset, "_dst_zone_");
+ z2->setDSTSavings(45 * 60000, status); // 0:45
+ z2->setStartRule(UCAL_JANUARY, 1, 0, status);
+ z2->setEndRule(UCAL_JULY, 1, 0, status);
+
+ // Also check DateFormat
+ DateFormat* fmt1 = new SimpleDateFormat(UnicodeString("z"), status);
+ if(!assertSuccess("trying to construct", status))return;
+ fmt1->setTimeZone(*z1); // Format uses standard zone
+ DateFormat* fmt2 = new SimpleDateFormat(UnicodeString("z"), status);
+ if(!assertSuccess("trying to construct", status))return;
+ fmt2->setTimeZone(*z2); // Format uses DST zone
+ Calendar* tempcal = Calendar::createInstance(status);
+ tempcal->clear();
+ tempcal->set(1970, UCAL_FEBRUARY, 1);
+ UDate dst = tempcal->getTime(status); // Time in DST
+ tempcal->set(1970, UCAL_AUGUST, 1);
+ UDate std = tempcal->getTime(status); // Time in standard
+
+ // Description, Result, Expected Result
+ UnicodeString a,b,c,d,e,f,g,h,i,j,k,l;
+ UnicodeString DATA[] = {
+ "z1->getDisplayName(false, SHORT)/std zone",
+ z1->getDisplayName(FALSE, TimeZone::SHORT, a), "GMT+01:30",
+ "z1->getDisplayName(false, LONG)/std zone",
+ z1->getDisplayName(FALSE, TimeZone::LONG, b), "GMT+01:30",
+ "z1->getDisplayName(true, SHORT)/std zone",
+ z1->getDisplayName(TRUE, TimeZone::SHORT, c), "GMT+01:30",
+ "z1->getDisplayName(true, LONG)/std zone",
+ z1->getDisplayName(TRUE, TimeZone::LONG, d ), "GMT+01:30",
+ "z2->getDisplayName(false, SHORT)/dst zone",
+ z2->getDisplayName(FALSE, TimeZone::SHORT, e), "GMT+01:30",
+ "z2->getDisplayName(false, LONG)/dst zone",
+ z2->getDisplayName(FALSE, TimeZone::LONG, f ), "GMT+01:30",
+ "z2->getDisplayName(true, SHORT)/dst zone",
+ z2->getDisplayName(TRUE, TimeZone::SHORT, g), "GMT+02:15",
+ "z2->getDisplayName(true, LONG)/dst zone",
+ z2->getDisplayName(TRUE, TimeZone::LONG, h ), "GMT+02:15",
+ "DateFormat.format(std)/std zone", fmt1->format(std, i), "GMT+01:30",
+ "DateFormat.format(dst)/std zone", fmt1->format(dst, j), "GMT+01:30",
+ "DateFormat.format(std)/dst zone", fmt2->format(std, k), "GMT+01:30",
+ "DateFormat.format(dst)/dst zone", fmt2->format(dst, l), "GMT+02:15",
+ };
+
+ for (int32_t idx=0; idx<(int32_t)ARRAY_LENGTH(DATA); idx+=3) {
+ if (DATA[idx+1]!=(DATA[idx+2])) {
+ errln("FAIL: " + DATA[idx] + " -> " + DATA[idx+1] + ", exp " + DATA[idx+2]);
+ }
+ }
+ delete z1;
+ delete z2;
+ delete fmt1;
+ delete fmt2;
+ delete tempcal;
+}
+
+/**
+ * Make sure setStartRule and setEndRule set the DST savings to nonzero
+ * if it was zero.
+ */
+void TimeZoneRegressionTest::TestJ186() {
+ UErrorCode status = U_ZERO_ERROR;
+ // NOTE: Setting the DST savings to zero is illegal, so we
+ // are limited in the testing we can do here. This is why
+ // lines marked //~ are commented out.
+ SimpleTimeZone z(0, "ID");
+ //~z.setDSTSavings(0, status); // Must do this!
+ z.setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status);
+ failure(status, "setStartRule()");
+ if (z.useDaylightTime()) {
+ errln("Fail: useDaylightTime true with start rule only");
+ }
+ //~if (z.getDSTSavings() != 0) {
+ //~ errln("Fail: dst savings != 0 with start rule only");
+ //~}
+ z.setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status);
+ failure(status, "setStartRule()");
+ if (!z.useDaylightTime()) {
+ errln("Fail: useDaylightTime false with rules set");
+ }
+ if (z.getDSTSavings() == 0) {
+ errln("Fail: dst savings == 0 with rules set");
+ }
+}
+
+/**
+ * Test to see if DateFormat understands zone equivalency groups. It
+ * might seem that this should be a DateFormat test, but it's really a
+ * TimeZone test -- the changes to DateFormat are minor.
+ *
+ * We use two known, stable zones that shouldn't change much over time
+ * -- America/Vancouver and America/Los_Angeles. However, they MAY
+ * change at some point -- if that happens, replace them with any two
+ * zones in an equivalency group where one zone has localized name
+ * data, and the other doesn't, in some locale.
+ */
+void TimeZoneRegressionTest::TestJ449() {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString str;
+
+ // Modify the following three as necessary. The two IDs must
+ // specify two zones in the same equivalency group. One must have
+ // locale data in 'loc'; the other must not.
+ const char* idWithLocaleData = "America/Los_Angeles";
+ const char* idWithoutLocaleData = "US/Pacific";
+ const Locale loc("en", "", "");
+
+ TimeZone *zoneWith = TimeZone::createTimeZone(idWithLocaleData);
+ TimeZone *zoneWithout = TimeZone::createTimeZone(idWithoutLocaleData);
+ // Make sure we got valid zones
+ if (zoneWith->getID(str) != UnicodeString(idWithLocaleData) ||
+ zoneWithout->getID(str) != UnicodeString(idWithoutLocaleData)) {
+ errln(UnicodeString("Fail: Unable to create zones - wanted ") + idWithLocaleData + ", got " + zoneWith->getID(str) + ", and wanted " + idWithoutLocaleData + " but got " + zoneWithout->getID(str));
+ } else {
+ GregorianCalendar calWith(*zoneWith, status);
+ GregorianCalendar calWithout(*zoneWithout, status);
+ SimpleDateFormat fmt("MMM d yyyy hh:mm a zzz", loc, status);
+ if (U_FAILURE(status)) {
+ errln("Fail: Unable to create GregorianCalendar/SimpleDateFormat");
+ } else {
+ UDate date = 0;
+ UnicodeString strWith, strWithout;
+ fmt.setCalendar(calWith);
+ fmt.format(date, strWith);
+ fmt.setCalendar(calWithout);
+ fmt.format(date, strWithout);
+ if (strWith == strWithout) {
+ logln((UnicodeString)"Ok: " + idWithLocaleData + " -> " +
+ strWith + "; " + idWithoutLocaleData + " -> " +
+ strWithout);
+ } else {
+ errln((UnicodeString)"FAIL: " + idWithLocaleData + " -> " +
+ strWith + "; " + idWithoutLocaleData + " -> " +
+ strWithout);
+ }
+ }
+ }
+
+ delete zoneWith;
+ delete zoneWithout;
+}
+
+// test new API for JDK 1.2 8/31 putback
+void
+TimeZoneRegressionTest::TestJDK12API()
+{
+ // TimeZone *pst = TimeZone::createTimeZone("PST");
+ // TimeZone *cst1 = TimeZone::createTimeZone("CST");
+ UErrorCode ec = U_ZERO_ERROR;
+ //d,-28800,3,1,-1,120,w,9,-1,1,120,w,60
+ TimeZone *pst = new SimpleTimeZone(-28800*U_MILLIS_PER_SECOND,
+ "PST",
+ 3,1,-1,120*U_MILLIS_PER_MINUTE,
+ SimpleTimeZone::WALL_TIME,
+ 9,-1,1,120*U_MILLIS_PER_MINUTE,
+ SimpleTimeZone::WALL_TIME,
+ 60*U_MILLIS_PER_MINUTE,ec);
+ //d,-21600,3,1,-1,120,w,9,-1,1,120,w,60
+ TimeZone *cst1 = new SimpleTimeZone(-21600*U_MILLIS_PER_SECOND,
+ "CST",
+ 3,1,-1,120*U_MILLIS_PER_MINUTE,
+ SimpleTimeZone::WALL_TIME,
+ 9,-1,1,120*U_MILLIS_PER_MINUTE,
+ SimpleTimeZone::WALL_TIME,
+ 60*U_MILLIS_PER_MINUTE,ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: SimpleTimeZone constructor");
+ return;
+ }
+
+ SimpleTimeZone *cst = 0;
+
+ if(cst1->getDynamicClassID() == SimpleTimeZone::getStaticClassID())
+ cst = (SimpleTimeZone*) cst1;
+
+ if(pst->hasSameRules(*cst)) {
+ errln("FAILURE: PST and CST have same rules");
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t offset1 = pst->getOffset(1,
+ 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status);
+ failure(status, "getOffset() failed");
+
+
+ int32_t offset2 = cst->getOffset(1,
+ 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), 31, status);
+ failure(status, "getOffset() failed");
+
+ if(offset1 == offset2)
+ errln("FAILURE: Sunday Oct. 26 1997 2:00 has same offset for PST and CST");
+
+ // verify error checking
+ pst->getOffset(1,
+ 1997, UCAL_FIELD_COUNT+1, 26, UCAL_SUNDAY, (2*60*60*1000), status);
+ if(U_SUCCESS(status))
+ errln("FAILURE: getOffset() succeeded with -1 for month");
+
+ status = U_ZERO_ERROR;
+ cst->setDSTSavings(60*60*1000, status);
+ failure(status, "setDSTSavings() failed");
+
+ int32_t savings = cst->getDSTSavings();
+ if(savings != 60*60*1000) {
+ errln("setDSTSavings() failed");
+ }
+
+ delete pst;
+ delete cst;
+}
+/**
+ * SimpleTimeZone allows invalid DOM values.
+ */
+void TimeZoneRegressionTest::Test4184229() {
+ SimpleTimeZone* zone = NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, status);
+ if(U_SUCCESS(status)){
+ errln("Failed. No exception has been thrown for DOM -1 startDay");
+ }else{
+ logln("(a) " + UnicodeString( u_errorName(status)));
+ }
+ status = U_ZERO_ERROR;
+ delete zone;
+
+ zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, status);
+ if(U_SUCCESS(status)){
+ errln("Failed. No exception has been thrown for DOM -1 endDay");
+ }else{
+ logln("(b) " + UnicodeString(u_errorName(status)));
+ }
+ status = U_ZERO_ERROR;
+ delete zone;
+
+ zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 1000, status);
+ if(U_SUCCESS(status)){
+ errln("Failed. No exception has been thrown for DOM -1 startDay+savings");
+ }else{
+ logln("(c) " + UnicodeString(u_errorName(status)));
+ }
+ status = U_ZERO_ERROR;
+ delete zone;
+ zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000, status);
+ if(U_SUCCESS(status)){
+ errln("Failed. No exception has been thrown for DOM -1 endDay+ savings");
+ }else{
+ logln("(d) " + UnicodeString(u_errorName(status)));
+ }
+ status = U_ZERO_ERROR;
+ delete zone;
+ // Make a valid constructor call for subsequent tests.
+ zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0, status);
+
+ zone->setStartRule(0, -1, 0, 0, status);
+ if(U_SUCCESS(status)){
+ errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings");
+ } else{
+ logln("(e) " + UnicodeString(u_errorName(status)));
+ }
+ zone->setStartRule(0, -1, 0, status);
+ if(U_SUCCESS(status)){
+ errln("Failed. No exception has been thrown for DOM -1 setStartRule");
+ } else{
+ logln("(f) " + UnicodeString(u_errorName(status)));
+ }
+
+ zone->setEndRule(0, -1, 0, 0, status);
+ if(U_SUCCESS(status)){
+ errln("Failed. No exception has been thrown for DOM -1 setEndRule+savings");
+ } else{
+ logln("(g) " + UnicodeString(u_errorName(status)));
+ }
+
+ zone->setEndRule(0, -1, 0, status);
+ if(U_SUCCESS(status)){
+ errln("Failed. No exception has been thrown for DOM -1 setEndRule");
+ } else{
+ logln("(h) " + UnicodeString(u_errorName(status)));
+ }
+ delete zone;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzregts.h b/Build/source/libs/icu/icu-xetex/test/intltest/tzregts.h
new file mode 100644
index 00000000000..6b5500c953e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzregts.h
@@ -0,0 +1,61 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1998-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef _TIMEZONEREGRESSIONTEST_
+#define _TIMEZONEREGRESSIONTEST_
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/timezone.h"
+#include "unicode/gregocal.h"
+#include "unicode/simpletz.h"
+#include "intltest.h"
+
+
+
+/**
+ * Performs regression test for Calendar
+ **/
+class TimeZoneRegressionTest: public IntlTest {
+
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public:
+
+ void Test4052967(void);
+ void Test4073209(void);
+ void Test4073215(void);
+ void Test4084933(void);
+ void Test4096952(void);
+ void Test4109314(void);
+ void Test4126678(void);
+ void Test4151406(void);
+ void Test4151429(void);
+ void Test4154537(void);
+ void Test4154542(void);
+ void Test4154650(void);
+ void Test4154525(void);
+ void Test4162593(void);
+ void Test4176686(void);
+ void TestJ186(void);
+ void TestJ449(void);
+ void TestJDK12API(void);
+ void Test4184229(void);
+ UBool checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ);
+
+
+protected:
+ UDate findTransitionBinary(const SimpleTimeZone& tz, UDate min, UDate max);
+ UDate findTransitionStepwise(const SimpleTimeZone& tz, UDate min, UDate max);
+ UBool failure(UErrorCode status, const char* msg);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _CALENDARREGRESSIONTEST_
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzrulets.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tzrulets.cpp
new file mode 100644
index 00000000000..702b502ea2c
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzrulets.cpp
@@ -0,0 +1,2087 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/dtrule.h"
+#include "unicode/tzrule.h"
+#include "unicode/rbtz.h"
+#include "unicode/simpletz.h"
+#include "unicode/tzrule.h"
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "unicode/ucal.h"
+#include "unicode/unistr.h"
+#include "unicode/tztrans.h"
+#include "unicode/vtzone.h"
+#include "tzrulets.h"
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break
+#define HOUR (60*60*1000)
+
+static const char *const TESTZIDS[] = {
+ "AGT",
+ "America/New_York",
+ "America/Los_Angeles",
+ "America/Indiana/Indianapolis",
+ "America/Havana",
+ "Europe/Lisbon",
+ "Europe/Paris",
+ "Asia/Tokyo",
+ "Asia/Sakhalin",
+ "Africa/Cairo",
+ "Africa/Windhoek",
+ "Australia/Sydney",
+ "Etc/GMT+8"
+};
+
+class TestZIDEnumeration : public StringEnumeration {
+public:
+ TestZIDEnumeration(UBool all = FALSE);
+ ~TestZIDEnumeration();
+
+ virtual int32_t count(UErrorCode& /*status*/) const {
+ return len;
+ }
+ virtual const UnicodeString *snext(UErrorCode& status);
+ virtual void reset(UErrorCode& status);
+ static inline UClassID getStaticClassID() {
+ return (UClassID)&fgClassID;
+ }
+ virtual UClassID getDynamicClassID() const {
+ return getStaticClassID();
+ }
+private:
+ static const char fgClassID;
+ int32_t idx;
+ int32_t len;
+ StringEnumeration *tzenum;
+};
+
+const char TestZIDEnumeration::fgClassID = 0;
+
+TestZIDEnumeration::TestZIDEnumeration(UBool all)
+: idx(0) {
+ UErrorCode status = U_ZERO_ERROR;
+ if (all) {
+ tzenum = TimeZone::createEnumeration();
+ len = tzenum->count(status);
+ } else {
+ tzenum = NULL;
+ len = (int32_t)sizeof(TESTZIDS)/sizeof(TESTZIDS[0]);
+ }
+}
+
+TestZIDEnumeration::~TestZIDEnumeration() {
+ if (tzenum != NULL) {
+ delete tzenum;
+ }
+}
+
+const UnicodeString*
+TestZIDEnumeration::snext(UErrorCode& status) {
+ if (tzenum != NULL) {
+ return tzenum->snext(status);
+ } else if (U_SUCCESS(status) && idx < len) {
+ unistr = UnicodeString(TESTZIDS[idx++], "");
+ return &unistr;
+ }
+ return NULL;
+}
+
+void
+TestZIDEnumeration::reset(UErrorCode& status) {
+ if (tzenum != NULL) {
+ tzenum->reset(status);
+ } else {
+ idx = 0;
+ }
+}
+
+
+void TimeZoneRuleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) {
+ logln("TestSuite TestTimeZoneRule");
+ }
+ switch (index) {
+ CASE(0, TestSimpleRuleBasedTimeZone);
+ CASE(1, TestHistoricalRuleBasedTimeZone);
+ CASE(2, TestOlsonTransition);
+ CASE(3, TestRBTZTransition);
+ CASE(4, TestHasEquivalentTransitions);
+ CASE(5, TestVTimeZoneRoundTrip);
+ CASE(6, TestVTimeZoneRoundTripPartial);
+ CASE(7, TestVTimeZoneSimpleWrite);
+ CASE(8, TestVTimeZoneHeaderProps);
+ CASE(9, TestGetSimpleRules);
+ CASE(10, TestTimeZoneRuleCoverage);
+ CASE(11, TestSimpleTimeZoneCoverage);
+ CASE(12, TestVTimeZoneCoverage);
+ CASE(13, TestVTimeZoneParse);
+ default: name = ""; break;
+ }
+}
+
+/*
+ * Compare SimpleTimeZone with equivalent RBTZ
+ */
+void
+TimeZoneRuleTest::TestSimpleRuleBasedTimeZone(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleTimeZone stz(-1*HOUR, "TestSTZ",
+ UCAL_SEPTEMBER, -30, -UCAL_SATURDAY, 1*HOUR, SimpleTimeZone::WALL_TIME,
+ UCAL_FEBRUARY, 2, UCAL_SUNDAY, 1*HOUR, SimpleTimeZone::WALL_TIME,
+ 1*HOUR, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Couldn't create SimpleTimezone.");
+ }
+
+ DateTimeRule *dtr;
+ AnnualTimeZoneRule *atzr;
+ int32_t STARTYEAR = 2000;
+
+ InitialTimeZoneRule *ir = new InitialTimeZoneRule(
+ "RBTZ_Initial", // Initial time Name
+ -1*HOUR, // Raw offset
+ 1*HOUR); // DST saving amount
+
+ // Original rules
+ RuleBasedTimeZone *rbtz1 = new RuleBasedTimeZone("RBTZ1", ir->clone());
+ dtr = new DateTimeRule(UCAL_SEPTEMBER, 30, UCAL_SATURDAY, FALSE,
+ 1*HOUR, DateTimeRule::WALL_TIME); // SUN<=30 in September, at 1AM wall time
+ atzr = new AnnualTimeZoneRule("RBTZ_DST1",
+ -1*HOUR /*rawOffset*/, 1*HOUR /*dstSavings*/, dtr,
+ STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
+ rbtz1->addTransitionRule(atzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 1-1.");
+ }
+ dtr = new DateTimeRule(UCAL_FEBRUARY, 2, UCAL_SUNDAY,
+ 1*HOUR, DateTimeRule::WALL_TIME); // 2nd Sunday in February, at 1AM wall time
+ atzr = new AnnualTimeZoneRule("RBTZ_STD1",
+ -1*HOUR /*rawOffset*/, 0 /*dstSavings*/, dtr,
+ STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
+ rbtz1->addTransitionRule(atzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 1-2.");
+ }
+ rbtz1->complete(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't complete RBTZ 1.");
+ }
+
+ // Equivalent, but different date rule type
+ RuleBasedTimeZone *rbtz2 = new RuleBasedTimeZone("RBTZ2", ir->clone());
+ dtr = new DateTimeRule(UCAL_SEPTEMBER, -1, UCAL_SATURDAY,
+ 1*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in September at 1AM wall time
+ atzr = new AnnualTimeZoneRule("RBTZ_DST2", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
+ rbtz2->addTransitionRule(atzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 2-1.");
+ }
+ dtr = new DateTimeRule(UCAL_FEBRUARY, 8, UCAL_SUNDAY, true,
+ 1*HOUR, DateTimeRule::WALL_TIME); // SUN>=8 in February, at 1AM wall time
+ atzr = new AnnualTimeZoneRule("RBTZ_STD2", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
+ rbtz2->addTransitionRule(atzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 2-2.");
+ }
+ rbtz2->complete(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't complete RBTZ 2");
+ }
+
+ // Equivalent, but different time rule type
+ RuleBasedTimeZone *rbtz3 = new RuleBasedTimeZone("RBTZ3", ir->clone());
+ dtr = new DateTimeRule(UCAL_SEPTEMBER, 30, UCAL_SATURDAY, false,
+ 2*HOUR, DateTimeRule::UTC_TIME);
+ atzr = new AnnualTimeZoneRule("RBTZ_DST3", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
+ rbtz3->addTransitionRule(atzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 3-1.");
+ }
+ dtr = new DateTimeRule(UCAL_FEBRUARY, 2, UCAL_SUNDAY,
+ 0*HOUR, DateTimeRule::STANDARD_TIME);
+ atzr = new AnnualTimeZoneRule("RBTZ_STD3", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
+ rbtz3->addTransitionRule(atzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 3-2.");
+ }
+ rbtz3->complete(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't complete RBTZ 3");
+ }
+
+ // Check equivalency for 10 years
+ UDate start = getUTCMillis(STARTYEAR, UCAL_JANUARY, 1);
+ UDate until = getUTCMillis(STARTYEAR + 10, UCAL_JANUARY, 1);
+
+ if (!(stz.hasEquivalentTransitions(*rbtz1, start, until, TRUE, status))) {
+ errln("FAIL: rbtz1 must be equivalent to the SimpleTimeZone in the time range.");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned from hasEquivalentTransitions");
+ }
+ if (!(stz.hasEquivalentTransitions(*rbtz2, start, until, TRUE, status))) {
+ errln("FAIL: rbtz2 must be equivalent to the SimpleTimeZone in the time range.");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned from hasEquivalentTransitions");
+ }
+ if (!(stz.hasEquivalentTransitions(*rbtz3, start, until, TRUE, status))) {
+ errln("FAIL: rbtz3 must be equivalent to the SimpleTimeZone in the time range.");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned from hasEquivalentTransitions");
+ }
+
+ // hasSameRules
+ if (rbtz1->hasSameRules(*rbtz2)) {
+ errln("FAIL: rbtz1 and rbtz2 have different rules, but returned true.");
+ }
+ if (rbtz1->hasSameRules(*rbtz3)) {
+ errln("FAIL: rbtz1 and rbtz3 have different rules, but returned true.");
+ }
+ RuleBasedTimeZone *rbtz1c = (RuleBasedTimeZone*)rbtz1->clone();
+ if (!rbtz1->hasSameRules(*rbtz1c)) {
+ errln("FAIL: Cloned RuleBasedTimeZone must have the same rules with the original.");
+ }
+
+ // getOffset
+ int32_t era, year, month, dayOfMonth, dayOfWeek, millisInDay;
+ UDate time;
+ int32_t offset, dstSavings;
+ UBool dst;
+
+ GregorianCalendar *cal = new GregorianCalendar(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Could not create a Gregorian calendar instance.");
+ }
+ cal->setTimeZone(*rbtz1);
+ cal->clear();
+
+ // Jan 1, 1000 BC
+ cal->set(UCAL_ERA, GregorianCalendar::BC);
+ cal->set(1000, UCAL_JANUARY, 1);
+
+ era = cal->get(UCAL_ERA, status);
+ year = cal->get(UCAL_YEAR, status);
+ month = cal->get(UCAL_MONTH, status);
+ dayOfMonth = cal->get(UCAL_DAY_OF_MONTH, status);
+ dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status);
+ millisInDay = cal->get(UCAL_MILLISECONDS_IN_DAY, status);
+ time = cal->getTime(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Could not get calendar field values.");
+ }
+ offset = rbtz1->getOffset(era, year, month, dayOfMonth, dayOfWeek, millisInDay, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(7 args) failed.");
+ }
+ if (offset != 0) {
+ errln(UnicodeString("FAIL: Invalid time zone offset: ") + offset + " /expected: 0");
+ }
+ dst = rbtz1->inDaylightTime(time, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: inDaylightTime failed.");
+ }
+ if (!dst) {
+ errln("FAIL: Invalid daylight saving time");
+ }
+ rbtz1->getOffset(time, TRUE, offset, dstSavings, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(5 args) failed.");
+ }
+ if (offset != -3600000) {
+ errln(UnicodeString("FAIL: Invalid time zone raw offset: ") + offset + " /expected: -3600000");
+ }
+ if (dstSavings != 3600000) {
+ errln(UnicodeString("FAIL: Invalid DST amount: ") + dstSavings + " /expected: 3600000");
+ }
+
+ // July 1, 2000, AD
+ cal->set(UCAL_ERA, GregorianCalendar::AD);
+ cal->set(2000, UCAL_JULY, 1);
+
+ era = cal->get(UCAL_ERA, status);
+ year = cal->get(UCAL_YEAR, status);
+ month = cal->get(UCAL_MONTH, status);
+ dayOfMonth = cal->get(UCAL_DAY_OF_MONTH, status);
+ dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status);
+ millisInDay = cal->get(UCAL_MILLISECONDS_IN_DAY, status);
+ time = cal->getTime(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Could not get calendar field values.");
+ }
+ offset = rbtz1->getOffset(era, year, month, dayOfMonth, dayOfWeek, millisInDay, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(7 args) failed.");
+ }
+ if (offset != -3600000) {
+ errln((UnicodeString)"FAIL: Invalid time zone offset: " + offset + " /expected: -3600000");
+ }
+ dst = rbtz1->inDaylightTime(time, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: inDaylightTime failed.");
+ }
+ if (dst) {
+ errln("FAIL: Invalid daylight saving time");
+ }
+ rbtz1->getOffset(time, TRUE, offset, dstSavings, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(5 args) failed.");
+ }
+ if (offset != -3600000) {
+ errln((UnicodeString)"FAIL: Invalid time zone raw offset: " + offset + " /expected: -3600000");
+ }
+ if (dstSavings != 0) {
+ errln((UnicodeString)"FAIL: Invalid DST amount: " + dstSavings + " /expected: 0");
+ }
+
+ // getRawOffset
+ offset = rbtz1->getRawOffset();
+ if (offset != -1*HOUR) {
+ errln((UnicodeString)"FAIL: Invalid time zone raw offset returned by getRawOffset: "
+ + offset + " /expected: -3600000");
+ }
+
+ // operator=/==/!=
+ RuleBasedTimeZone rbtz0("RBTZ1", ir->clone());
+ if (rbtz0 == *rbtz1 || !(rbtz0 != *rbtz1)) {
+ errln("FAIL: RuleBasedTimeZone rbtz0 is not equal to rbtz1, but got wrong result");
+ }
+ rbtz0 = *rbtz1;
+ if (rbtz0 != *rbtz1 || !(rbtz0 == *rbtz1)) {
+ errln("FAIL: RuleBasedTimeZone rbtz0 is equal to rbtz1, but got wrong result");
+ }
+
+ // setRawOffset
+ const int32_t RAW = -10*HOUR;
+ rbtz0.setRawOffset(RAW);
+ if (rbtz0.getRawOffset() != RAW) {
+ logln("setRawOffset is implemented in RuleBasedTimeZone");
+ }
+
+ // useDaylightTime
+ if (!rbtz1->useDaylightTime()) {
+ errln("FAIL: useDaylightTime returned FALSE");
+ }
+
+ // Try to add 3rd final rule
+ dtr = new DateTimeRule(UCAL_OCTOBER, 15, 1*HOUR, DateTimeRule::WALL_TIME);
+ atzr = new AnnualTimeZoneRule("3RD_ATZ", -1*HOUR, 2*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
+ rbtz1->addTransitionRule(atzr, status);
+ if (U_SUCCESS(status)) {
+ errln("FAIL: 3rd final rule must be rejected");
+ } else {
+ delete atzr;
+ }
+
+ // Try to add an initial rule
+ InitialTimeZoneRule *ir1 = new InitialTimeZoneRule("Test Initial", 2*HOUR, 0);
+ rbtz1->addTransitionRule(ir1, status);
+ if (U_SUCCESS(status)) {
+ errln("FAIL: InitialTimeZoneRule must be rejected");
+ } else {
+ delete ir1;
+ }
+
+ delete ir;
+ delete rbtz1;
+ delete rbtz2;
+ delete rbtz3;
+ delete rbtz1c;
+ delete cal;
+}
+
+/*
+ * Test equivalency between OlsonTimeZone and custom RBTZ representing the
+ * equivalent rules in a certain time range
+ */
+void
+TimeZoneRuleTest::TestHistoricalRuleBasedTimeZone(void) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Compare to America/New_York with equivalent RBTZ
+ BasicTimeZone *ny = (BasicTimeZone*)TimeZone::createTimeZone("America/New_York");
+
+ //RBTZ
+ InitialTimeZoneRule *ir = new InitialTimeZoneRule("EST", -5*HOUR, 0);
+ RuleBasedTimeZone *rbtz = new RuleBasedTimeZone("EST5EDT", ir);
+
+ DateTimeRule *dtr;
+ AnnualTimeZoneRule *tzr;
+
+ // Standard time
+ dtr = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SUNDAY,
+ 2*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in October, at 2AM wall time
+ tzr = new AnnualTimeZoneRule("EST", -5*HOUR /*rawOffset*/, 0 /*dstSavings*/, dtr, 1967, 2006);
+ rbtz->addTransitionRule(tzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 1.");
+ }
+
+ dtr = new DateTimeRule(UCAL_NOVEMBER, 1, UCAL_SUNDAY,
+ true, 2*HOUR, DateTimeRule::WALL_TIME); // SUN>=1 in November, at 2AM wall time
+ tzr = new AnnualTimeZoneRule("EST", -5*HOUR, 0, dtr, 2007, AnnualTimeZoneRule::MAX_YEAR);
+ rbtz->addTransitionRule(tzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 2.");
+ }
+
+ // Daylight saving time
+ dtr = new DateTimeRule(UCAL_APRIL, -1, UCAL_SUNDAY,
+ 2*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in April, at 2AM wall time
+ tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1967, 1973);
+ rbtz->addTransitionRule(tzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 3.");
+ }
+
+ dtr = new DateTimeRule(UCAL_JANUARY, 6,
+ 2*HOUR, DateTimeRule::WALL_TIME); // January 6, at 2AM wall time
+ tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1974, 1974);
+ rbtz->addTransitionRule(tzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 4.");
+ }
+
+ dtr = new DateTimeRule(UCAL_FEBRUARY, 23,
+ 2*HOUR, DateTimeRule::WALL_TIME); // February 23, at 2AM wall time
+ tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1975, 1975);
+ rbtz->addTransitionRule(tzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 5.");
+ }
+
+ dtr = new DateTimeRule(UCAL_APRIL, -1, UCAL_SUNDAY,
+ 2*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in April, at 2AM wall time
+ tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1976, 1986);
+ rbtz->addTransitionRule(tzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 6.");
+ }
+
+ dtr = new DateTimeRule(UCAL_APRIL, 1, UCAL_SUNDAY,
+ true, 2*HOUR, DateTimeRule::WALL_TIME); // SUN>=1 in April, at 2AM wall time
+ tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1987, 2006);
+ rbtz->addTransitionRule(tzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 7.");
+ }
+
+ dtr = new DateTimeRule(UCAL_MARCH, 8, UCAL_SUNDAY,
+ true, 2*HOUR, DateTimeRule::WALL_TIME); // SUN>=8 in March, at 2AM wall time
+ tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 2007, AnnualTimeZoneRule::MAX_YEAR);
+ rbtz->addTransitionRule(tzr, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add AnnualTimeZoneRule 7.");
+ }
+
+ rbtz->complete(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't complete RBTZ.");
+ }
+
+ // hasEquivalentTransitions
+ UDate jan1_1950 = getUTCMillis(1950, UCAL_JANUARY, 1);
+ UDate jan1_1967 = getUTCMillis(1971, UCAL_JANUARY, 1);
+ UDate jan1_2010 = getUTCMillis(2010, UCAL_JANUARY, 1);
+
+ if (!ny->hasEquivalentTransitions(*rbtz, jan1_1967, jan1_2010, TRUE, status)) {
+ errln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1967-2010");
+ }
+ if (ny->hasEquivalentTransitions(*rbtz, jan1_1950, jan1_2010, TRUE, status)) {
+ errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1950-2010");
+ }
+
+ // Same with above, but calling RBTZ#hasEquivalentTransitions against OlsonTimeZone
+ if (!rbtz->hasEquivalentTransitions(*ny, jan1_1967, jan1_2010, TRUE, status)) {
+ errln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1967-2010");
+ }
+ if (rbtz->hasEquivalentTransitions(*ny, jan1_1950, jan1_2010, TRUE, status)) {
+ errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1950-2010");
+ }
+
+ // TimeZone APIs
+ if (ny->hasSameRules(*rbtz) || rbtz->hasSameRules(*ny)) {
+ errln("FAIL: hasSameRules must return false");
+ }
+ RuleBasedTimeZone *rbtzc = (RuleBasedTimeZone*)rbtz->clone();
+ if (!rbtz->hasSameRules(*rbtzc) || !rbtz->hasEquivalentTransitions(*rbtzc, jan1_1950, jan1_2010, TRUE, status)) {
+ errln("FAIL: hasSameRules/hasEquivalentTransitions must return true for cloned RBTZs");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned from hasEquivalentTransitions for rbtz/rbtzc 1950-2010");
+ }
+
+ UDate times[] = {
+ getUTCMillis(2006, UCAL_MARCH, 15),
+ getUTCMillis(2006, UCAL_NOVEMBER, 1),
+ getUTCMillis(2007, UCAL_MARCH, 15),
+ getUTCMillis(2007, UCAL_NOVEMBER, 1),
+ getUTCMillis(2008, UCAL_MARCH, 15),
+ getUTCMillis(2008, UCAL_NOVEMBER, 1),
+ 0
+ };
+ int32_t offset1, dst1;
+ int32_t offset2, dst2;
+
+ for (int i = 0; times[i] != 0; i++) {
+ // Check getOffset - must return the same results for these time data
+ rbtz->getOffset(times[i], FALSE, offset1, dst1, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: rbtz->getOffset failed");
+ }
+ ny->getOffset(times[i], FALSE, offset2, dst2, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: ny->getOffset failed");
+ }
+ if (offset1 != offset2 || dst1 != dst2) {
+ errln("FAIL: Incompatible time zone offset/dstSavings for ny and rbtz");
+ }
+
+ // Check inDaylightTime
+ if (rbtz->inDaylightTime(times[i], status) != ny->inDaylightTime(times[i], status)) {
+ errln("FAIL: Incompatible daylight saving time for ny and rbtz");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: inDaylightTime failed");
+ }
+ }
+
+ delete ny;
+ delete rbtz;
+ delete rbtzc;
+}
+
+/*
+ * Check if transitions returned by getNextTransition/getPreviousTransition
+ * are actual time transitions.
+ */
+void
+TimeZoneRuleTest::TestOlsonTransition(void) {
+
+ const int32_t TESTYEARS[][2] = {
+ {1895, 1905}, // including int32 minimum second
+ {1965, 1975}, // including the epoch
+ {1995, 2015}, // practical year range
+ {0,0}
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ TestZIDEnumeration tzenum(!quick);
+ while (TRUE) {
+ const UnicodeString *tzid = tzenum.snext(status);
+ if (tzid == NULL) {
+ break;
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while enumerating timezone IDs.");
+ break;
+ }
+ BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
+ for (int32_t i = 0; TESTYEARS[i][0] != 0 || TESTYEARS[i][1] != 0; i++) {
+ UDate lo = getUTCMillis(TESTYEARS[i][0], UCAL_JANUARY, 1);
+ UDate hi = getUTCMillis(TESTYEARS[i][1], UCAL_JANUARY, 1);
+ verifyTransitions(*tz, lo, hi);
+ }
+ delete tz;
+ }
+}
+
+/*
+ * Check if an OlsonTimeZone and its equivalent RBTZ have the exact same
+ * transitions.
+ */
+void
+TimeZoneRuleTest::TestRBTZTransition(void) {
+ const int32_t STARTYEARS[] = {
+ 1900,
+ 1960,
+ 1990,
+ 2010,
+ 0
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ TestZIDEnumeration tzenum(!quick);
+ while (TRUE) {
+ const UnicodeString *tzid = tzenum.snext(status);
+ if (tzid == NULL) {
+ break;
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while enumerating timezone IDs.");
+ break;
+ }
+ BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
+ int32_t ruleCount = tz->countTransitionRules(status);
+
+ const InitialTimeZoneRule *initial;
+ const TimeZoneRule **trsrules = new const TimeZoneRule*[ruleCount];
+ tz->getTimeZoneRules(initial, trsrules, ruleCount, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: failed to get the TimeZoneRules from time zone " + *tzid);
+ }
+ RuleBasedTimeZone *rbtz = new RuleBasedTimeZone(*tzid, initial->clone());
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: failed to get the transition rule count from time zone " + *tzid);
+ }
+ for (int32_t i = 0; i < ruleCount; i++) {
+ rbtz->addTransitionRule(trsrules[i]->clone(), status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: failed to add a transition rule at index " + i + " to the RBTZ for " + *tzid);
+ }
+ }
+ rbtz->complete(status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: complete() failed for the RBTZ for " + *tzid);
+ }
+
+ for (int32_t idx = 0; STARTYEARS[idx] != 0; idx++) {
+ UDate start = getUTCMillis(STARTYEARS[idx], UCAL_JANUARY, 1);
+ UDate until = getUTCMillis(STARTYEARS[idx] + 20, UCAL_JANUARY, 1);
+ // Compare the original OlsonTimeZone with the RBTZ starting the startTime for 20 years
+
+ // Ascending
+ compareTransitionsAscending(*tz, *rbtz, start, until, FALSE);
+ // Ascending/inclusive
+ compareTransitionsAscending(*tz, *rbtz, start + 1, until, TRUE);
+ // Descending
+ compareTransitionsDescending(*tz, *rbtz, start, until, FALSE);
+ // Descending/inclusive
+ compareTransitionsDescending(*tz, *rbtz, start + 1, until, TRUE);
+ }
+ delete [] trsrules;
+ delete rbtz;
+ delete tz;
+ }
+}
+
+void
+TimeZoneRuleTest::TestHasEquivalentTransitions(void) {
+ // America/New_York and America/Indiana/Indianapolis are equivalent
+ // since 2006
+ UErrorCode status = U_ZERO_ERROR;
+ BasicTimeZone *newyork = (BasicTimeZone*)TimeZone::createTimeZone("America/New_York");
+ BasicTimeZone *indianapolis = (BasicTimeZone*)TimeZone::createTimeZone("America/Indiana/Indianapolis");
+ BasicTimeZone *gmt_5 = (BasicTimeZone*)TimeZone::createTimeZone("Etc/GMT+5");
+
+ UDate jan1_1971 = getUTCMillis(1971, UCAL_JANUARY, 1);
+ UDate jan1_2005 = getUTCMillis(2005, UCAL_JANUARY, 1);
+ UDate jan1_2006 = getUTCMillis(2006, UCAL_JANUARY, 1);
+ UDate jan1_2007 = getUTCMillis(2007, UCAL_JANUARY, 1);
+ UDate jan1_2011 = getUTCMillis(2010, UCAL_JANUARY, 1);
+
+ if (newyork->hasEquivalentTransitions(*indianapolis, jan1_2005, jan1_2011, TRUE, status)) {
+ errln("FAIL: New_York is not equivalent to Indianapolis between 2005 and 2010");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from hasEquivalentTransition");
+ }
+ if (!newyork->hasEquivalentTransitions(*indianapolis, jan1_2006, jan1_2011, TRUE, status)) {
+ errln("FAIL: New_York is equivalent to Indianapolis between 2006 and 2010");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from hasEquivalentTransition");
+ }
+
+ if (!indianapolis->hasEquivalentTransitions(*gmt_5, jan1_1971, jan1_2006, TRUE, status)) {
+ errln("FAIL: Indianapolis is equivalent to GMT+5 between 1971 and 2005");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from hasEquivalentTransition");
+ }
+ if (indianapolis->hasEquivalentTransitions(*gmt_5, jan1_1971, jan1_2007, TRUE, status)) {
+ errln("FAIL: Indianapolis is not equivalent to GMT+5 between 1971 and 2006");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from hasEquivalentTransition");
+ }
+
+ // Cloned TimeZone
+ BasicTimeZone *newyork2 = (BasicTimeZone*)newyork->clone();
+ if (!newyork->hasEquivalentTransitions(*newyork2, jan1_1971, jan1_2011, FALSE, status)) {
+ errln("FAIL: Cloned TimeZone must have the same transitions");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2");
+ }
+ if (!newyork->hasEquivalentTransitions(*newyork2, jan1_1971, jan1_2011, TRUE, status)) {
+ errln("FAIL: Cloned TimeZone must have the same transitions");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2");
+ }
+
+ // America/New_York and America/Los_Angeles has same DST start rules, but
+ // raw offsets are different
+ BasicTimeZone *losangeles = (BasicTimeZone*)TimeZone::createTimeZone("America/Los_Angeles");
+ if (newyork->hasEquivalentTransitions(*losangeles, jan1_2006, jan1_2011, TRUE, status)) {
+ errln("FAIL: New_York is not equivalent to Los Angeles, but returned true");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from hasEquivalentTransition for newyork/losangeles");
+ }
+
+ delete newyork;
+ delete newyork2;
+ delete indianapolis;
+ delete gmt_5;
+ delete losangeles;
+}
+
+/*
+ * Write out time zone rules of OlsonTimeZone into VTIMEZONE format, create a new
+ * VTimeZone from the VTIMEZONE data, then compare transitions
+ */
+void
+TimeZoneRuleTest::TestVTimeZoneRoundTrip(void) {
+ UDate startTime = getUTCMillis(1850, UCAL_JANUARY, 1);
+ UDate endTime = getUTCMillis(2050, UCAL_JANUARY, 1);
+
+ UErrorCode status = U_ZERO_ERROR;
+ TestZIDEnumeration tzenum(!quick);
+ while (TRUE) {
+ const UnicodeString *tzid = tzenum.snext(status);
+ if (tzid == NULL) {
+ break;
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while enumerating timezone IDs.");
+ break;
+ }
+ BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
+ VTimeZone *vtz_org = VTimeZone::createVTimeZoneByID(*tzid);
+ vtz_org->setTZURL("http://source.icu-project.org/timezone");
+ vtz_org->setLastModified(Calendar::getNow());
+ VTimeZone *vtz_new = NULL;
+ UnicodeString vtzdata;
+ // Write out VTIMEZONE data
+ vtz_org->write(vtzdata, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: error returned while writing time zone rules for " +
+ *tzid + " into VTIMEZONE format.");
+ } else {
+ // Read VTIMEZONE data
+ vtz_new = VTimeZone::createVTimeZone(vtzdata, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: error returned while reading VTIMEZONE data for " + *tzid);
+ } else {
+ // Write out VTIMEZONE one more time
+ UnicodeString vtzdata1;
+ vtz_new->write(vtzdata1, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: error returned while writing time zone rules for " +
+ *tzid + "(vtz_new) into VTIMEZONE format.");
+ } else {
+ // Make sure VTIMEZONE data is exactly same with the first one
+ if (vtzdata != vtzdata1) {
+ errln((UnicodeString)"FAIL: different VTIMEZONE data after round trip for " + *tzid);
+ }
+ }
+ // Check equivalency after the first transition.
+ // The DST information before the first transition might be lost
+ // because there is no good way to represent the initial time with
+ // VTIMEZONE.
+ int32_t raw1, raw2, dst1, dst2;
+ tz->getOffset(startTime, FALSE, raw1, dst1, status);
+ vtz_new->getOffset(startTime, FALSE, raw2, dst2, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from getOffset");
+ } else {
+ if (raw1 + dst1 != raw2 + dst2) {
+ errln("FAIL: VTimeZone for " + *tzid +
+ " is not equivalent to its OlsonTimeZone corresponding at "
+ + dateToString(startTime));
+ }
+ TimeZoneTransition trans;
+ UBool avail = tz->getNextTransition(startTime, FALSE, trans);
+ if (avail) {
+ if (!vtz_new->hasEquivalentTransitions(*tz, trans.getTime(),
+ endTime, TRUE, status)) {
+ errln("FAIL: VTimeZone for " + *tzid +
+ " is not equivalent to its OlsonTimeZone corresponding.");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from hasEquivalentTransition");
+ }
+ }
+ }
+ }
+ if (vtz_new != NULL) {
+ delete vtz_new;
+ vtz_new = NULL;
+ }
+ }
+ delete tz;
+ delete vtz_org;
+ }
+}
+
+/*
+ * Write out time zone rules of OlsonTimeZone after a cutover date into VTIMEZONE format,
+ * create a new VTimeZone from the VTIMEZONE data, then compare transitions
+ */
+void
+TimeZoneRuleTest::TestVTimeZoneRoundTripPartial(void) {
+ const int32_t STARTYEARS[] = {
+ 1900,
+ 1950,
+ 2020,
+ 0
+ };
+ UDate endTime = getUTCMillis(2050, UCAL_JANUARY, 1);
+
+ UErrorCode status = U_ZERO_ERROR;
+ TestZIDEnumeration tzenum(!quick);
+ while (TRUE) {
+ const UnicodeString *tzid = tzenum.snext(status);
+ if (tzid == NULL) {
+ break;
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while enumerating timezone IDs.");
+ break;
+ }
+ BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
+ VTimeZone *vtz_org = VTimeZone::createVTimeZoneByID(*tzid);
+ VTimeZone *vtz_new = NULL;
+ UnicodeString vtzdata;
+
+ for (int32_t i = 0; STARTYEARS[i] != 0; i++) {
+ // Write out VTIMEZONE
+ UDate startTime = getUTCMillis(STARTYEARS[i], UCAL_JANUARY, 1);
+ vtz_org->write(startTime, vtzdata, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: error returned while writing time zone rules for " +
+ *tzid + " into VTIMEZONE format since " + dateToString(startTime));
+ } else {
+ // Read VTIMEZONE data
+ vtz_new = VTimeZone::createVTimeZone(vtzdata, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: error returned while reading VTIMEZONE data for " + *tzid
+ + " since " + dateToString(startTime));
+ } else {
+ // Check equivalency after the first transition.
+ // The DST information before the first transition might be lost
+ // because there is no good way to represent the initial time with
+ // VTIMEZONE.
+ int32_t raw1, raw2, dst1, dst2;
+ tz->getOffset(startTime, FALSE, raw1, dst1, status);
+ vtz_new->getOffset(startTime, FALSE, raw2, dst2, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from getOffset");
+ } else {
+ if (raw1 + dst1 != raw2 + dst2) {
+ errln("FAIL: VTimeZone for " + *tzid +
+ " is not equivalent to its OlsonTimeZone corresponding at "
+ + dateToString(startTime));
+ }
+ TimeZoneTransition trans;
+ UBool avail = tz->getNextTransition(startTime, FALSE, trans);
+ if (avail) {
+ if (!vtz_new->hasEquivalentTransitions(*tz, trans.getTime(),
+ endTime, TRUE, status)) {
+ errln("FAIL: VTimeZone for " + *tzid +
+ " is not equivalent to its OlsonTimeZone corresponding.");
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error status is returned from hasEquivalentTransition");
+ }
+ }
+ }
+ }
+ }
+ if (vtz_new != NULL) {
+ delete vtz_new;
+ vtz_new = NULL;
+ }
+ }
+ delete tz;
+ delete vtz_org;
+ }
+}
+
+/*
+ * Write out simple time zone rules from an OlsonTimeZone at various time into VTIMEZONE
+ * format and create a new VTimeZone from the VTIMEZONE data, then make sure the raw offset
+ * and DST savings are same in these two time zones.
+ */
+void
+TimeZoneRuleTest::TestVTimeZoneSimpleWrite(void) {
+ const int32_t TESTDATES[][3] = {
+ {2006, UCAL_JANUARY, 1},
+ {2006, UCAL_MARCH, 15},
+ {2006, UCAL_MARCH, 31},
+ {2006, UCAL_OCTOBER, 25},
+ {2006, UCAL_NOVEMBER, 1},
+ {2006, UCAL_NOVEMBER, 5},
+ {2007, UCAL_JANUARY, 1},
+ {0, 0, 0}
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ TestZIDEnumeration tzenum(!quick);
+ while (TRUE) {
+ const UnicodeString *tzid = tzenum.snext(status);
+ if (tzid == NULL) {
+ break;
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while enumerating timezone IDs.");
+ break;
+ }
+ VTimeZone *vtz_org = VTimeZone::createVTimeZoneByID(*tzid);
+ VTimeZone *vtz_new = NULL;
+ UnicodeString vtzdata;
+
+ for (int32_t i = 0; TESTDATES[i][0] != 0; i++) {
+ // Write out VTIMEZONE
+ UDate time = getUTCMillis(TESTDATES[i][0], TESTDATES[i][1], TESTDATES[i][2]);
+ vtz_org->writeSimple(time, vtzdata, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: error returned while writing simple time zone rules for " +
+ *tzid + " into VTIMEZONE format at " + dateToString(time));
+ } else {
+ // Read VTIMEZONE data
+ vtz_new = VTimeZone::createVTimeZone(vtzdata, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"FAIL: error returned while reading simple VTIMEZONE data for " + *tzid
+ + " at " + dateToString(time));
+ } else {
+ // Check equivalency
+ int32_t raw0, dst0;
+ int32_t raw1, dst1;
+ vtz_org->getOffset(time, FALSE, raw0, dst0, status);
+ vtz_new->getOffset(time, FALSE, raw1, dst1, status);
+ if (U_SUCCESS(status)) {
+ if (raw0 != raw1 || dst0 != dst1) {
+ errln("FAIL: VTimeZone writeSimple for " + *tzid + " at "
+ + dateToString(time) + " failed to the round trip.");
+ }
+ } else {
+ errln("FAIL: getOffset returns error status");
+ }
+ }
+ }
+ if (vtz_new != NULL) {
+ delete vtz_new;
+ vtz_new = NULL;
+ }
+ }
+ delete vtz_org;
+ }
+}
+
+/*
+ * Write out time zone rules of OlsonTimeZone into VTIMEZONE format with RFC2445 header TZURL and
+ * LAST-MODIFIED, create a new VTimeZone from the VTIMEZONE data to see if the headers are preserved.
+ */
+void
+TimeZoneRuleTest::TestVTimeZoneHeaderProps(void) {
+ const UnicodeString TESTURL1("http://source.icu-project.org");
+ const UnicodeString TESTURL2("http://www.ibm.com");
+
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString tzurl;
+ UDate lmod;
+ UDate lastmod = getUTCMillis(2007, UCAL_JUNE, 1);
+ VTimeZone *vtz = VTimeZone::createVTimeZoneByID("America/Chicago");
+ vtz->setTZURL(TESTURL1);
+ vtz->setLastModified(lastmod);
+
+ // Roundtrip conversion
+ UnicodeString vtzdata;
+ vtz->write(vtzdata, status);
+ VTimeZone *newvtz1 = NULL;
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while writing VTIMEZONE data 1");
+ return;
+ }
+ // Create a new one
+ newvtz1 = VTimeZone::createVTimeZone(vtzdata, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while loading VTIMEZONE data 1");
+ } else {
+ // Check if TZURL and LAST-MODIFIED properties are preserved
+ newvtz1->getTZURL(tzurl);
+ if (tzurl != TESTURL1) {
+ errln("FAIL: TZURL 1 was not preserved");
+ }
+ vtz->getLastModified(lmod);
+ if (lastmod != lmod) {
+ errln("FAIL: LAST-MODIFIED was not preserved");
+ }
+ }
+
+ if (U_SUCCESS(status)) {
+ // Set different tzurl
+ newvtz1->setTZURL(TESTURL2);
+
+ // Second roundtrip, with a cutover
+ newvtz1->write(vtzdata, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while writing VTIMEZONE data 2");
+ } else {
+ VTimeZone *newvtz2 = VTimeZone::createVTimeZone(vtzdata, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while loading VTIMEZONE data 2");
+ } else {
+ // Check if TZURL and LAST-MODIFIED properties are preserved
+ newvtz2->getTZURL(tzurl);
+ if (tzurl != TESTURL2) {
+ errln("FAIL: TZURL was not preserved in the second roundtrip");
+ }
+ vtz->getLastModified(lmod);
+ if (lastmod != lmod) {
+ errln("FAIL: LAST-MODIFIED was not preserved in the second roundtrip");
+ }
+ }
+ delete newvtz2;
+ }
+ }
+ delete newvtz1;
+ delete vtz;
+}
+
+/*
+ * Extract simple rules from an OlsonTimeZone and make sure the rule format matches
+ * the expected format.
+ */
+void
+TimeZoneRuleTest::TestGetSimpleRules(void) {
+ UDate testTimes[] = {
+ getUTCMillis(1970, UCAL_JANUARY, 1),
+ getUTCMillis(2000, UCAL_MARCH, 31),
+ getUTCMillis(2005, UCAL_JULY, 1),
+ getUTCMillis(2010, UCAL_NOVEMBER, 1),
+ };
+ int32_t numTimes = sizeof(testTimes)/sizeof(UDate);
+ UErrorCode status = U_ZERO_ERROR;
+ TestZIDEnumeration tzenum(!quick);
+ InitialTimeZoneRule *initial;
+ AnnualTimeZoneRule *std, *dst;
+ for (int32_t i = 0; i < numTimes ; i++) {
+ while (TRUE) {
+ const UnicodeString *tzid = tzenum.snext(status);
+ if (tzid == NULL) {
+ break;
+ }
+ if (U_FAILURE(status)) {
+ errln("FAIL: error returned while enumerating timezone IDs.");
+ break;
+ }
+ BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
+ initial = NULL;
+ std = dst = NULL;
+ tz->getSimpleRulesNear(testTimes[i], initial, std, dst, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getSimpleRules failed.");
+ break;
+ }
+ if (initial == NULL) {
+ errln("FAIL: initial rule must not be NULL");
+ break;
+ } else if (!(std == NULL && dst == NULL || std != NULL && dst != NULL)) {
+ errln("FAIL: invalid std/dst pair.");
+ break;
+ }
+ if (std != NULL) {
+ const DateTimeRule *dtr = std->getRule();
+ if (dtr->getDateRuleType() != DateTimeRule::DOW) {
+ errln("FAIL: simple std rull must use DateTimeRule::DOW as date rule.");
+ break;
+ }
+ if (dtr->getTimeRuleType() != DateTimeRule::WALL_TIME) {
+ errln("FAIL: simple std rull must use DateTimeRule::WALL_TIME as time rule.");
+ break;
+ }
+ dtr = dst->getRule();
+ if (dtr->getDateRuleType() != DateTimeRule::DOW) {
+ errln("FAIL: simple dst rull must use DateTimeRule::DOW as date rule.");
+ break;
+ }
+ if (dtr->getTimeRuleType() != DateTimeRule::WALL_TIME) {
+ errln("FAIL: simple dst rull must use DateTimeRule::WALL_TIME as time rule.");
+ break;
+ }
+ }
+ // Create an RBTZ from the rules and compare the offsets at the date
+ RuleBasedTimeZone *rbtz = new RuleBasedTimeZone(*tzid, initial);
+ if (std != NULL) {
+ rbtz->addTransitionRule(std, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add std rule.");
+ }
+ rbtz->addTransitionRule(dst, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't add dst rule.");
+ }
+ }
+ rbtz->complete(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't complete rbtz for " + *tzid);
+ }
+
+ int32_t raw0, dst0, raw1, dst1;
+ tz->getOffset(testTimes[i], FALSE, raw0, dst0, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't get offsets from tz for " + *tzid);
+ }
+ rbtz->getOffset(testTimes[i], FALSE, raw1, dst1, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: couldn't get offsets from rbtz for " + *tzid);
+ }
+ if (raw0 != raw1 || dst0 != dst1) {
+ errln("FAIL: rbtz created by simple rule does not match the original tz for tzid " + *tzid);
+ }
+ delete rbtz;
+ delete tz;
+ }
+ }
+}
+
+/*
+ * API coverage tests for TimeZoneRule
+ */
+void
+TimeZoneRuleTest::TestTimeZoneRuleCoverage(void) {
+ UDate time1 = getUTCMillis(2005, UCAL_JULY, 4);
+ UDate time2 = getUTCMillis(2015, UCAL_JULY, 4);
+ UDate time3 = getUTCMillis(1950, UCAL_JULY, 4);
+
+ DateTimeRule *dtr1 = new DateTimeRule(UCAL_FEBRUARY, 29, UCAL_SUNDAY, FALSE,
+ 3*HOUR, DateTimeRule::WALL_TIME); // Last Sunday on or before Feb 29, at 3 AM, wall time
+ DateTimeRule *dtr2 = new DateTimeRule(UCAL_MARCH, 11, 2*HOUR,
+ DateTimeRule::STANDARD_TIME); // Mar 11, at 2 AM, standard time
+ DateTimeRule *dtr3 = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SATURDAY,
+ 6*HOUR, DateTimeRule::UTC_TIME); //Last Saturday in Oct, at 6 AM, UTC
+ DateTimeRule *dtr4 = new DateTimeRule(UCAL_MARCH, 8, UCAL_SUNDAY, TRUE,
+ 2*HOUR, DateTimeRule::WALL_TIME); // First Sunday on or after Mar 8, at 2 AM, wall time
+
+ AnnualTimeZoneRule *a1 = new AnnualTimeZoneRule("a1", -3*HOUR, 1*HOUR, *dtr1,
+ 2000, AnnualTimeZoneRule::MAX_YEAR);
+ AnnualTimeZoneRule *a2 = new AnnualTimeZoneRule("a2", -3*HOUR, 1*HOUR, *dtr1,
+ 2000, AnnualTimeZoneRule::MAX_YEAR);
+ AnnualTimeZoneRule *a3 = new AnnualTimeZoneRule("a3", -3*HOUR, 1*HOUR, *dtr1,
+ 2000, 2010);
+
+ InitialTimeZoneRule *i1 = new InitialTimeZoneRule("i1", -3*HOUR, 0);
+ InitialTimeZoneRule *i2 = new InitialTimeZoneRule("i2", -3*HOUR, 0);
+ InitialTimeZoneRule *i3 = new InitialTimeZoneRule("i3", -3*HOUR, 1*HOUR);
+
+ UDate trtimes1[] = {0.0};
+ UDate trtimes2[] = {0.0, 10000000.0};
+
+ TimeArrayTimeZoneRule *t1 = new TimeArrayTimeZoneRule("t1", -3*HOUR, 0, trtimes1, 1, DateTimeRule::UTC_TIME);
+ TimeArrayTimeZoneRule *t2 = new TimeArrayTimeZoneRule("t2", -3*HOUR, 0, trtimes1, 1, DateTimeRule::UTC_TIME);
+ TimeArrayTimeZoneRule *t3 = new TimeArrayTimeZoneRule("t3", -3*HOUR, 0, trtimes2, 2, DateTimeRule::UTC_TIME);
+ TimeArrayTimeZoneRule *t4 = new TimeArrayTimeZoneRule("t4", -3*HOUR, 0, trtimes1, 1, DateTimeRule::STANDARD_TIME);
+ TimeArrayTimeZoneRule *t5 = new TimeArrayTimeZoneRule("t5", -4*HOUR, 1*HOUR, trtimes1, 1, DateTimeRule::WALL_TIME);
+
+ // DateTimeRule::operator=/clone
+ DateTimeRule dtr0(UCAL_MAY, 31, 2*HOUR, DateTimeRule::WALL_TIME);
+ if (dtr0 == *dtr1 || !(dtr0 != *dtr1)) {
+ errln("FAIL: DateTimeRule dtr0 is not equal to dtr1, but got wrong result");
+ }
+ dtr0 = *dtr1;
+ if (dtr0 != *dtr1 || !(dtr0 == *dtr1)) {
+ errln("FAIL: DateTimeRule dtr0 is equal to dtr1, but got wrong result");
+ }
+ DateTimeRule *dtr0c = dtr0.clone();
+ if (*dtr0c != *dtr1 || !(*dtr0c == *dtr1)) {
+ errln("FAIL: DateTimeRule dtr0c is equal to dtr1, but got wrong result");
+ }
+ delete dtr0c;
+
+ // AnnualTimeZonerule::operator=/clone
+ AnnualTimeZoneRule a0("a0", 5*HOUR, 1*HOUR, *dtr1, 1990, AnnualTimeZoneRule::MAX_YEAR);
+ if (a0 == *a1 || !(a0 != *a1)) {
+ errln("FAIL: AnnualTimeZoneRule a0 is not equal to a1, but got wrong result");
+ }
+ a0 = *a1;
+ if (a0 != *a1 || !(a0 == *a1)) {
+ errln("FAIL: AnnualTimeZoneRule a0 is equal to a1, but got wrong result");
+ }
+ AnnualTimeZoneRule *a0c = a0.clone();
+ if (*a0c != *a1 || !(*a0c == *a1)) {
+ errln("FAIL: AnnualTimeZoneRule a0c is equal to a1, but got wrong result");
+ }
+ delete a0c;
+
+ // AnnualTimeZoneRule::getRule
+ if (*(a1->getRule()) != *(a2->getRule())) {
+ errln("FAIL: The same DateTimeRule must be returned from AnnualTimeZoneRule a1 and a2");
+ }
+
+ // AnnualTimeZoneRule::getStartYear
+ int32_t startYear = a1->getStartYear();
+ if (startYear != 2000) {
+ errln((UnicodeString)"FAIL: The start year of AnnualTimeZoneRule a1 must be 2000 - returned: " + startYear);
+ }
+
+ // AnnualTimeZoneRule::getEndYear
+ int32_t endYear = a1->getEndYear();
+ if (endYear != AnnualTimeZoneRule::MAX_YEAR) {
+ errln((UnicodeString)"FAIL: The start year of AnnualTimeZoneRule a1 must be MAX_YEAR - returned: " + endYear);
+ }
+ endYear = a3->getEndYear();
+ if (endYear != 2010) {
+ errln((UnicodeString)"FAIL: The start year of AnnualTimeZoneRule a3 must be 2010 - returned: " + endYear);
+ }
+
+ // AnnualTimeZone::getStartInYear
+ UBool b1, b2;
+ UDate d1, d2;
+ b1 = a1->getStartInYear(2005, -3*HOUR, 0, d1);
+ b2 = a3->getStartInYear(2005, -3*HOUR, 0, d2);
+ if (!b1 || !b2 || d1 != d2) {
+ errln("FAIL: AnnualTimeZoneRule::getStartInYear did not work as expected");
+ }
+ b2 = a3->getStartInYear(2015, -3*HOUR, 0, d2);
+ if (b2) {
+ errln("FAIL: AnnualTimeZoneRule::getStartInYear returned TRUE for 2015 which is out of rule range");
+ }
+
+ // AnnualTimeZone::getFirstStart
+ b1 = a1->getFirstStart(-3*HOUR, 0, d1);
+ b2 = a1->getFirstStart(-4*HOUR, 1*HOUR, d2);
+ if (!b1 || !b2 || d1 != d2) {
+ errln("FAIL: The same start time should be returned by getFirstStart");
+ }
+
+ // AnnualTimeZone::getFinalStart
+ b1 = a1->getFinalStart(-3*HOUR, 0, d1);
+ if (b1) {
+ errln("FAIL: getFinalStart returned TRUE for a1");
+ }
+ b1 = a1->getStartInYear(2010, -3*HOUR, 0, d1);
+ b2 = a3->getFinalStart(-3*HOUR, 0, d2);
+ if (!b1 || !b2 || d1 != d2) {
+ errln("FAIL: Bad date is returned by getFinalStart");
+ }
+
+ // AnnualTimeZone::getNextStart / getPreviousStart
+ b1 = a1->getNextStart(time1, -3*HOUR, 0, FALSE, d1);
+ if (!b1) {
+ errln("FAIL: getNextStart returned FALSE for ai");
+ } else {
+ b2 = a1->getPreviousStart(d1, -3*HOUR, 0, TRUE, d2);
+ if (!b2 || d1 != d2) {
+ errln("FAIL: Bad Date is returned by getPreviousStart");
+ }
+ }
+ b1 = a3->getNextStart(time2, -3*HOUR, 0, FALSE, d1);
+ if (b1) {
+ errln("FAIL: getNextStart must return FALSE when no start time is available after the base time");
+ }
+ b1 = a3->getFinalStart(-3*HOUR, 0, d1);
+ b2 = a3->getPreviousStart(time2, -3*HOUR, 0, FALSE, d2);
+ if (!b1 || !b2 || d1 != d2) {
+ errln("FAIL: getPreviousStart does not match with getFinalStart after the end year");
+ }
+
+ // AnnualTimeZone::isEquavalentTo
+ if (!a1->isEquivalentTo(*a2)) {
+ errln("FAIL: AnnualTimeZoneRule a1 is equivalent to a2, but returned FALSE");
+ }
+ if (a1->isEquivalentTo(*a3)) {
+ errln("FAIL: AnnualTimeZoneRule a1 is not equivalent to a3, but returned TRUE");
+ }
+ if (!a1->isEquivalentTo(*a1)) {
+ errln("FAIL: AnnualTimeZoneRule a1 is equivalent to itself, but returned FALSE");
+ }
+ if (a1->isEquivalentTo(*t1)) {
+ errln("FAIL: AnnualTimeZoneRule is not equivalent to TimeArrayTimeZoneRule, but returned TRUE");
+ }
+
+ // InitialTimezoneRule::operator=/clone
+ InitialTimeZoneRule i0("i0", 10*HOUR, 0);
+ if (i0 == *i1 || !(i0 != *i1)) {
+ errln("FAIL: InitialTimeZoneRule i0 is not equal to i1, but got wrong result");
+ }
+ i0 = *i1;
+ if (i0 != *i1 || !(i0 == *i1)) {
+ errln("FAIL: InitialTimeZoneRule i0 is equal to i1, but got wrong result");
+ }
+ InitialTimeZoneRule *i0c = i0.clone();
+ if (*i0c != *i1 || !(*i0c == *i1)) {
+ errln("FAIL: InitialTimeZoneRule i0c is equal to i1, but got wrong result");
+ }
+ delete i0c;
+
+ // InitialTimeZoneRule::isEquivalentRule
+ if (!i1->isEquivalentTo(*i2)) {
+ errln("FAIL: InitialTimeZoneRule i1 is equivalent to i2, but returned FALSE");
+ }
+ if (i1->isEquivalentTo(*i3)) {
+ errln("FAIL: InitialTimeZoneRule i1 is not equivalent to i3, but returned TRUE");
+ }
+ if (i1->isEquivalentTo(*a1)) {
+ errln("FAIL: An InitialTimeZoneRule is not equivalent to an AnnualTimeZoneRule, but returned TRUE");
+ }
+
+ // InitialTimeZoneRule::getFirstStart/getFinalStart/getNextStart/getPreviousStart
+ b1 = i1->getFirstStart(0, 0, d1);
+ if (b1) {
+ errln("FAIL: InitialTimeZone::getFirstStart returned TRUE");
+ }
+ b1 = i1->getFinalStart(0, 0, d1);
+ if (b1) {
+ errln("FAIL: InitialTimeZone::getFinalStart returned TRUE");
+ }
+ b1 = i1->getNextStart(time1, 0, 0, FALSE, d1);
+ if (b1) {
+ errln("FAIL: InitialTimeZone::getNextStart returned TRUE");
+ }
+ b1 = i1->getPreviousStart(time1, 0, 0, FALSE, d1);
+ if (b1) {
+ errln("FAIL: InitialTimeZone::getPreviousStart returned TRUE");
+ }
+
+ // TimeArrayTimeZoneRule::operator=/clone
+ TimeArrayTimeZoneRule t0("t0", 4*HOUR, 0, trtimes1, 1, DateTimeRule::UTC_TIME);
+ if (t0 == *t1 || !(t0 != *t1)) {
+ errln("FAIL: TimeArrayTimeZoneRule t0 is not equal to t1, but got wrong result");
+ }
+ t0 = *t1;
+ if (t0 != *t1 || !(t0 == *t1)) {
+ errln("FAIL: TimeArrayTimeZoneRule t0 is equal to t1, but got wrong result");
+ }
+ TimeArrayTimeZoneRule *t0c = t0.clone();
+ if (*t0c != *t1 || !(*t0c == *t1)) {
+ errln("FAIL: TimeArrayTimeZoneRule t0c is equal to t1, but got wrong result");
+ }
+ delete t0c;
+
+ // TimeArrayTimeZoneRule::countStartTimes
+ if (t1->countStartTimes() != 1) {
+ errln("FAIL: Bad start time count is returned by TimeArrayTimeZoneRule::countStartTimes");
+ }
+
+ // TimeArrayTimeZoneRule::getStartTimeAt
+ b1 = t1->getStartTimeAt(-1, d1);
+ if (b1) {
+ errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index -1");
+ }
+ b1 = t1->getStartTimeAt(0, d1);
+ if (!b1 || d1 != trtimes1[0]) {
+ errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned incorrect result for index 0");
+ }
+ b1 = t1->getStartTimeAt(1, d1);
+ if (b1) {
+ errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index 1");
+ }
+
+ // TimeArrayTimeZoneRule::getTimeType
+ if (t1->getTimeType() != DateTimeRule::UTC_TIME) {
+ errln("FAIL: TimeArrayTimeZoneRule t1 uses UTC_TIME, but different type is returned");
+ }
+ if (t4->getTimeType() != DateTimeRule::STANDARD_TIME) {
+ errln("FAIL: TimeArrayTimeZoneRule t4 uses STANDARD_TIME, but different type is returned");
+ }
+ if (t5->getTimeType() != DateTimeRule::WALL_TIME) {
+ errln("FAIL: TimeArrayTimeZoneRule t5 uses WALL_TIME, but different type is returned");
+ }
+
+ // TimeArrayTimeZoneRule::getFirstStart/getFinalStart
+ b1 = t1->getFirstStart(0, 0, d1);
+ if (!b1 || d1 != trtimes1[0]) {
+ errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t1");
+ }
+ b1 = t1->getFinalStart(0, 0, d1);
+ if (!b1 || d1 != trtimes1[0]) {
+ errln("FAIL: Bad final start time returned from TimeArrayTimeZoneRule t1");
+ }
+ b1 = t4->getFirstStart(-4*HOUR, 1*HOUR, d1);
+ if (!b1 || d1 != (trtimes1[0] + 4*HOUR)) {
+ errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t4");
+ }
+ b1 = t5->getFirstStart(-4*HOUR, 1*HOUR, d1);
+ if (!b1 || d1 != (trtimes1[0] + 3*HOUR)) {
+ errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t5");
+ }
+
+ // TimeArrayTimeZoneRule::getNextStart/getPreviousStart
+ b1 = t3->getNextStart(time1, -3*HOUR, 1*HOUR, FALSE, d1);
+ if (b1) {
+ errln("FAIL: getNextStart returned TRUE after the final transition for t3");
+ }
+ b1 = t3->getPreviousStart(time1, -3*HOUR, 1*HOUR, FALSE, d1);
+ if (!b1 || d1 != trtimes2[1]) {
+ errln("FAIL: Bad start time returned by getPreviousStart for t3");
+ } else {
+ b2 = t3->getPreviousStart(d1, -3*HOUR, 1*HOUR, FALSE, d2);
+ if (!b2 || d2 != trtimes2[0]) {
+ errln("FAIL: Bad start time returned by getPreviousStart for t3");
+ }
+ }
+ b1 = t3->getPreviousStart(time3, -3*HOUR, 1*HOUR, FALSE, d1); //time3 - year 1950, no result expected
+ if (b1) {
+ errln("FAIL: getPreviousStart returned TRUE before the first transition for t3");
+ }
+
+ // TimeArrayTimeZoneRule::isEquivalentTo
+ if (!t1->isEquivalentTo(*t2)) {
+ errln("FAIL: TimeArrayTimeZoneRule t1 is equivalent to t2, but returned FALSE");
+ }
+ if (t1->isEquivalentTo(*t3)) {
+ errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t3, but returned TRUE");
+ }
+ if (t1->isEquivalentTo(*t4)) {
+ errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t4, but returned TRUE");
+ }
+ if (t1->isEquivalentTo(*a1)) {
+ errln("FAIL: TimeArrayTimeZoneRule is not equivalent to AnnualTimeZoneRule, but returned TRUE");
+ }
+
+ delete dtr1;
+ delete dtr2;
+ delete dtr3;
+ delete dtr4;
+ delete a1;
+ delete a2;
+ delete a3;
+ delete i1;
+ delete i2;
+ delete i3;
+ delete t1;
+ delete t2;
+ delete t3;
+ delete t4;
+ delete t5;
+}
+
+/*
+ * API coverage test for BasicTimeZone APIs in SimpleTimeZone
+ */
+void
+TimeZoneRuleTest::TestSimpleTimeZoneCoverage(void) {
+ UDate time1 = getUTCMillis(1990, UCAL_JUNE, 1);
+ UDate time2 = getUTCMillis(2000, UCAL_JUNE, 1);
+
+ TimeZoneTransition tzt1, tzt2;
+ UBool avail1, avail2;
+ UErrorCode status = U_ZERO_ERROR;
+ const TimeZoneRule *trrules[2];
+ const InitialTimeZoneRule *ir = NULL;
+ int32_t numTzRules;
+
+ // BasicTimeZone API implementation in SimpleTimeZone
+ SimpleTimeZone *stz1 = new SimpleTimeZone(-5*HOUR, "GMT-5");
+
+ avail1 = stz1->getNextTransition(time1, FALSE, tzt1);
+ if (avail1) {
+ errln("FAIL: No transition must be returned by getNextTranstion for SimpleTimeZone with no DST rule");
+ }
+ avail1 = stz1->getPreviousTransition(time1, FALSE, tzt1);
+ if (avail1) {
+ errln("FAIL: No transition must be returned by getPreviousTransition for SimpleTimeZone with no DST rule");
+ }
+
+ numTzRules = stz1->countTransitionRules(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: countTransitionRules failed");
+ }
+ if (numTzRules != 0) {
+ errln((UnicodeString)"FAIL: countTransitionRules returned " + numTzRules);
+ }
+ numTzRules = 2;
+ stz1->getTimeZoneRules(ir, trrules, numTzRules, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getTimeZoneRules failed");
+ }
+ if (numTzRules != 0) {
+ errln("FAIL: Incorrect transition rule count");
+ }
+ if (ir == NULL || ir->getRawOffset() != stz1->getRawOffset()) {
+ errln("FAIL: Bad initial time zone rule");
+ }
+
+ // Set DST rule
+ stz1->setStartRule(UCAL_MARCH, 11, 2*HOUR, status); // March 11
+ stz1->setEndRule(UCAL_NOVEMBER, 1, UCAL_SUNDAY, 2*HOUR, status); // First Sunday in November
+ if (U_FAILURE(status)) {
+ errln("FAIL: Failed to set DST rules in a SimpleTimeZone");
+ }
+
+ avail1 = stz1->getNextTransition(time1, FALSE, tzt1);
+ if (!avail1) {
+ errln("FAIL: Non-null transition must be returned by getNextTranstion for SimpleTimeZone with a DST rule");
+ }
+ avail1 = stz1->getPreviousTransition(time1, FALSE, tzt1);
+ if (!avail1) {
+ errln("FAIL: Non-null transition must be returned by getPreviousTransition for SimpleTimeZone with a DST rule");
+ }
+
+ numTzRules = stz1->countTransitionRules(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: countTransitionRules failed");
+ }
+ if (numTzRules != 2) {
+ errln((UnicodeString)"FAIL: countTransitionRules returned " + numTzRules);
+ }
+
+ numTzRules = 2;
+ trrules[0] = NULL;
+ trrules[1] = NULL;
+ stz1->getTimeZoneRules(ir, trrules, numTzRules, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getTimeZoneRules failed");
+ }
+ if (numTzRules != 2) {
+ errln("FAIL: Incorrect transition rule count");
+ }
+ if (ir == NULL || ir->getRawOffset() != stz1->getRawOffset()) {
+ errln("FAIL: Bad initial time zone rule");
+ }
+ if (trrules[0] == NULL || trrules[0]->getRawOffset() != stz1->getRawOffset()) {
+ errln("FAIL: Bad transition rule 0");
+ }
+ if (trrules[1] == NULL || trrules[1]->getRawOffset() != stz1->getRawOffset()) {
+ errln("FAIL: Bad transition rule 1");
+ }
+
+ // Set DST start year
+ stz1->setStartYear(2007);
+ avail1 = stz1->getPreviousTransition(time1, FALSE, tzt1);
+ if (avail1) {
+ errln("FAIL: No transition must be returned before 1990");
+ }
+ avail1 = stz1->getNextTransition(time1, FALSE, tzt1); // transition after 1990-06-01
+ avail2 = stz1->getNextTransition(time2, FALSE, tzt2); // transition after 2000-06-01
+ if (!avail1 || !avail2 || tzt1 != tzt2) {
+ errln("FAIL: Bad transition returned by SimpleTimeZone::getNextTransition");
+ }
+ delete stz1;
+}
+
+/*
+ * API coverage test for VTimeZone
+ */
+void
+TimeZoneRuleTest::TestVTimeZoneCoverage(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString TZID("Europe/Moscow");
+
+ BasicTimeZone *otz = (BasicTimeZone*)TimeZone::createTimeZone(TZID);
+ VTimeZone *vtz = VTimeZone::createVTimeZoneByID(TZID);
+
+ // getOffset(era, year, month, day, dayOfWeek, milliseconds, ec)
+ int32_t offset1 = otz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(7 args) failed for otz");
+ }
+ int32_t offset2 = vtz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(7 args) failed for vtz");
+ }
+ if (offset1 != offset2) {
+ errln("FAIL: getOffset(7 args) returned different results in VTimeZone and OlsonTimeZone");
+ }
+
+ // getOffset(era, year, month, day, dayOfWeek, milliseconds, monthLength, ec)
+ offset1 = otz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, 31, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(8 args) failed for otz");
+ }
+ offset2 = vtz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, 31, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(8 args) failed for vtz");
+ }
+ if (offset1 != offset2) {
+ errln("FAIL: getOffset(8 args) returned different results in VTimeZone and OlsonTimeZone");
+ }
+
+
+ // getOffset(date, local, rawOffset, dstOffset, ec)
+ UDate t = Calendar::getNow();
+ int32_t rawOffset1, dstSavings1;
+ int32_t rawOffset2, dstSavings2;
+
+ otz->getOffset(t, FALSE, rawOffset1, dstSavings1, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(5 args) failed for otz");
+ }
+ vtz->getOffset(t, FALSE, rawOffset2, dstSavings2, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset(5 args) failed for vtz");
+ }
+ if (rawOffset1 != rawOffset2 || dstSavings1 != dstSavings2) {
+ errln("FAIL: getOffset(long,boolean,int[]) returned different results in VTimeZone and OlsonTimeZone");
+ }
+
+ // getRawOffset
+ if (otz->getRawOffset() != vtz->getRawOffset()) {
+ errln("FAIL: getRawOffset returned different results in VTimeZone and OlsonTimeZone");
+ }
+
+ // inDaylightTime
+ UBool inDst1, inDst2;
+ inDst1 = otz->inDaylightTime(t, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: inDaylightTime failed for otz");
+ }
+ inDst2 = vtz->inDaylightTime(t, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: inDaylightTime failed for vtz");
+ }
+ if (inDst1 != inDst2) {
+ errln("FAIL: inDaylightTime returned different results in VTimeZone and OlsonTimeZone");
+ }
+
+ // useDaylightTime
+ if (otz->useDaylightTime() != vtz->useDaylightTime()) {
+ errln("FAIL: useDaylightTime returned different results in VTimeZone and OlsonTimeZone");
+ }
+
+ // setRawOffset
+ const int32_t RAW = -10*HOUR;
+ VTimeZone *tmpvtz = (VTimeZone*)vtz->clone();
+ tmpvtz->setRawOffset(RAW);
+ if (tmpvtz->getRawOffset() != RAW) {
+ logln("setRawOffset is implemented in VTimeZone");
+ }
+
+ // hasSameRules
+ UBool bSame = otz->hasSameRules(*vtz);
+ logln((UnicodeString)"OlsonTimeZone::hasSameRules(VTimeZone) should return FALSE always for now - actual: " + bSame);
+
+ // getTZURL/setTZURL
+ UnicodeString TZURL("http://icu-project.org/timezone");
+ UnicodeString url;
+ if (vtz->getTZURL(url)) {
+ errln("FAIL: getTZURL returned TRUE");
+ }
+ vtz->setTZURL(TZURL);
+ if (!vtz->getTZURL(url) || url != TZURL) {
+ errln("FAIL: URL returned by getTZURL does not match the one set by setTZURL");
+ }
+
+ // getLastModified/setLastModified
+ UDate lastmod;
+ if (vtz->getLastModified(lastmod)) {
+ errln("FAIL: getLastModified returned TRUE");
+ }
+ vtz->setLastModified(t);
+ if (!vtz->getLastModified(lastmod) || lastmod != t) {
+ errln("FAIL: Date returned by getLastModified does not match the one set by setLastModified");
+ }
+
+ // getNextTransition/getPreviousTransition
+ UDate base = getUTCMillis(2007, UCAL_JULY, 1);
+ TimeZoneTransition tzt1, tzt2;
+ UBool btr1 = otz->getNextTransition(base, TRUE, tzt1);
+ UBool btr2 = vtz->getNextTransition(base, TRUE, tzt2);
+ if (!btr1 || !btr2 || tzt1 != tzt2) {
+ errln("FAIL: getNextTransition returned different results in VTimeZone and OlsonTimeZone");
+ }
+ btr1 = otz->getPreviousTransition(base, FALSE, tzt1);
+ btr2 = vtz->getPreviousTransition(base, FALSE, tzt2);
+ if (!btr1 || !btr2 || tzt1 != tzt2) {
+ errln("FAIL: getPreviousTransition returned different results in VTimeZone and OlsonTimeZone");
+ }
+
+ // TimeZoneTransition constructor/clone
+ TimeZoneTransition *tzt1c = tzt1.clone();
+ if (*tzt1c != tzt1 || !(*tzt1c == tzt1)) {
+ errln("FAIL: TimeZoneTransition tzt1c is equal to tzt1, but got wrong result");
+ }
+ delete tzt1c;
+ TimeZoneTransition tzt3(tzt1);
+ if (tzt3 != tzt1 || !(tzt3 == tzt1)) {
+ errln("FAIL: TimeZoneTransition tzt3 is equal to tzt1, but got wrong result");
+ }
+
+ // hasEquivalentTransitions
+ UDate time1 = getUTCMillis(1950, UCAL_JANUARY, 1);
+ UDate time2 = getUTCMillis(2020, UCAL_JANUARY, 1);
+ UBool equiv = vtz->hasEquivalentTransitions(*otz, time1, time2, FALSE, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: hasEquivalentTransitions failed for vtz/otz");
+ }
+ if (!equiv) {
+ errln("FAIL: hasEquivalentTransitons returned false for the same time zone");
+ }
+
+ // operator=/operator==/operator!=
+ VTimeZone *vtz1 = VTimeZone::createVTimeZoneByID("America/Los_Angeles");
+ if (*vtz1 == *vtz || !(*vtz1 != *vtz)) {
+ errln("FAIL: VTimeZone vtz1 is not equal to vtz, but got wrong result");
+ }
+ *vtz1 = *vtz;
+ if (*vtz1 != *vtz || !(*vtz1 == *vtz)) {
+ errln("FAIL: VTimeZone vtz1 is equal to vtz, but got wrong result");
+ }
+
+ delete otz;
+ delete vtz;
+ delete tmpvtz;
+ delete vtz1;
+}
+
+
+void
+TimeZoneRuleTest::TestVTimeZoneParse(void) {
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Trying to create VTimeZone from empty data
+ UnicodeString emptyData;
+ VTimeZone *empty = VTimeZone::createVTimeZone(emptyData, status);
+ if (U_SUCCESS(status) || empty != NULL) {
+ delete empty;
+ errln("FAIL: Non-null VTimeZone is returned for empty VTIMEZONE data");
+ }
+ status = U_ZERO_ERROR;
+
+ // Create VTimeZone for Asia/Tokyo
+ UnicodeString asiaTokyoID("Asia/Tokyo");
+ static const UChar asiaTokyo[] = {
+ /* "BEGIN:VTIMEZONE\x0D\x0A" */
+ 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
+ /* "TZID:Asia\x0D\x0A" */
+ 0x54,0x5A,0x49,0x44,0x3A,0x41,0x73,0x69,0x61,0x0D,0x0A,
+ /* "\x09/Tokyo\x0D\x0A" */
+ 0x09,0x2F,0x54,0x6F,0x6B,0x79,0x6F,0x0D,0x0A,
+ /* "BEGIN:STANDARD\x0D\x0A" */
+ 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
+ /* "TZOFFSETFROM:+0900\x0D\x0A" */
+ 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A,
+ /* "TZOFFSETTO:+0900\x0D\x0A" */
+ 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A,
+ /* "TZNAME:JST\x0D\x0A" */
+ 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x4A,0x53,0x54,0x0D,0x0A,
+ /* "DTSTART:19700101\x0D\x0A" */
+ 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x31,0x39,0x37,0x30,0x30,0x31,0x30,0x31,0x0D,0x0A,
+ /* " T000000\x0D\x0A" */
+ 0x20,0x54,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,
+ /* "END:STANDARD\x0D\x0A" */
+ 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
+ /* "END:VTIMEZONE" */
+ 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,
+ 0
+ };
+ VTimeZone *tokyo = VTimeZone::createVTimeZone(asiaTokyo, status);
+ if (U_FAILURE(status) || tokyo == NULL) {
+ errln("FAIL: Failed to create a VTimeZone tokyo");
+ } else {
+ // Check ID
+ UnicodeString tzid;
+ tokyo->getID(tzid);
+ if (tzid != asiaTokyoID) {
+ errln((UnicodeString)"FAIL: Invalid TZID: " + tzid);
+ }
+ // Make sure offsets are correct
+ int32_t rawOffset, dstSavings;
+ tokyo->getOffset(Calendar::getNow(), FALSE, rawOffset, dstSavings, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getOffset failed for tokyo");
+ }
+ if (rawOffset != 9*HOUR || dstSavings != 0) {
+ errln("FAIL: Bad offsets returned by a VTimeZone created for Tokyo");
+ }
+ }
+ delete tokyo;
+
+ // Create VTimeZone from VTIMEZONE data
+ static const UChar fooData[] = {
+ /* "BEGIN:VCALENDAR\x0D\x0A" */
+ 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52,0x0D,0x0A,
+ /* "BEGIN:VTIMEZONE\x0D\x0A" */
+ 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
+ /* "TZID:FOO\x0D\x0A" */
+ 0x54,0x5A,0x49,0x44,0x3A,0x46,0x4F,0x4F,0x0D,0x0A,
+ /* "BEGIN:STANDARD\x0D\x0A" */
+ 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
+ /* "TZOFFSETFROM:-0700\x0D\x0A" */
+ 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A,
+ /* "TZOFFSETTO:-0800\x0D\x0A" */
+ 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A,
+ /* "TZNAME:FST\x0D\x0A" */
+ 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x53,0x54,0x0D,0x0A,
+ /* "DTSTART:20071010T010000\x0D\x0A" */
+ 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x32,0x30,0x30,0x37,0x31,0x30,0x31,0x30,0x54,0x30,0x31,0x30,0x30,0x30,0x30,0x0D,0x0A,
+ /* "RRULE:FREQ=YEARLY;BYDAY=WE;BYMONTHDAY=10,11,12,13,14,15,16;BYMONTH=10\x0D\x0A" */
+ 0x52,0x52,0x55,0x4C,0x45,0x3A,0x46,0x52,0x45,0x51,0x3D,0x59,0x45,0x41,0x52,0x4C,0x59,0x3B,0x42,0x59,0x44,0x41,0x59,0x3D,0x57,0x45,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x44,0x41,0x59,0x3D,0x31,0x30,0x2C,0x31,0x31,0x2C,0x31,0x32,0x2C,0x31,0x33,0x2C,0x31,0x34,0x2C,0x31,0x35,0x2C,0x31,0x36,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x3D,0x31,0x30,0x0D,0x0A,
+ /* "END:STANDARD\x0D\x0A" */
+ 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A,
+ /* "BEGIN:DAYLIGHT\x0D\x0A" */
+ 0x42,0x45,0x47,0x49,0x4E,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A,
+ /* "TZOFFSETFROM:-0800\x0D\x0A" */
+ 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A,
+ /* "TZOFFSETTO:-0700\x0D\x0A" */
+ 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A,
+ /* "TZNAME:FDT\x0D\x0A" */
+ 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x44,0x54,0x0D,0x0A,
+ /* "DTSTART:20070415T010000\x0D\x0A" */
+ 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x32,0x30,0x30,0x37,0x30,0x34,0x31,0x35,0x54,0x30,0x31,0x30,0x30,0x30,0x30,0x0D,0x0A,
+ /* "RRULE:FREQ=YEARLY;BYMONTHDAY=15;BYMONTH=4\x0D\x0A" */
+ 0x52,0x52,0x55,0x4C,0x45,0x3A,0x46,0x52,0x45,0x51,0x3D,0x59,0x45,0x41,0x52,0x4C,0x59,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x44,0x41,0x59,0x3D,0x31,0x35,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x3D,0x34,0x0D,0x0A,
+ /* "END:DAYLIGHT\x0D\x0A" */
+ 0x45,0x4E,0x44,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A,
+ /* "END:VTIMEZONE\x0D\x0A" */
+ 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A,
+ /* "END:VCALENDAR" */
+ 0x45,0x4E,0x44,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52,
+ 0
+ };
+
+ VTimeZone *foo = VTimeZone::createVTimeZone(fooData, status);
+ if (U_FAILURE(status) || foo == NULL) {
+ errln("FAIL: Failed to create a VTimeZone foo");
+ } else {
+ // Write VTIMEZONE data
+ UnicodeString fooData2;
+ foo->write(getUTCMillis(2005, UCAL_JANUARY, 1), fooData2, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Failed to write VTIMEZONE data for foo");
+ }
+ logln(fooData2);
+ }
+ delete foo;
+}
+
+//----------- private test helpers -------------------------------------------------
+
+UDate
+TimeZoneRuleTest::getUTCMillis(int32_t y, int32_t m, int32_t d,
+ int32_t hr, int32_t min, int32_t sec, int32_t msec) {
+ UErrorCode status = U_ZERO_ERROR;
+ const TimeZone *tz = TimeZone::getGMT();
+ Calendar *cal = Calendar::createInstance(*tz, status);
+ if (U_FAILURE(status)) {
+ delete cal;
+ errln("FAIL: Calendar::createInstance failed");
+ return 0.0;
+ }
+ cal->set(y, m, d, hr, min, sec);
+ cal->set(UCAL_MILLISECOND, msec);
+ UDate utc = cal->getTime(status);
+ if (U_FAILURE(status)) {
+ delete cal;
+ errln("FAIL: Calendar::getTime failed");
+ return 0.0;
+ }
+ delete cal;
+ return utc;
+}
+
+/*
+ * Check if a time shift really happens on each transition returned by getNextTransition or
+ * getPreviousTransition in the specified time range
+ */
+void
+TimeZoneRuleTest::verifyTransitions(BasicTimeZone& icutz, UDate start, UDate end) {
+ UErrorCode status = U_ZERO_ERROR;
+ UDate time;
+ int32_t raw, dst, raw0, dst0;
+ TimeZoneTransition tzt, tzt0;
+ UBool avail;
+ UBool first = TRUE;
+ UnicodeString tzid;
+
+ // Ascending
+ time = start;
+ while (TRUE) {
+ avail = icutz.getNextTransition(time, FALSE, tzt);
+ if (!avail) {
+ break;
+ }
+ time = tzt.getTime();
+ if (time >= end) {
+ break;
+ }
+ icutz.getOffset(time, FALSE, raw, dst, status);
+ icutz.getOffset(time - 1, FALSE, raw0, dst0, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Error in getOffset");
+ break;
+ }
+
+ if (raw == raw0 && dst == dst0) {
+ errln((UnicodeString)"FAIL: False transition returned by getNextTransition for "
+ + icutz.getID(tzid) + " at " + dateToString(time));
+ }
+ if (!first &&
+ (tzt0.getTo()->getRawOffset() != tzt.getFrom()->getRawOffset()
+ || tzt0.getTo()->getDSTSavings() != tzt.getFrom()->getDSTSavings())) {
+ errln((UnicodeString)"FAIL: TO rule of the previous transition does not match FROM rule of this transtion at "
+ + dateToString(time) + " for " + icutz.getID(tzid));
+ }
+ tzt0 = tzt;
+ first = FALSE;
+ }
+
+ // Descending
+ first = TRUE;
+ time = end;
+ while(true) {
+ avail = icutz.getPreviousTransition(time, FALSE, tzt);
+ if (!avail) {
+ break;
+ }
+ time = tzt.getTime();
+ if (time <= start) {
+ break;
+ }
+ icutz.getOffset(time, FALSE, raw, dst, status);
+ icutz.getOffset(time - 1, FALSE, raw0, dst0, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Error in getOffset");
+ break;
+ }
+
+ if (raw == raw0 && dst == dst0) {
+ errln((UnicodeString)"FAIL: False transition returned by getPreviousTransition for "
+ + icutz.getID(tzid) + " at " + dateToString(time));
+ }
+
+ if (!first &&
+ (tzt0.getFrom()->getRawOffset() != tzt.getTo()->getRawOffset()
+ || tzt0.getFrom()->getDSTSavings() != tzt.getTo()->getDSTSavings())) {
+ errln((UnicodeString)"FAIL: TO rule of the next transition does not match FROM rule in this transtion at "
+ + dateToString(time) + " for " + icutz.getID(tzid));
+ }
+ tzt0 = tzt;
+ first = FALSE;
+ }
+}
+
+/*
+ * Compare all time transitions in 2 time zones in the specified time range in ascending order
+ */
+void
+TimeZoneRuleTest::compareTransitionsAscending(BasicTimeZone& z1, BasicTimeZone& z2,
+ UDate start, UDate end, UBool inclusive) {
+ UnicodeString zid1, zid2;
+ TimeZoneTransition tzt1, tzt2;
+ UBool avail1, avail2;
+ UBool inRange1, inRange2;
+
+ z1.getID(zid1);
+ z2.getID(zid2);
+
+ UDate time = start;
+ while (TRUE) {
+ avail1 = z1.getNextTransition(time, inclusive, tzt1);
+ avail2 = z2.getNextTransition(time, inclusive, tzt2);
+
+ inRange1 = inRange2 = FALSE;
+ if (avail1) {
+ if (tzt1.getTime() < end || (inclusive && tzt1.getTime() == end)) {
+ inRange1 = TRUE;
+ }
+ }
+ if (avail2) {
+ if (tzt2.getTime() < end || (inclusive && tzt2.getTime() == end)) {
+ inRange2 = TRUE;
+ }
+ }
+ if (!inRange1 && !inRange2) {
+ // No more transition in the range
+ break;
+ }
+ if (!inRange1) {
+ errln((UnicodeString)"FAIL: " + zid1 + " does not have any transitions after "
+ + dateToString(time) + " before " + dateToString(end));
+ break;
+ }
+ if (!inRange2) {
+ errln((UnicodeString)"FAIL: " + zid2 + " does not have any transitions after "
+ + dateToString(time) + " before " + dateToString(end));
+ break;
+ }
+ if (tzt1.getTime() != tzt2.getTime()) {
+ errln((UnicodeString)"FAIL: First transition after " + dateToString(time) + " "
+ + zid1 + "[" + dateToString(tzt1.getTime()) + "] "
+ + zid2 + "[" + dateToString(tzt2.getTime()) + "]");
+ break;
+ }
+ time = tzt1.getTime();
+ if (inclusive) {
+ time += 1;
+ }
+ }
+}
+
+/*
+ * Compare all time transitions in 2 time zones in the specified time range in descending order
+ */
+void
+TimeZoneRuleTest::compareTransitionsDescending(BasicTimeZone& z1, BasicTimeZone& z2,
+ UDate start, UDate end, UBool inclusive) {
+ UnicodeString zid1, zid2;
+ TimeZoneTransition tzt1, tzt2;
+ UBool avail1, avail2;
+ UBool inRange1, inRange2;
+
+ z1.getID(zid1);
+ z2.getID(zid2);
+
+ UDate time = end;
+ while (TRUE) {
+ avail1 = z1.getPreviousTransition(time, inclusive, tzt1);
+ avail2 = z2.getPreviousTransition(time, inclusive, tzt2);
+
+ inRange1 = inRange2 = FALSE;
+ if (avail1) {
+ if (tzt1.getTime() > start || (inclusive && tzt1.getTime() == start)) {
+ inRange1 = TRUE;
+ }
+ }
+ if (avail2) {
+ if (tzt2.getTime() > start || (inclusive && tzt2.getTime() == start)) {
+ inRange2 = TRUE;
+ }
+ }
+ if (!inRange1 && !inRange2) {
+ // No more transition in the range
+ break;
+ }
+ if (!inRange1) {
+ errln((UnicodeString)"FAIL: " + zid1 + " does not have any transitions before "
+ + dateToString(time) + " after " + dateToString(start));
+ break;
+ }
+ if (!inRange2) {
+ errln((UnicodeString)"FAIL: " + zid2 + " does not have any transitions before "
+ + dateToString(time) + " after " + dateToString(start));
+ break;
+ }
+ if (tzt1.getTime() != tzt2.getTime()) {
+ errln((UnicodeString)"FAIL: Last transition before " + dateToString(time) + " "
+ + zid1 + "[" + dateToString(tzt1.getTime()) + "] "
+ + zid2 + "[" + dateToString(tzt2.getTime()) + "]");
+ break;
+ }
+ time = tzt1.getTime();
+ if (inclusive) {
+ time -= 1;
+ }
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tzrulets.h b/Build/source/libs/icu/icu-xetex/test/intltest/tzrulets.h
new file mode 100644
index 00000000000..643d2719d83
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tzrulets.h
@@ -0,0 +1,50 @@
+/*
+*******************************************************************************
+* Copyright (C) 2007, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+*******************************************************************************
+*/
+
+#ifndef _TIMEZONERULETEST_
+#define _TIMEZONERULETEST_
+
+#include "unicode/utypes.h"
+#include "caltztst.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * Tests for TimeZoneRule, RuleBasedTimeZone and VTimeZone
+ */
+class TimeZoneRuleTest : public CalendarTimeZoneTest {
+ // IntlTest override
+ void runIndexedTest(int32_t index, UBool exec, const char*& name, char* par);
+public:
+ void TestSimpleRuleBasedTimeZone(void);
+ void TestHistoricalRuleBasedTimeZone(void);
+ void TestOlsonTransition(void);
+ void TestRBTZTransition(void);
+ void TestHasEquivalentTransitions(void);
+ void TestVTimeZoneRoundTrip(void);
+ void TestVTimeZoneRoundTripPartial(void);
+ void TestVTimeZoneSimpleWrite(void);
+ void TestVTimeZoneHeaderProps(void);
+ void TestGetSimpleRules(void);
+ void TestTimeZoneRuleCoverage(void);
+ void TestSimpleTimeZoneCoverage(void);
+ void TestVTimeZoneCoverage(void);
+ void TestVTimeZoneParse(void);
+
+private:
+ void verifyTransitions(BasicTimeZone& icutz, UDate start, UDate end);
+ void compareTransitionsAscending(BasicTimeZone& z1, BasicTimeZone& z2,
+ UDate start, UDate end, UBool inclusive);
+ void compareTransitionsDescending(BasicTimeZone& z1, BasicTimeZone& z2,
+ UDate start, UDate end, UBool inclusive);
+ UDate getUTCMillis(int32_t year, int32_t month, int32_t dom,
+ int32_t hour=0, int32_t min=0, int32_t sec=0, int32_t msec=0);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // _TIMEZONERULETEST_
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tztest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/tztest.cpp
new file mode 100644
index 00000000000..0c5b07ccd21
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tztest.cpp
@@ -0,0 +1,1664 @@
+/***********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation
+ * and others. All Rights Reserved.
+ ***********************************************************************/
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/timezone.h"
+#include "unicode/simpletz.h"
+#include "unicode/calendar.h"
+#include "unicode/gregocal.h"
+#include "unicode/resbund.h"
+#include "unicode/strenum.h"
+#include "tztest.h"
+#include "cmemory.h"
+#include "putilimp.h"
+#include "cstring.h"
+#include "olsontz.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+#define CASE(id,test) case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); logln(""); \
+ test(); \
+ } \
+ break
+
+// *****************************************************************************
+// class TimeZoneTest
+// *****************************************************************************
+
+void TimeZoneTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite TestTimeZone");
+ switch (index) {
+ CASE(0, TestPRTOffset);
+ CASE(1, TestVariousAPI518);
+ CASE(2, TestGetAvailableIDs913);
+ CASE(3, TestGenericAPI);
+ CASE(4, TestRuleAPI);
+ CASE(5, TestShortZoneIDs);
+ CASE(6, TestCustomParse);
+ CASE(7, TestDisplayName);
+ CASE(8, TestDSTSavings);
+ CASE(9, TestAlternateRules);
+ CASE(10,TestCountries);
+ CASE(11,TestHistorical);
+ CASE(12,TestEquivalentIDs);
+ CASE(13, TestAliasedNames);
+ CASE(14, TestFractionalDST);
+ CASE(15, TestFebruary);
+ default: name = ""; break;
+ }
+}
+
+const int32_t TimeZoneTest::millisPerHour = 3600000;
+
+// ---------------------------------------------------------------------------------
+
+/**
+ * Generic API testing for API coverage.
+ */
+void
+TimeZoneTest::TestGenericAPI()
+{
+ UnicodeString id("NewGMT");
+ int32_t offset = 12345;
+
+ SimpleTimeZone *zone = new SimpleTimeZone(offset, id);
+ if (zone->useDaylightTime()) errln("FAIL: useDaylightTime should return FALSE");
+
+ TimeZone* zoneclone = zone->clone();
+ if (!(*zoneclone == *zone)) errln("FAIL: clone or operator== failed");
+ zoneclone->setID("abc");
+ if (!(*zoneclone != *zone)) errln("FAIL: clone or operator!= failed");
+ delete zoneclone;
+
+ zoneclone = zone->clone();
+ if (!(*zoneclone == *zone)) errln("FAIL: clone or operator== failed");
+ zoneclone->setRawOffset(45678);
+ if (!(*zoneclone != *zone)) errln("FAIL: clone or operator!= failed");
+
+ SimpleTimeZone copy(*zone);
+ if (!(copy == *zone)) errln("FAIL: copy constructor or operator== failed");
+ copy = *(SimpleTimeZone*)zoneclone;
+ if (!(copy == *zoneclone)) errln("FAIL: assignment operator or operator== failed");
+
+ TimeZone* saveDefault = TimeZone::createDefault();
+ logln((UnicodeString)"TimeZone::createDefault() => " + saveDefault->getID(id));
+ TimeZone* pstZone = TimeZone::createTimeZone("America/Los_Angeles");
+
+ logln("call uprv_timezone() which uses the host");
+ logln("to get the difference in seconds between coordinated universal");
+ logln("time and local time. E.g., -28,800 for PST (GMT-8hrs)");
+
+ int32_t tzoffset = uprv_timezone();
+ logln(UnicodeString("Value returned from uprv_timezone = ") + tzoffset);
+ // Invert sign because UNIX semantics are backwards
+ if (tzoffset < 0)
+ tzoffset = -tzoffset;
+ if ((*saveDefault == *pstZone) && (tzoffset != 28800)) {
+ errln("FAIL: t_timezone may be incorrect. It is not 28800");
+ }
+
+ if ((tzoffset % 900) != 0) {
+ errln("FAIL: t_timezone may be incorrect. It is not a multiple of 15min. It is %d", tzoffset);
+ }
+
+ TimeZone::adoptDefault(zone);
+ TimeZone* defaultzone = TimeZone::createDefault();
+ if (defaultzone == zone ||
+ !(*defaultzone == *zone))
+ errln("FAIL: createDefault failed");
+ TimeZone::adoptDefault(saveDefault);
+ delete defaultzone;
+ delete zoneclone;
+ delete pstZone;
+
+ UErrorCode status = U_ZERO_ERROR;
+ const char* tzver = TimeZone::getTZDataVersion(status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: getTZDataVersion failed");
+ } else if (uprv_strlen(tzver) != 5 /* 4 digits + 1 letter */) {
+ errln((UnicodeString)"FAIL: getTZDataVersion returned " + tzver);
+ } else {
+ logln((UnicodeString)"tzdata version: " + tzver);
+ }
+}
+
+// ---------------------------------------------------------------------------------
+
+/**
+ * Test the setStartRule/setEndRule API calls.
+ */
+void
+TimeZoneTest::TestRuleAPI()
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ UDate offset = 60*60*1000*1.75; // Pick a weird offset
+ SimpleTimeZone *zone = new SimpleTimeZone((int32_t)offset, "TestZone");
+ if (zone->useDaylightTime()) errln("FAIL: useDaylightTime should return FALSE");
+
+ // Establish our expected transition times. Do this with a non-DST
+ // calendar with the (above) declared local offset.
+ GregorianCalendar *gc = new GregorianCalendar(*zone, status);
+ if (failure(status, "new GregorianCalendar")) return;
+ gc->clear();
+ gc->set(1990, UCAL_MARCH, 1);
+ UDate marchOneStd = gc->getTime(status); // Local Std time midnight
+ gc->clear();
+ gc->set(1990, UCAL_JULY, 1);
+ UDate julyOneStd = gc->getTime(status); // Local Std time midnight
+ if (failure(status, "GregorianCalendar::getTime")) return;
+
+ // Starting and ending hours, WALL TIME
+ int32_t startHour = (int32_t)(2.25 * 3600000);
+ int32_t endHour = (int32_t)(3.5 * 3600000);
+
+ zone->setStartRule(UCAL_MARCH, 1, 0, startHour, status);
+ zone->setEndRule (UCAL_JULY, 1, 0, endHour, status);
+
+ delete gc;
+ gc = new GregorianCalendar(*zone, status);
+ if (failure(status, "new GregorianCalendar")) return;
+
+ UDate marchOne = marchOneStd + startHour;
+ UDate julyOne = julyOneStd + endHour - 3600000; // Adjust from wall to Std time
+
+ UDate expMarchOne = 636251400000.0;
+ if (marchOne != expMarchOne)
+ {
+ errln((UnicodeString)"FAIL: Expected start computed as " + marchOne +
+ " = " + dateToString(marchOne));
+ logln((UnicodeString)" Should be " + expMarchOne +
+ " = " + dateToString(expMarchOne));
+ }
+
+ UDate expJulyOne = 646793100000.0;
+ if (julyOne != expJulyOne)
+ {
+ errln((UnicodeString)"FAIL: Expected start computed as " + julyOne +
+ " = " + dateToString(julyOne));
+ logln((UnicodeString)" Should be " + expJulyOne +
+ " = " + dateToString(expJulyOne));
+ }
+
+ testUsingBinarySearch(*zone, date(90, UCAL_JANUARY, 1), date(90, UCAL_JUNE, 15), marchOne);
+ testUsingBinarySearch(*zone, date(90, UCAL_JUNE, 1), date(90, UCAL_DECEMBER, 31), julyOne);
+
+ if (zone->inDaylightTime(marchOne - 1000, status) ||
+ !zone->inDaylightTime(marchOne, status))
+ errln("FAIL: Start rule broken");
+ if (!zone->inDaylightTime(julyOne - 1000, status) ||
+ zone->inDaylightTime(julyOne, status))
+ errln("FAIL: End rule broken");
+
+ zone->setStartYear(1991);
+ if (zone->inDaylightTime(marchOne, status) ||
+ zone->inDaylightTime(julyOne - 1000, status))
+ errln("FAIL: Start year broken");
+
+ failure(status, "TestRuleAPI");
+ delete gc;
+ delete zone;
+}
+
+void
+TimeZoneTest::findTransition(const TimeZone& tz,
+ UDate min, UDate max) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString id,s;
+ UBool startsInDST = tz.inDaylightTime(min, ec);
+ if (failure(ec, "TimeZone::inDaylightTime")) return;
+ if (tz.inDaylightTime(max, ec) == startsInDST) {
+ logln("Error: " + tz.getID(id) + ".inDaylightTime(" + dateToString(min) + ") = " + (startsInDST?"TRUE":"FALSE") +
+ ", inDaylightTime(" + dateToString(max) + ") = " + (startsInDST?"TRUE":"FALSE"));
+ return;
+ }
+ if (failure(ec, "TimeZone::inDaylightTime")) return;
+ while ((max - min) > INTERVAL) {
+ UDate mid = (min + max) / 2;
+ if (tz.inDaylightTime(mid, ec) == startsInDST) {
+ min = mid;
+ } else {
+ max = mid;
+ }
+ if (failure(ec, "TimeZone::inDaylightTime")) return;
+ }
+ min = 1000.0 * uprv_floor(min/1000.0);
+ max = 1000.0 * uprv_floor(max/1000.0);
+ logln(tz.getID(id) + " Before: " + min/1000 + " = " +
+ dateToString(min,s,tz));
+ logln(tz.getID(id) + " After: " + max/1000 + " = " +
+ dateToString(max,s,tz));
+}
+
+void
+TimeZoneTest::testUsingBinarySearch(const TimeZone& tz,
+ UDate min, UDate max,
+ UDate expectedBoundary)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UBool startsInDST = tz.inDaylightTime(min, status);
+ if (failure(status, "TimeZone::inDaylightTime")) return;
+ if (tz.inDaylightTime(max, status) == startsInDST) {
+ logln("Error: inDaylightTime(" + dateToString(max) + ") != " + ((!startsInDST)?"TRUE":"FALSE"));
+ return;
+ }
+ if (failure(status, "TimeZone::inDaylightTime")) return;
+ while ((max - min) > INTERVAL) {
+ UDate mid = (min + max) / 2;
+ if (tz.inDaylightTime(mid, status) == startsInDST) {
+ min = mid;
+ } else {
+ max = mid;
+ }
+ if (failure(status, "TimeZone::inDaylightTime")) return;
+ }
+ logln(UnicodeString("Binary Search Before: ") + uprv_floor(0.5 + min) + " = " + dateToString(min));
+ logln(UnicodeString("Binary Search After: ") + uprv_floor(0.5 + max) + " = " + dateToString(max));
+ UDate mindelta = expectedBoundary - min;
+ UDate maxdelta = max - expectedBoundary;
+ if (mindelta >= 0 &&
+ mindelta <= INTERVAL &&
+ maxdelta >= 0 &&
+ maxdelta <= INTERVAL)
+ logln(UnicodeString("PASS: Expected bdry: ") + expectedBoundary + " = " + dateToString(expectedBoundary));
+ else
+ errln(UnicodeString("FAIL: Expected bdry: ") + expectedBoundary + " = " + dateToString(expectedBoundary));
+}
+
+const UDate TimeZoneTest::INTERVAL = 100;
+
+// ---------------------------------------------------------------------------------
+
+// -------------------------------------
+
+/**
+ * Test the offset of the PRT timezone.
+ */
+void
+TimeZoneTest::TestPRTOffset()
+{
+ TimeZone* tz = TimeZone::createTimeZone("PRT");
+ if (tz == 0) {
+ errln("FAIL: TimeZone(PRT) is null");
+ }
+ else {
+ int32_t expectedHour = -4;
+ double expectedOffset = (((double)expectedHour) * millisPerHour);
+ double foundOffset = tz->getRawOffset();
+ int32_t foundHour = (int32_t)foundOffset / millisPerHour;
+ if (expectedOffset != foundOffset) {
+ errln("FAIL: Offset for PRT should be %d, found %d", expectedHour, foundHour);
+ } else {
+ logln("PASS: Offset for PRT should be %d, found %d", expectedHour, foundHour);
+ }
+ }
+ delete tz;
+}
+
+// -------------------------------------
+
+/**
+ * Regress a specific bug with a sequence of API calls.
+ */
+void
+TimeZoneTest::TestVariousAPI518()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ TimeZone* time_zone = TimeZone::createTimeZone("PST");
+ UDate d = date(97, UCAL_APRIL, 30);
+ UnicodeString str;
+ logln("The timezone is " + time_zone->getID(str));
+ if (!time_zone->inDaylightTime(d, status)) errln("FAIL: inDaylightTime returned FALSE");
+ if (U_FAILURE(status)) { errln("FAIL: TimeZone::inDaylightTime failed"); return; }
+ if (!time_zone->useDaylightTime()) errln("FAIL: useDaylightTime returned FALSE");
+ if (time_zone->getRawOffset() != - 8 * millisPerHour) errln("FAIL: getRawOffset returned wrong value");
+ GregorianCalendar *gc = new GregorianCalendar(status);
+ if (U_FAILURE(status)) { errln("FAIL: Couldn't create GregorianCalendar"); return; }
+ gc->setTime(d, status);
+ if (U_FAILURE(status)) { errln("FAIL: GregorianCalendar::setTime failed"); return; }
+ if (time_zone->getOffset(gc->AD, gc->get(UCAL_YEAR, status), gc->get(UCAL_MONTH, status),
+ gc->get(UCAL_DATE, status), (uint8_t)gc->get(UCAL_DAY_OF_WEEK, status), 0, status) != - 7 * millisPerHour)
+ errln("FAIL: getOffset returned wrong value");
+ if (U_FAILURE(status)) { errln("FAIL: GregorianCalendar::set failed"); return; }
+ delete gc;
+ delete time_zone;
+}
+
+// -------------------------------------
+
+/**
+ * Test the call which retrieves the available IDs.
+ */
+void
+TimeZoneTest::TestGetAvailableIDs913()
+{
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t i;
+
+#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
+ // Test legacy API -- remove these tests when the corresponding API goes away (duh)
+ int32_t numIDs = -1;
+ const UnicodeString** ids = TimeZone::createAvailableIDs(numIDs);
+ if (ids == 0 || numIDs < 1) {
+ errln("FAIL: createAvailableIDs()");
+ } else {
+ UnicodeString buf("TimeZone::createAvailableIDs() = { ");
+ for(i=0; i<numIDs; ++i) {
+ if (i) buf.append(", ");
+ buf.append(*ids[i]);
+ }
+ buf.append(" } ");
+ logln(buf + numIDs);
+ // we own the array; the caller owns the contained strings (yuck)
+ uprv_free(ids);
+ }
+
+ numIDs = -1;
+ ids = TimeZone::createAvailableIDs(-8*U_MILLIS_PER_HOUR, numIDs);
+ if (ids == 0 || numIDs < 1) {
+ errln("FAIL: createAvailableIDs(-8:00)");
+ } else {
+ UnicodeString buf("TimeZone::createAvailableIDs(-8:00) = { ");
+ for(i=0; i<numIDs; ++i) {
+ if (i) buf.append(", ");
+ buf.append(*ids[i]);
+ }
+ buf.append(" } ");
+ logln(buf + numIDs);
+ // we own the array; the caller owns the contained strings (yuck)
+ uprv_free(ids);
+ }
+ numIDs = -1;
+ ids = TimeZone::createAvailableIDs("US", numIDs);
+ if (ids == 0 || numIDs < 1) {
+ errln("FAIL: createAvailableIDs(US) ids=%d, numIDs=%d", ids, numIDs);
+ } else {
+ UnicodeString buf("TimeZone::createAvailableIDs(US) = { ");
+ for(i=0; i<numIDs; ++i) {
+ if (i) buf.append(", ");
+ buf.append(*ids[i]);
+ }
+ buf.append(" } ");
+ logln(buf + numIDs);
+ // we own the array; the caller owns the contained strings (yuck)
+ uprv_free(ids);
+ }
+#endif
+
+ UnicodeString str;
+ UnicodeString *buf = new UnicodeString("TimeZone::createEnumeration() = { ");
+ int32_t s_length;
+ StringEnumeration* s = TimeZone::createEnumeration();
+ s_length = s->count(ec);
+ for (i = 0; i < s_length;++i) {
+ if (i > 0) *buf += ", ";
+ if ((i & 1) == 0) {
+ *buf += *s->snext(ec);
+ } else {
+ *buf += UnicodeString(s->next(NULL, ec), "");
+ }
+
+ if((i % 5) == 4) {
+ // replace s with a clone of itself
+ StringEnumeration *s2 = s->clone();
+ if(s2 == NULL || s_length != s2->count(ec)) {
+ errln("TimezoneEnumeration.clone() failed");
+ } else {
+ delete s;
+ s = s2;
+ }
+ }
+ }
+ *buf += " };";
+ logln(*buf);
+
+ /* Confirm that the following zones can be retrieved: The first
+ * zone, the last zone, and one in-between. This tests the binary
+ * search through the system zone data.
+ */
+ s->reset(ec);
+ int32_t middle = s_length/2;
+ for (i=0; i<s_length; ++i) {
+ const UnicodeString* id = s->snext(ec);
+ if (i==0 || i==middle || i==(s_length-1)) {
+ TimeZone *z = TimeZone::createTimeZone(*id);
+ if (z == 0) {
+ errln(UnicodeString("FAIL: createTimeZone(") +
+ *id + ") -> 0");
+ } else if (z->getID(str) != *id) {
+ errln(UnicodeString("FAIL: createTimeZone(") +
+ *id + ") -> zone " + str);
+ } else {
+ logln(UnicodeString("OK: createTimeZone(") +
+ *id + ") succeeded");
+ }
+ delete z;
+ }
+ }
+ delete s;
+
+ buf->truncate(0);
+ *buf += "TimeZone::createEnumeration(GMT+01:00) = { ";
+
+ s = TimeZone::createEnumeration(1 * U_MILLIS_PER_HOUR);
+ s_length = s->count(ec);
+ for (i = 0; i < s_length;++i) {
+ if (i > 0) *buf += ", ";
+ *buf += *s->snext(ec);
+ }
+ delete s;
+ *buf += " };";
+ logln(*buf);
+
+
+ buf->truncate(0);
+ *buf += "TimeZone::createEnumeration(US) = { ";
+
+ s = TimeZone::createEnumeration("US");
+ s_length = s->count(ec);
+ for (i = 0; i < s_length;++i) {
+ if (i > 0) *buf += ", ";
+ *buf += *s->snext(ec);
+ }
+ *buf += " };";
+ logln(*buf);
+
+ TimeZone *tz = TimeZone::createTimeZone("PST");
+ if (tz != 0) logln("getTimeZone(PST) = " + tz->getID(str));
+ else errln("FAIL: getTimeZone(PST) = null");
+ delete tz;
+ tz = TimeZone::createTimeZone("America/Los_Angeles");
+ if (tz != 0) logln("getTimeZone(America/Los_Angeles) = " + tz->getID(str));
+ else errln("FAIL: getTimeZone(PST) = null");
+ delete tz;
+
+ // @bug 4096694
+ tz = TimeZone::createTimeZone("NON_EXISTENT");
+ UnicodeString temp;
+ if (tz == 0)
+ errln("FAIL: getTimeZone(NON_EXISTENT) = null");
+ else if (tz->getID(temp) != "GMT")
+ errln("FAIL: getTimeZone(NON_EXISTENT) = " + temp);
+ delete tz;
+
+ delete buf;
+ delete s;
+}
+
+
+/**
+ * NOTE: As of ICU 2.8, this test confirms that the "tz.alias"
+ * file, used to build ICU alias zones, is working. It also
+ * looks at some genuine Olson compatibility IDs. [aliu]
+ *
+ * This test is problematic. It should really just confirm that
+ * the list of compatibility zone IDs exist and are somewhat
+ * meaningful (that is, they aren't all aliases of GMT). It goes a
+ * bit further -- it hard-codes expectations about zone behavior,
+ * when in fact zones are redefined quite frequently. ICU's build
+ * process means that it is easy to update ICU to contain the
+ * latest Olson zone data, but if a zone tested here changes, then
+ * this test will fail. I have updated the test for 1999j data,
+ * but further updates will probably be required. Note that some
+ * of the concerts listed below no longer apply -- in particular,
+ * we do NOT overwrite real UNIX zones with 3-letter IDs. There
+ * are two points of overlap as of 1999j: MET and EET. These are
+ * both real UNIX zones, so we just use the official
+ * definition. This test has been updated to reflect this.
+ * 12/3/99 aliu
+ *
+ * Added tests for additional zones and aliases from the icuzones file.
+ * Markus Scherer 2006-nov-06
+ *
+ * [srl - from java - 7/5/1998]
+ * @bug 4130885
+ * Certain short zone IDs, used since 1.1.x, are incorrect.
+ *
+ * The worst of these is:
+ *
+ * "CAT" (Central African Time) should be GMT+2:00, but instead returns a
+ * zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST,
+ * or AZOST, depending on which zone is meant, but in no case is it CAT.
+ *
+ * Other wrong zone IDs:
+ *
+ * ECT (European Central Time) GMT+1:00: ECT is Ecuador Time,
+ * GMT-5:00. European Central time is abbreviated CEST.
+ *
+ * SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time,
+ * GMT-11:00. Solomon Island time is SBT.
+ *
+ * NST (New Zealand Time) GMT+12:00. NST is the abbreviation for
+ * Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST.
+ *
+ * AST (Alaska Standard Time) GMT-9:00. [This has already been noted in
+ * another bug.] It should be "AKST". AST is Atlantic Standard Time,
+ * GMT-4:00.
+ *
+ * PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time,
+ * GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct
+ * from MST with daylight savings.
+ *
+ * In addition to these problems, a number of zones are FAKE. That is, they
+ * don't match what people use in the real world.
+ *
+ * FAKE zones:
+ *
+ * EET (should be EEST)
+ * ART (should be EEST)
+ * MET (should be IRST)
+ * NET (should be AMST)
+ * PLT (should be PKT)
+ * BST (should be BDT)
+ * VST (should be ICT)
+ * CTT (should be CST) +
+ * ACT (should be CST) +
+ * AET (should be EST) +
+ * MIT (should be WST) +
+ * IET (should be EST) +
+ * PRT (should be AST) +
+ * CNT (should be NST)
+ * AGT (should be ARST)
+ * BET (should be EST) +
+ *
+ * + A zone with the correct name already exists and means something
+ * else. E.g., EST usually indicates the US Eastern zone, so it cannot be
+ * used for Brazil (BET).
+ */
+void TimeZoneTest::TestShortZoneIDs()
+{
+ int32_t i;
+ // Create a small struct to hold the array
+ struct
+ {
+ const char *id;
+ int32_t offset;
+ UBool daylight;
+ }
+ kReferenceList [] =
+ {
+ {"MIT", -660, FALSE},
+ {"HST", -600, FALSE},
+ {"AST", -540, TRUE},
+ {"PST", -480, TRUE},
+ {"PNT", -420, FALSE},
+ {"MST", -420, FALSE}, // updated Aug 2003 aliu
+ {"CST", -360, TRUE},
+ {"IET", -300, TRUE}, // updated Jan 2006 srl
+ {"EST", -300, FALSE}, // updated Aug 2003 aliu
+ {"PRT", -240, FALSE},
+ {"CNT", -210, TRUE},
+ {"AGT", -180, FALSE}, // updated 26 Sep 2000 aliu
+ {"BET", -180, TRUE},
+ // "CAT", -60, FALSE, // Wrong:
+ // As of bug 4130885, fix CAT (Central Africa)
+ {"CAT", 120, FALSE}, // Africa/Harare
+ {"GMT", 0, FALSE},
+ {"UTC", 0, FALSE}, // ** srl: seems broken in C++
+ {"ECT", 60, TRUE},
+ {"ART", 120, TRUE},
+ {"EET", 120, TRUE},
+ {"EAT", 180, FALSE},
+ {"MET", 60, TRUE}, // updated 12/3/99 aliu
+ {"NET", 240, TRUE}, // updated 12/3/99 aliu
+ {"PLT", 300, FALSE}, // updated Aug 2003 aliu
+ {"IST", 330, FALSE},
+ {"BST", 360, FALSE},
+ {"VST", 420, FALSE},
+ {"CTT", 480, FALSE}, // updated Aug 2003 aliu
+ {"JST", 540, FALSE},
+ {"ACT", 570, FALSE}, // updated Aug 2003 aliu
+ {"AET", 600, TRUE},
+ {"SST", 660, FALSE},
+ // "NST", 720, FALSE,
+ // As of bug 4130885, fix NST (New Zealand)
+ {"NST", 720, TRUE}, // Pacific/Auckland
+
+ // From icuzones:
+ {"Etc/Unknown", 0, FALSE},
+
+ {"SystemV/AST4ADT", -240, TRUE},
+ {"SystemV/EST5EDT", -300, TRUE},
+ {"SystemV/CST6CDT", -360, TRUE},
+ {"SystemV/MST7MDT", -420, TRUE},
+ {"SystemV/PST8PDT", -480, TRUE},
+ {"SystemV/YST9YDT", -540, TRUE},
+ {"SystemV/AST4", -240, FALSE},
+ {"SystemV/EST5", -300, FALSE},
+ {"SystemV/CST6", -360, FALSE},
+ {"SystemV/MST7", -420, FALSE},
+ {"SystemV/PST8", -480, FALSE},
+ {"SystemV/YST9", -540, FALSE},
+ {"SystemV/HST10", -600, FALSE},
+
+ {"",0,FALSE}
+ };
+
+
+ for(i=0;kReferenceList[i].id[0];i++) {
+ UnicodeString itsID(kReferenceList[i].id);
+ UBool ok = TRUE;
+ // Check existence.
+ TimeZone *tz = TimeZone::createTimeZone(itsID);
+ if (!tz || (kReferenceList[i].offset != 0 && *tz == *TimeZone::getGMT())) {
+ errln("FAIL: Time Zone " + itsID + " does not exist!");
+ continue;
+ }
+
+ // Check daylight usage.
+ UBool usesDaylight = tz->useDaylightTime();
+ if (usesDaylight != kReferenceList[i].daylight) {
+ errln("FAIL: Time Zone " + itsID + " use daylight is " +
+ (usesDaylight?"TRUE":"FALSE") +
+ " but it should be " +
+ ((kReferenceList[i].daylight)?"TRUE":"FALSE"));
+ ok = FALSE;
+ }
+
+ // Check offset
+ int32_t offsetInMinutes = tz->getRawOffset()/60000;
+ if (offsetInMinutes != kReferenceList[i].offset) {
+ errln("FAIL: Time Zone " + itsID + " raw offset is " +
+ offsetInMinutes +
+ " but it should be " + kReferenceList[i].offset);
+ ok = FALSE;
+ }
+
+ if (ok) {
+ logln("OK: " + itsID +
+ " useDaylightTime() & getRawOffset() as expected");
+ }
+ delete tz;
+ }
+
+
+ // OK now test compat
+ logln("Testing for compatibility zones");
+
+ const char* compatibilityMap[] = {
+ // This list is copied from tz.alias. If tz.alias
+ // changes, this list must be updated. Current as of Mar 2007
+ "ACT", "Australia/Darwin",
+ "AET", "Australia/Sydney",
+ "AGT", "America/Buenos_Aires",
+ "ART", "Africa/Cairo",
+ "AST", "America/Anchorage",
+ "BET", "America/Sao_Paulo",
+ "BST", "Asia/Dhaka", // # spelling changed in 2000h; was Asia/Dacca
+ "CAT", "Africa/Harare",
+ "CNT", "America/St_Johns",
+ "CST", "America/Chicago",
+ "CTT", "Asia/Shanghai",
+ "EAT", "Africa/Addis_Ababa",
+ "ECT", "Europe/Paris",
+ // EET Europe/Istanbul # EET is a standard UNIX zone
+ // "EST", "America/New_York", # Defined as -05:00
+ // "HST", "Pacific/Honolulu", # Defined as -10:00
+ "IET", "America/Indianapolis",
+ "IST", "Asia/Calcutta",
+ "JST", "Asia/Tokyo",
+ // MET Asia/Tehran # MET is a standard UNIX zone
+ "MIT", "Pacific/Apia",
+ // "MST", "America/Denver", # Defined as -07:00
+ "NET", "Asia/Yerevan",
+ "NST", "Pacific/Auckland",
+ "PLT", "Asia/Karachi",
+ "PNT", "America/Phoenix",
+ "PRT", "America/Puerto_Rico",
+ "PST", "America/Los_Angeles",
+ "SST", "Pacific/Guadalcanal",
+ "UTC", "Etc/GMT",
+ "VST", "Asia/Saigon",
+ "","",""
+ };
+
+ for (i=0;*compatibilityMap[i];i+=2) {
+ UnicodeString itsID;
+
+ const char *zone1 = compatibilityMap[i];
+ const char *zone2 = compatibilityMap[i+1];
+
+ TimeZone *tz1 = TimeZone::createTimeZone(zone1);
+ TimeZone *tz2 = TimeZone::createTimeZone(zone2);
+
+ if (!tz1) {
+ errln(UnicodeString("FAIL: Could not find short ID zone ") + zone1);
+ }
+ if (!tz2) {
+ errln(UnicodeString("FAIL: Could not find long ID zone ") + zone2);
+ }
+
+ if (tz1 && tz2) {
+ // make NAME same so comparison will only look at the rest
+ tz2->setID(tz1->getID(itsID));
+
+ if (*tz1 != *tz2) {
+ errln("FAIL: " + UnicodeString(zone1) +
+ " != " + UnicodeString(zone2));
+ } else {
+ logln("OK: " + UnicodeString(zone1) +
+ " == " + UnicodeString(zone2));
+ }
+ }
+
+ delete tz1;
+ delete tz2;
+ }
+}
+
+
+/**
+ * Utility function for TestCustomParse
+ */
+UnicodeString& TimeZoneTest::formatOffset(int32_t offset, UnicodeString &rv) {
+ rv.remove();
+ UChar sign = 0x002B;
+ if (offset < 0) {
+ sign = 0x002D;
+ offset = -offset;
+ }
+
+ int32_t s = offset % 60;
+ offset /= 60;
+ int32_t m = offset % 60;
+ int32_t h = offset / 60;
+
+ rv += (UChar)(sign);
+ if (h >= 10) {
+ rv += (UChar)(0x0030 + (h/10));
+ } else {
+ rv += (UChar)0x0030;
+ }
+ rv += (UChar)(0x0030 + (h%10));
+
+ rv += (UChar)0x003A; /* ':' */
+ if (m >= 10) {
+ rv += (UChar)(0x0030 + (m/10));
+ } else {
+ rv += (UChar)0x0030;
+ }
+ rv += (UChar)(0x0030 + (m%10));
+
+ if (s) {
+ rv += (UChar)0x003A; /* ':' */
+ if (s >= 10) {
+ rv += (UChar)(0x0030 + (s/10));
+ } else {
+ rv += (UChar)0x0030;
+ }
+ rv += (UChar)(0x0030 + (s%10));
+ }
+ return rv;
+}
+
+/**
+ * Utility function for TestCustomParse, generating time zone ID
+ * string for the give offset.
+ */
+UnicodeString& TimeZoneTest::formatTZID(int32_t offset, UnicodeString &rv) {
+ rv.remove();
+ UChar sign = 0x002B;
+ if (offset < 0) {
+ sign = 0x002D;
+ offset = -offset;
+ }
+
+ int32_t s = offset % 60;
+ offset /= 60;
+ int32_t m = offset % 60;
+ int32_t h = offset / 60;
+
+ rv += "GMT";
+ rv += (UChar)(sign);
+ if (h >= 10) {
+ rv += (UChar)(0x0030 + (h/10));
+ } else {
+ rv += (UChar)0x0030;
+ }
+ rv += (UChar)(0x0030 + (h%10));
+
+ if (m >= 10) {
+ rv += (UChar)(0x0030 + (m/10));
+ } else {
+ rv += (UChar)0x0030;
+ }
+ rv += (UChar)(0x0030 + (m%10));
+
+ if (s) {
+ if (s >= 10) {
+ rv += (UChar)(0x0030 + (s/10));
+ } else {
+ rv += (UChar)0x0030;
+ }
+ rv += (UChar)(0x0030 + (s%10));
+ }
+ return rv;
+}
+
+/**
+ * As part of the VM fix (see CCC approved RFE 4028006, bug
+ * 4044013), TimeZone.getTimeZone() has been modified to recognize
+ * generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and
+ * GMT[+-]hh. Test this behavior here.
+ *
+ * @bug 4044013
+ */
+void TimeZoneTest::TestCustomParse()
+{
+ int32_t i;
+ const int32_t kUnparseable = 604800; // the number of seconds in a week. More than any offset should be.
+
+ struct
+ {
+ const char *customId;
+ int32_t expectedOffset;
+ }
+ kData[] =
+ {
+ // ID Expected offset in seconds
+ {"GMT", kUnparseable}, //Isn't custom. [returns normal GMT]
+ {"GMT-YOUR.AD.HERE", kUnparseable},
+ {"GMT0", kUnparseable},
+ {"GMT+0", (0)},
+ {"GMT+1", (1*60*60)},
+ {"GMT-0030", (-30*60)},
+ {"GMT+15:99", kUnparseable},
+ {"GMT+", kUnparseable},
+ {"GMT-", kUnparseable},
+ {"GMT+0:", kUnparseable},
+ {"GMT-:", kUnparseable},
+ {"GMT-YOUR.AD.HERE", kUnparseable},
+ {"GMT+0010", (10*60)}, // Interpret this as 00:10
+ {"GMT-10", (-10*60*60)},
+ {"GMT+30", kUnparseable},
+ {"GMT-3:30", (-(3*60+30)*60)},
+ {"GMT-230", (-(2*60+30)*60)},
+ {"GMT+05:13:05", ((5*60+13)*60+5)},
+ {"GMT-71023", (-((7*60+10)*60+23))},
+ {"GMT+01:23:45:67", kUnparseable},
+ {"GMT+01:234", kUnparseable},
+ {"GMT-2:31:123", kUnparseable},
+ {"GMT+3:75", kUnparseable},
+ {"GMT-01010101", kUnparseable},
+ {0, 0}
+ };
+
+ for (i=0; kData[i].customId != 0; i++) {
+ UnicodeString id(kData[i].customId);
+ int32_t exp = kData[i].expectedOffset;
+ TimeZone *zone = TimeZone::createTimeZone(id);
+ UnicodeString itsID, temp;
+
+ if (zone->getDynamicClassID() == OlsonTimeZone::getStaticClassID()) {
+ logln(id + " -> Olson time zone");
+ } else {
+ zone->getID(itsID);
+ int32_t ioffset = zone->getRawOffset()/1000;
+ UnicodeString offset, expectedID;
+ formatOffset(ioffset, offset);
+ formatTZID(ioffset, expectedID);
+ logln(id + " -> " + itsID + " " + offset);
+ if (exp == kUnparseable && itsID != "GMT") {
+ errln("Expected parse failure for " + id +
+ ", got offset of " + offset +
+ ", id " + itsID);
+ }
+ // JDK 1.3 creates custom zones with the ID "Custom"
+ // JDK 1.4 creates custom zones with IDs of the form "GMT+02:00"
+ // ICU creates custom zones with IDs of the form "GMT+0200"
+ else if (exp != kUnparseable && (ioffset != exp || itsID != expectedID)) {
+ errln("Expected offset of " + formatOffset(exp, temp) +
+ ", id " + expectedID +
+ ", for " + id +
+ ", got offset of " + offset +
+ ", id " + itsID);
+ }
+ }
+ delete zone;
+ }
+}
+
+void
+TimeZoneTest::TestAliasedNames()
+{
+ struct {
+ const char *from;
+ const char *to;
+ } kData[] = {
+ /* Generated by org.unicode.cldr.tool.CountItems */
+
+ /* zoneID, canonical zoneID */
+ {"Africa/Timbuktu", "Africa/Bamako"},
+ {"America/Argentina/Buenos_Aires", "America/Buenos_Aires"},
+ {"America/Argentina/Catamarca", "America/Catamarca"},
+ {"America/Argentina/ComodRivadavia", "America/Catamarca"},
+ {"America/Argentina/Cordoba", "America/Cordoba"},
+ {"America/Argentina/Jujuy", "America/Jujuy"},
+ {"America/Argentina/Mendoza", "America/Mendoza"},
+ {"America/Atka", "America/Adak"},
+ {"America/Ensenada", "America/Tijuana"},
+ {"America/Fort_Wayne", "America/Indiana/Indianapolis"},
+ {"America/Indianapolis", "America/Indiana/Indianapolis"},
+ {"America/Knox_IN", "America/Indiana/Knox"},
+ {"America/Louisville", "America/Kentucky/Louisville"},
+ {"America/Porto_Acre", "America/Rio_Branco"},
+ {"America/Rosario", "America/Cordoba"},
+ {"America/Virgin", "America/St_Thomas"},
+ {"Asia/Ashkhabad", "Asia/Ashgabat"},
+ {"Asia/Chungking", "Asia/Chongqing"},
+ {"Asia/Dacca", "Asia/Dhaka"},
+ {"Asia/Istanbul", "Europe/Istanbul"},
+ {"Asia/Macao", "Asia/Macau"},
+ {"Asia/Tel_Aviv", "Asia/Jerusalem"},
+ {"Asia/Thimbu", "Asia/Thimphu"},
+ {"Asia/Ujung_Pandang", "Asia/Makassar"},
+ {"Asia/Ulan_Bator", "Asia/Ulaanbaatar"},
+ {"Australia/ACT", "Australia/Sydney"},
+ {"Australia/Canberra", "Australia/Sydney"},
+ {"Australia/LHI", "Australia/Lord_Howe"},
+ {"Australia/NSW", "Australia/Sydney"},
+ {"Australia/North", "Australia/Darwin"},
+ {"Australia/Queensland", "Australia/Brisbane"},
+ {"Australia/South", "Australia/Adelaide"},
+ {"Australia/Tasmania", "Australia/Hobart"},
+ {"Australia/Victoria", "Australia/Melbourne"},
+ {"Australia/West", "Australia/Perth"},
+ {"Australia/Yancowinna", "Australia/Broken_Hill"},
+ {"Brazil/Acre", "America/Rio_Branco"},
+ {"Brazil/DeNoronha", "America/Noronha"},
+ {"Brazil/East", "America/Sao_Paulo"},
+ {"Brazil/West", "America/Manaus"},
+ {"Canada/Atlantic", "America/Halifax"},
+ {"Canada/Central", "America/Winnipeg"},
+ {"Canada/East-Saskatchewan", "America/Regina"},
+ {"Canada/Eastern", "America/Toronto"},
+ {"Canada/Mountain", "America/Edmonton"},
+ {"Canada/Newfoundland", "America/St_Johns"},
+ {"Canada/Pacific", "America/Vancouver"},
+ {"Canada/Saskatchewan", "America/Regina"},
+ {"Canada/Yukon", "America/Whitehorse"},
+ {"Chile/Continental", "America/Santiago"},
+ {"Chile/EasterIsland", "Pacific/Easter"},
+ {"Cuba", "America/Havana"},
+ {"Egypt", "Africa/Cairo"},
+ {"Eire", "Europe/Dublin"},
+ {"Etc/GMT+0", "Etc/GMT"},
+ {"Etc/GMT-0", "Etc/GMT"},
+ {"Etc/GMT0", "Etc/GMT"},
+ {"Etc/Greenwich", "Etc/GMT"},
+ {"Etc/UCT", "Etc/GMT"},
+ {"Etc/UTC", "Etc/GMT"},
+ {"Etc/Universal", "Etc/GMT"},
+ {"Etc/Zulu", "Etc/GMT"},
+ {"Europe/Belfast", "Europe/London"},
+ {"Europe/Nicosia", "Asia/Nicosia"},
+ {"Europe/Tiraspol", "Europe/Chisinau"},
+ {"GB", "Europe/London"},
+ {"GB-Eire", "Europe/London"},
+ {"GMT", "Etc/GMT"},
+ {"GMT+0", "Etc/GMT"},
+ {"GMT-0", "Etc/GMT"},
+ {"GMT0", "Etc/GMT"},
+ {"Greenwich", "Etc/GMT"},
+ {"Hongkong", "Asia/Hong_Kong"},
+ {"Iceland", "Atlantic/Reykjavik"},
+ {"Iran", "Asia/Tehran"},
+ {"Israel", "Asia/Jerusalem"},
+ {"Jamaica", "America/Jamaica"},
+ {"Japan", "Asia/Tokyo"},
+ {"Kwajalein", "Pacific/Kwajalein"},
+ {"Libya", "Africa/Tripoli"},
+ {"Mexico/BajaNorte", "America/Tijuana"},
+ {"Mexico/BajaSur", "America/Mazatlan"},
+ {"Mexico/General", "America/Mexico_City"},
+ {"NZ", "Pacific/Auckland"},
+ {"NZ-CHAT", "Pacific/Chatham"},
+ {"Navajo", "America/Shiprock"},
+ {"PRC", "Asia/Shanghai"},
+ {"Pacific/Samoa", "Pacific/Pago_Pago"},
+ {"Pacific/Yap", "Pacific/Truk"},
+ {"Poland", "Europe/Warsaw"},
+ {"Portugal", "Europe/Lisbon"},
+ {"ROC", "Asia/Taipei"},
+ {"ROK", "Asia/Seoul"},
+ {"Singapore", "Asia/Singapore"},
+ {"Turkey", "Europe/Istanbul"},
+ {"UCT", "Etc/GMT"},
+ {"US/Alaska", "America/Anchorage"},
+ {"US/Aleutian", "America/Adak"},
+ {"US/Arizona", "America/Phoenix"},
+ {"US/Central", "America/Chicago"},
+ {"US/East-Indiana", "America/Indiana/Indianapolis"},
+ {"US/Eastern", "America/New_York"},
+ {"US/Hawaii", "Pacific/Honolulu"},
+ {"US/Indiana-Starke", "America/Indiana/Knox"},
+ {"US/Michigan", "America/Detroit"},
+ {"US/Mountain", "America/Denver"},
+ {"US/Pacific", "America/Los_Angeles"},
+ {"US/Pacific-New", "America/Los_Angeles"},
+ {"US/Samoa", "Pacific/Pago_Pago"},
+ {"UTC", "Etc/GMT"},
+ {"Universal", "Etc/GMT"},
+ {"W-SU", "Europe/Moscow"},
+ {"Zulu", "Etc/GMT"},
+ /* Total: 113 */
+
+ };
+
+ TimeZone::EDisplayType styles[] = { TimeZone::SHORT, TimeZone::LONG };
+ UBool useDst[] = { FALSE, TRUE };
+ int32_t noLoc = uloc_countAvailable();
+
+ int32_t i, j, k, loc;
+ UnicodeString fromName, toName;
+ TimeZone *from = NULL, *to = NULL;
+ for(i = 0; i < (int32_t)(sizeof(kData)/sizeof(kData[0])); i++) {
+ from = TimeZone::createTimeZone(kData[i].from);
+ to = TimeZone::createTimeZone(kData[i].to);
+ if(!from->hasSameRules(*to)) {
+ errln("different at %i\n", i);
+ }
+ if(!quick) {
+ for(loc = 0; loc < noLoc; loc++) {
+ const char* locale = uloc_getAvailable(loc);
+ for(j = 0; j < (int32_t)(sizeof(styles)/sizeof(styles[0])); j++) {
+ for(k = 0; k < (int32_t)(sizeof(useDst)/sizeof(useDst[0])); k++) {
+ fromName.remove();
+ toName.remove();
+ from->getDisplayName(useDst[k], styles[j],locale, fromName);
+ to->getDisplayName(useDst[k], styles[j], locale, toName);
+ if(fromName.compare(toName) != 0) {
+ errln("Fail: Expected "+toName+" but got " + prettify(fromName)
+ + " for locale: " + locale + " index: "+ loc
+ + " to id "+ kData[i].to
+ + " from id " + kData[i].from);
+ }
+ }
+ }
+ }
+ } else {
+ fromName.remove();
+ toName.remove();
+ from->getDisplayName(fromName);
+ to->getDisplayName(toName);
+ if(fromName.compare(toName) != 0) {
+ errln("Fail: Expected "+toName+" but got " + fromName);
+ }
+ }
+ delete from;
+ delete to;
+ }
+}
+
+/**
+ * Test the basic functionality of the getDisplayName() API.
+ *
+ * @bug 4112869
+ * @bug 4028006
+ *
+ * See also API change request A41.
+ *
+ * 4/21/98 - make smarter, so the test works if the ext resources
+ * are present or not.
+ */
+void
+TimeZoneTest::TestDisplayName()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t i;
+ TimeZone *zone = TimeZone::createTimeZone("PST");
+ UnicodeString name;
+ zone->getDisplayName(Locale::getEnglish(), name);
+ logln("PST->" + name);
+ if (name.compare("Pacific Standard Time") != 0)
+ errln("Fail: Expected \"Pacific Standard Time\" but got " + name);
+
+ //*****************************************************************
+ // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
+ // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
+ // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
+ //*****************************************************************
+ struct
+ {
+ UBool useDst;
+ TimeZone::EDisplayType style;
+ const char *expect;
+ } kData[] = {
+ {FALSE, TimeZone::SHORT, "PST"},
+ {TRUE, TimeZone::SHORT, "PDT"},
+ {FALSE, TimeZone::LONG, "Pacific Standard Time"},
+ {TRUE, TimeZone::LONG, "Pacific Daylight Time"},
+
+ {FALSE, TimeZone::LONG, ""}
+ };
+
+ for (i=0; kData[i].expect[0] != '\0'; i++)
+ {
+ name.remove();
+ name = zone->getDisplayName(kData[i].useDst,
+ kData[i].style,
+ Locale::getEnglish(), name);
+ if (name.compare(kData[i].expect) != 0)
+ errln("Fail: Expected " + UnicodeString(kData[i].expect) + "; got " + name);
+ logln("PST [with options]->" + name);
+ }
+ for (i=0; kData[i].expect[0] != '\0'; i++)
+ {
+ name.remove();
+ name = zone->getDisplayName(kData[i].useDst,
+ kData[i].style, name);
+ if (name.compare(kData[i].expect) != 0)
+ errln("Fail: Expected " + UnicodeString(kData[i].expect) + "; got " + name);
+ logln("PST [with options]->" + name);
+ }
+
+
+ // Make sure that we don't display the DST name by constructing a fake
+ // PST zone that has DST all year long.
+ SimpleTimeZone *zone2 = new SimpleTimeZone(0, "PST");
+
+ zone2->setStartRule(UCAL_JANUARY, 1, 0, 0, status);
+ zone2->setEndRule(UCAL_DECEMBER, 31, 0, 0, status);
+
+ UnicodeString inDaylight;
+ if (zone2->inDaylightTime(UDate(0), status)) {
+ inDaylight = UnicodeString("TRUE");
+ } else {
+ inDaylight = UnicodeString("FALSE");
+ }
+ logln(UnicodeString("Modified PST inDaylightTime->") + inDaylight );
+ if(U_FAILURE(status))
+ {
+ errln("Some sort of error..." + UnicodeString(u_errorName(status))); // REVISIT
+ }
+ name.remove();
+ name = zone2->getDisplayName(Locale::getEnglish(),name);
+ logln("Modified PST->" + name);
+ if (name.compare("Pacific Standard Time") != 0)
+ errln("Fail: Expected \"Pacific Standard Time\"");
+
+ // Make sure we get the default display format for Locales
+ // with no display name data.
+ Locale mt_MT("mt_MT");
+ name.remove();
+ name = zone->getDisplayName(mt_MT,name);
+ //*****************************************************************
+ // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
+ // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
+ // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
+ //*****************************************************************
+ logln("PST(mt_MT)->" + name);
+
+ // *** REVISIT SRL how in the world do I check this? looks java specific.
+ // Now be smart -- check to see if zh resource is even present.
+ // If not, we expect the en fallback behavior.
+ ResourceBundle enRB(NULL,
+ Locale::getEnglish(), status);
+ if(U_FAILURE(status))
+ errln("Couldn't get ResourceBundle for en");
+
+ ResourceBundle mtRB(NULL,
+ mt_MT, status);
+ //if(U_FAILURE(status))
+ // errln("Couldn't get ResourceBundle for mt_MT");
+
+ UBool noZH = U_FAILURE(status);
+
+ if (noZH) {
+ logln("Warning: Not testing the mt_MT behavior because resource is absent");
+ if (name != "Pacific Standard Time")
+ errln("Fail: Expected Pacific Standard Time");
+ }
+
+
+ if (name.compare("GMT-08:00") &&
+ name.compare("GMT-8:00") &&
+ name.compare("GMT-0800") &&
+ name.compare("GMT-800")) {
+ errln(UnicodeString("Fail: Expected GMT-08:00 or something similar for PST in mt_MT but got ") + name );
+ errln("************************************************************");
+ errln("THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED");
+ errln("************************************************************");
+ }
+
+ // Now try a non-existent zone
+ delete zone2;
+ zone2 = new SimpleTimeZone(90*60*1000, "xyzzy");
+ name.remove();
+ name = zone2->getDisplayName(Locale::getEnglish(),name);
+ logln("GMT+90min->" + name);
+ if (name.compare("GMT+01:30") &&
+ name.compare("GMT+1:30") &&
+ name.compare("GMT+0130") &&
+ name.compare("GMT+130"))
+ errln("Fail: Expected GMT+01:30 or something similar");
+ name.truncate(0);
+ zone2->getDisplayName(name);
+ logln("GMT+90min->" + name);
+ if (name.compare("GMT+01:30") &&
+ name.compare("GMT+1:30") &&
+ name.compare("GMT+0130") &&
+ name.compare("GMT+130"))
+ errln("Fail: Expected GMT+01:30 or something similar");
+ // clean up
+ delete zone;
+ delete zone2;
+}
+
+/**
+ * @bug 4107276
+ */
+void
+TimeZoneTest::TestDSTSavings()
+{
+ UErrorCode status = U_ZERO_ERROR;
+ // It might be better to find a way to integrate this test into the main TimeZone
+ // tests above, but I don't have time to figure out how to do this (or if it's
+ // even really a good idea). Let's consider that a future. --rtg 1/27/98
+ SimpleTimeZone *tz = new SimpleTimeZone(-5 * U_MILLIS_PER_HOUR, "dstSavingsTest",
+ UCAL_MARCH, 1, 0, 0, UCAL_SEPTEMBER, 1, 0, 0,
+ (int32_t)(0.5 * U_MILLIS_PER_HOUR), status);
+ if(U_FAILURE(status))
+ errln("couldn't create TimeZone");
+
+ if (tz->getRawOffset() != -5 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("Got back a raw offset of ") + (tz->getRawOffset() / U_MILLIS_PER_HOUR) +
+ " hours instead of -5 hours.");
+ if (!tz->useDaylightTime())
+ errln("Test time zone should use DST but claims it doesn't.");
+ if (tz->getDSTSavings() != 0.5 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("Set DST offset to 0.5 hour, but got back ") + (tz->getDSTSavings() /
+ U_MILLIS_PER_HOUR) + " hours instead.");
+
+ int32_t offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JANUARY, 1,
+ UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status);
+ if (offset != -5 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JUNE, 1, UCAL_MONDAY,
+ 10 * U_MILLIS_PER_HOUR,status);
+ if (offset != -4.5 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ tz->setDSTSavings(U_MILLIS_PER_HOUR, status);
+ offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JANUARY, 1,
+ UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status);
+ if (offset != -5 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ offset = tz->getOffset(GregorianCalendar::AD, 1998, UCAL_JUNE, 1, UCAL_MONDAY,
+ 10 * U_MILLIS_PER_HOUR,status);
+ if (offset != -4 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ delete tz;
+}
+
+/**
+ * @bug 4107570
+ */
+void
+TimeZoneTest::TestAlternateRules()
+{
+ // Like TestDSTSavings, this test should probably be integrated somehow with the main
+ // test at the top of this class, but I didn't have time to figure out how to do that.
+ // --rtg 1/28/98
+
+ SimpleTimeZone tz(-5 * U_MILLIS_PER_HOUR, "alternateRuleTest");
+
+ // test the day-of-month API
+ UErrorCode status = U_ZERO_ERROR;
+ tz.setStartRule(UCAL_MARCH, 10, 12 * U_MILLIS_PER_HOUR, status);
+ if(U_FAILURE(status))
+ errln("tz.setStartRule failed");
+ tz.setEndRule(UCAL_OCTOBER, 20, 12 * U_MILLIS_PER_HOUR, status);
+ if(U_FAILURE(status))
+ errln("tz.setStartRule failed");
+
+ int32_t offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 5,
+ UCAL_THURSDAY, 10 * U_MILLIS_PER_HOUR,status);
+ if (offset != -5 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10AM, 3/5/98 should have been -5 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 15,
+ UCAL_SUNDAY, 10 * millisPerHour,status);
+ if (offset != -4 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10AM, 3/15/98 should have been -4 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 15,
+ UCAL_THURSDAY, 10 * millisPerHour,status);
+ if (offset != -4 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ") + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 25,
+ UCAL_SUNDAY, 10 * millisPerHour,status);
+ if (offset != -5 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10AM, 10/25/98 should have been -5 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ // test the day-of-week-after-day-in-month API
+ tz.setStartRule(UCAL_MARCH, 10, UCAL_FRIDAY, 12 * millisPerHour, TRUE, status);
+ if(U_FAILURE(status))
+ errln("tz.setStartRule failed");
+ tz.setEndRule(UCAL_OCTOBER, 20, UCAL_FRIDAY, 12 * millisPerHour, FALSE, status);
+ if(U_FAILURE(status))
+ errln("tz.setStartRule failed");
+
+ offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 11,
+ UCAL_WEDNESDAY, 10 * millisPerHour,status);
+ if (offset != -5 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10AM, 3/11/98 should have been -5 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_MARCH, 14,
+ UCAL_SATURDAY, 10 * millisPerHour,status);
+ if (offset != -4 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10AM, 3/14/98 should have been -4 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 15,
+ UCAL_THURSDAY, 10 * millisPerHour,status);
+ if (offset != -4 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10AM, 10/15/98 should have been -4 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+
+ offset = tz.getOffset(GregorianCalendar::AD, 1998, UCAL_OCTOBER, 17,
+ UCAL_SATURDAY, 10 * millisPerHour,status);
+ if (offset != -5 * U_MILLIS_PER_HOUR)
+ errln(UnicodeString("The offset for 10AM, 10/17/98 should have been -5 hours, but we got ")
+ + (offset / U_MILLIS_PER_HOUR) + " hours.");
+}
+
+void TimeZoneTest::TestFractionalDST() {
+ const char* tzName = "Australia/Lord_Howe"; // 30 min offset
+ TimeZone* tz_icu = TimeZone::createTimeZone(tzName);
+ int dst_icu = tz_icu->getDSTSavings();
+ UnicodeString id;
+ int32_t expected = 1800000;
+ if (expected != dst_icu) {
+ errln(UnicodeString("java reports dst savings of ") + expected +
+ " but icu reports " + dst_icu +
+ " for tz " + tz_icu->getID(id));
+ } else {
+ logln(UnicodeString("both java and icu report dst savings of ") + expected + " for tz " + tz_icu->getID(id));
+ }
+ delete tz_icu;
+}
+
+/**
+ * Test country code support. Jitterbug 776.
+ */
+void TimeZoneTest::TestCountries() {
+ // Make sure America/Los_Angeles is in the "US" group, and
+ // Asia/Tokyo isn't. Vice versa for the "JP" group.
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t n;
+ StringEnumeration* s = TimeZone::createEnumeration("US");
+ n = s->count(ec);
+ UBool la = FALSE, tokyo = FALSE;
+ UnicodeString laZone("America/Los_Angeles", "");
+ UnicodeString tokyoZone("Asia/Tokyo", "");
+ int32_t i;
+
+ if (s == NULL || n <= 0) {
+ errln("FAIL: TimeZone::createEnumeration() returned nothing");
+ return;
+ }
+ for (i=0; i<n; ++i) {
+ const UnicodeString* id = s->snext(ec);
+ if (*id == (laZone)) {
+ la = TRUE;
+ }
+ if (*id == (tokyoZone)) {
+ tokyo = TRUE;
+ }
+ }
+ if (!la || tokyo) {
+ errln("FAIL: " + laZone + " in US = " + la);
+ errln("FAIL: " + tokyoZone + " in US = " + tokyo);
+ }
+ delete s;
+
+ s = TimeZone::createEnumeration("JP");
+ n = s->count(ec);
+ la = FALSE; tokyo = FALSE;
+
+ for (i=0; i<n; ++i) {
+ const UnicodeString* id = s->snext(ec);
+ if (*id == (laZone)) {
+ la = TRUE;
+ }
+ if (*id == (tokyoZone)) {
+ tokyo = TRUE;
+ }
+ }
+ if (la || !tokyo) {
+ errln("FAIL: " + laZone + " in JP = " + la);
+ errln("FAIL: " + tokyoZone + " in JP = " + tokyo);
+ }
+ StringEnumeration* s1 = TimeZone::createEnumeration("US");
+ StringEnumeration* s2 = TimeZone::createEnumeration("US");
+ for(i=0;i<n;++i){
+ const UnicodeString* id1 = s1->snext(ec);
+ if(id1==NULL || U_FAILURE(ec)){
+ errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n,i);
+ }
+ TimeZone* tz1 = TimeZone::createTimeZone(*id1);
+ for(int j=0; j<n;++j){
+ const UnicodeString* id2 = s2->snext(ec);
+ if(id2==NULL || U_FAILURE(ec)){
+ errln("Failed to fetch next from TimeZone enumeration. Length returned : %i Current Index: %i", n,i);
+ }
+ TimeZone* tz2 = TimeZone::createTimeZone(*id2);
+ if(tz1->hasSameRules(*tz2)){
+ logln("ID1 : " + *id1+" == ID2 : " +*id2);
+ }
+ delete tz2;
+ }
+ delete tz1;
+ }
+ delete s1;
+ delete s2;
+ delete s;
+}
+
+void TimeZoneTest::TestHistorical() {
+ const int32_t H = U_MILLIS_PER_HOUR;
+ struct {
+ const char* id;
+ int32_t time; // epoch seconds
+ int32_t offset; // total offset (millis)
+ } DATA[] = {
+ // Add transition points (before/after) as desired to test historical
+ // behavior.
+ {"America/Los_Angeles", 638963999, -8*H}, // Sun Apr 01 01:59:59 GMT-08:00 1990
+ {"America/Los_Angeles", 638964000, -7*H}, // Sun Apr 01 03:00:00 GMT-07:00 1990
+ {"America/Los_Angeles", 657104399, -7*H}, // Sun Oct 28 01:59:59 GMT-07:00 1990
+ {"America/Los_Angeles", 657104400, -8*H}, // Sun Oct 28 01:00:00 GMT-08:00 1990
+ {"America/Goose_Bay", -116445601, -4*H}, // Sun Apr 24 01:59:59 GMT-04:00 1966
+ {"America/Goose_Bay", -116445600, -3*H}, // Sun Apr 24 03:00:00 GMT-03:00 1966
+ {"America/Goose_Bay", -100119601, -3*H}, // Sun Oct 30 01:59:59 GMT-03:00 1966
+ {"America/Goose_Bay", -100119600, -4*H}, // Sun Oct 30 01:00:00 GMT-04:00 1966
+ {"America/Goose_Bay", -84391201, -4*H}, // Sun Apr 30 01:59:59 GMT-04:00 1967
+ {"America/Goose_Bay", -84391200, -3*H}, // Sun Apr 30 03:00:00 GMT-03:00 1967
+ {"America/Goose_Bay", -68670001, -3*H}, // Sun Oct 29 01:59:59 GMT-03:00 1967
+ {"America/Goose_Bay", -68670000, -4*H}, // Sun Oct 29 01:00:00 GMT-04:00 1967
+ {0, 0, 0}
+ };
+
+ for (int32_t i=0; DATA[i].id!=0; ++i) {
+ const char* id = DATA[i].id;
+ TimeZone *tz = TimeZone::createTimeZone(id);
+ UnicodeString s;
+ if (tz == 0) {
+ errln("FAIL: Cannot create %s", id);
+ } else if (tz->getID(s) != UnicodeString(id)) {
+ errln((UnicodeString)"FAIL: createTimeZone(" + id + ") => " + s);
+ } else {
+ UErrorCode ec = U_ZERO_ERROR;
+ int32_t raw, dst;
+ UDate when = (double) DATA[i].time * U_MILLIS_PER_SECOND;
+ tz->getOffset(when, FALSE, raw, dst, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: getOffset");
+ } else if ((raw+dst) != DATA[i].offset) {
+ errln((UnicodeString)"FAIL: " + DATA[i].id + ".getOffset(" +
+ //when + " = " +
+ dateToString(when) + ") => " +
+ raw + ", " + dst);
+ } else {
+ logln((UnicodeString)"Ok: " + DATA[i].id + ".getOffset(" +
+ //when + " = " +
+ dateToString(when) + ") => " +
+ raw + ", " + dst);
+ }
+ }
+ delete tz;
+ }
+}
+
+void TimeZoneTest::TestEquivalentIDs() {
+ int32_t n = TimeZone::countEquivalentIDs("PST");
+ if (n < 2) {
+ errln((UnicodeString)"FAIL: countEquivalentIDs(PST) = " + n);
+ } else {
+ UBool sawLA = FALSE;
+ for (int32_t i=0; i<n; ++i) {
+ UnicodeString id = TimeZone::getEquivalentID("PST", i);
+ logln((UnicodeString)"" + i + " : " + id);
+ if (id == UnicodeString("America/Los_Angeles")) {
+ sawLA = TRUE;
+ }
+ }
+ if (!sawLA) {
+ errln("FAIL: America/Los_Angeles should be in the list");
+ }
+ }
+}
+
+// Test that a transition at the end of February is handled correctly.
+void TimeZoneTest::TestFebruary() {
+ UErrorCode status = U_ZERO_ERROR;
+
+ // Time zone with daylight savings time from the first Sunday in November
+ // to the last Sunday in February.
+ // Similar to the new rule for Brazil (Sao Paulo) in tzdata2006n.
+ //
+ // Note: In tzdata2007h, the rule had changed, so no actual zones uses
+ // lastSun in Feb anymore.
+ SimpleTimeZone tz1(-3 * U_MILLIS_PER_HOUR, // raw offset: 3h before (west of) GMT
+ UNICODE_STRING("nov-feb", 7),
+ UCAL_NOVEMBER, 1, UCAL_SUNDAY, // start: November, first, Sunday
+ 0, // midnight wall time
+ UCAL_FEBRUARY, -1, UCAL_SUNDAY, // end: February, last, Sunday
+ 0, // midnight wall time
+ status);
+ if (U_FAILURE(status)) {
+ errln("Unable to create the SimpleTimeZone(nov-feb): %s", u_errorName(status));
+ return;
+ }
+
+ // Now hardcode the same rules as for Brazil in tzdata 2006n, so that
+ // we cover the intended code even when in the future zoneinfo hardcodes
+ // these transition dates.
+ SimpleTimeZone tz2(-3 * U_MILLIS_PER_HOUR, // raw offset: 3h before (west of) GMT
+ UNICODE_STRING("nov-feb2", 8),
+ UCAL_NOVEMBER, 1, -UCAL_SUNDAY, // start: November, 1 or after, Sunday
+ 0, // midnight wall time
+ UCAL_FEBRUARY, -29, -UCAL_SUNDAY,// end: February, 29 or before, Sunday
+ 0, // midnight wall time
+ status);
+ if (U_FAILURE(status)) {
+ errln("Unable to create the SimpleTimeZone(nov-feb2): %s", u_errorName(status));
+ return;
+ }
+
+ // Gregorian calendar with the UTC time zone for getting sample test date/times.
+ GregorianCalendar gc(*TimeZone::getGMT(), status);
+ if (U_FAILURE(status)) {
+ errln("Unable to create the UTC calendar: %s", u_errorName(status));
+ return;
+ }
+
+ struct {
+ // UTC time.
+ int32_t year, month, day, hour, minute, second;
+ // Expected time zone offset in hours after GMT (negative=before GMT).
+ int32_t offsetHours;
+ } data[] = {
+ { 2006, UCAL_NOVEMBER, 5, 02, 59, 59, -3 },
+ { 2006, UCAL_NOVEMBER, 5, 03, 00, 00, -2 },
+ { 2007, UCAL_FEBRUARY, 25, 01, 59, 59, -2 },
+ { 2007, UCAL_FEBRUARY, 25, 02, 00, 00, -3 },
+
+ { 2007, UCAL_NOVEMBER, 4, 02, 59, 59, -3 },
+ { 2007, UCAL_NOVEMBER, 4, 03, 00, 00, -2 },
+ { 2008, UCAL_FEBRUARY, 24, 01, 59, 59, -2 },
+ { 2008, UCAL_FEBRUARY, 24, 02, 00, 00, -3 },
+
+ { 2008, UCAL_NOVEMBER, 2, 02, 59, 59, -3 },
+ { 2008, UCAL_NOVEMBER, 2, 03, 00, 00, -2 },
+ { 2009, UCAL_FEBRUARY, 22, 01, 59, 59, -2 },
+ { 2009, UCAL_FEBRUARY, 22, 02, 00, 00, -3 },
+
+ { 2009, UCAL_NOVEMBER, 1, 02, 59, 59, -3 },
+ { 2009, UCAL_NOVEMBER, 1, 03, 00, 00, -2 },
+ { 2010, UCAL_FEBRUARY, 28, 01, 59, 59, -2 },
+ { 2010, UCAL_FEBRUARY, 28, 02, 00, 00, -3 }
+ };
+
+ TimeZone *timezones[] = { &tz1, &tz2 };
+
+ TimeZone *tz;
+ UDate dt;
+ int32_t t, i, raw, dst;
+ for (t = 0; t < LENGTHOF(timezones); ++t) {
+ tz = timezones[t];
+ for (i = 0; i < LENGTHOF(data); ++i) {
+ gc.set(data[i].year, data[i].month, data[i].day,
+ data[i].hour, data[i].minute, data[i].second);
+ dt = gc.getTime(status);
+ if (U_FAILURE(status)) {
+ errln("test case %d.%d: bad date/time %04d-%02d-%02d %02d:%02d:%02d",
+ t, i,
+ data[i].year, data[i].month + 1, data[i].day,
+ data[i].hour, data[i].minute, data[i].second);
+ status = U_ZERO_ERROR;
+ continue;
+ }
+ tz->getOffset(dt, FALSE, raw, dst, status);
+ if (U_FAILURE(status)) {
+ errln("test case %d.%d: tz.getOffset(%04d-%02d-%02d %02d:%02d:%02d) fails: %s",
+ t, i,
+ data[i].year, data[i].month + 1, data[i].day,
+ data[i].hour, data[i].minute, data[i].second,
+ u_errorName(status));
+ status = U_ZERO_ERROR;
+ } else if ((raw + dst) != data[i].offsetHours * U_MILLIS_PER_HOUR) {
+ errln("test case %d.%d: tz.getOffset(%04d-%02d-%02d %02d:%02d:%02d) returns %d+%d != %d",
+ t, i,
+ data[i].year, data[i].month + 1, data[i].day,
+ data[i].hour, data[i].minute, data[i].second,
+ raw, dst, data[i].offsetHours * U_MILLIS_PER_HOUR);
+ }
+ }
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/tztest.h b/Build/source/libs/icu/icu-xetex/test/intltest/tztest.h
new file mode 100644
index 00000000000..931509c199e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/tztest.h
@@ -0,0 +1,101 @@
+
+/********************************************************************
+ * Copyright (c) 1997-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef __TimeZoneTest__
+#define __TimeZoneTest__
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/simpletz.h"
+#include "caltztst.h"
+
+/**
+ * Various tests for TimeZone
+ **/
+class TimeZoneTest: public CalendarTimeZoneTest {
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+public: // package
+ static const int32_t millisPerHour;
+
+public:
+ /**
+ * Test the offset of the PRT timezone.
+ */
+ virtual void TestPRTOffset(void);
+ /**
+ * Regress a specific bug with a sequence of API calls.
+ */
+ virtual void TestVariousAPI518(void);
+ /**
+ * Test the call which retrieves the available IDs.
+ */
+ virtual void TestGetAvailableIDs913(void);
+
+ /**
+ * Generic API testing for API coverage.
+ */
+ virtual void TestGenericAPI(void);
+ /**
+ * Test the setStartRule/setEndRule API calls.
+ */
+ virtual void TestRuleAPI(void);
+
+ void findTransition(const TimeZone& tz,
+ UDate min, UDate max);
+
+ /**
+ * subtest used by TestRuleAPI
+ **/
+ void testUsingBinarySearch(const TimeZone& tz,
+ UDate min, UDate max,
+ UDate expectedBoundary);
+
+
+ /**
+ * Test short zone IDs for compliance
+ */
+ virtual void TestShortZoneIDs(void);
+
+
+ /**
+ * Test parsing custom zones
+ */
+ virtual void TestCustomParse(void);
+
+ /**
+ * Test new getDisplayName() API
+ */
+ virtual void TestDisplayName(void);
+
+ void TestDSTSavings(void);
+ void TestAlternateRules(void);
+
+ void TestCountries(void);
+
+ void TestHistorical(void);
+
+ void TestEquivalentIDs(void);
+
+ void TestAliasedNames(void);
+
+ void TestFractionalDST(void);
+
+ void TestFebruary(void);
+
+ static const UDate INTERVAL;
+
+private:
+ // internal functions
+ static UnicodeString& formatOffset(int32_t offset, UnicodeString& rv);
+ static UnicodeString& formatTZID(int32_t offset, UnicodeString& rv);
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // __TimeZoneTest__
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ucaconf.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/ucaconf.cpp
new file mode 100644
index 00000000000..ccd308a5712
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ucaconf.cpp
@@ -0,0 +1,265 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * UCAConformanceTest performs conformance tests defined in the data
+ * files. ICU ships with stub data files, as the whole test are too
+ * long. To do the whole test, download the test files.
+ */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "ucaconf.h"
+#include "unicode/ustring.h"
+#include "cstring.h"
+#include "uparse.h"
+
+UCAConformanceTest::UCAConformanceTest() :
+rbUCA(NULL),
+testFile(NULL),
+status(U_ZERO_ERROR)
+{
+ UCA = ucol_open("root", &status);
+ if(U_FAILURE(status)) {
+ errln("ERROR - UCAConformanceTest: Unable to open UCA collator!");
+ }
+
+ const char *srcDir = IntlTest::getSourceTestData(status);
+ if (U_FAILURE(status)) {
+ errln("ERROR: could not open test data %s", u_errorName(status));
+ return;
+ }
+ uprv_strcpy(testDataPath, srcDir);
+ uprv_strcat(testDataPath, "CollationTest_");
+}
+
+UCAConformanceTest::~UCAConformanceTest()
+{
+ ucol_close(UCA);
+ if(rbUCA) {
+ ucol_close(rbUCA);
+ }
+ if(testFile) {
+ fclose(testFile);
+ }
+}
+
+void UCAConformanceTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par */)
+{
+ if (exec) logln("TestSuite UCAConformanceTest: ");
+ if(U_SUCCESS(status)) {
+ switch (index) {
+ case 0: name = "TestTableNonIgnorable"; if (exec) TestTableNonIgnorable(/* par */); break;
+ case 1: name = "TestTableShifted"; if (exec) TestTableShifted(/* par */); break;
+ case 2: name = "TestRulesNonIgnorable"; if (exec) TestRulesNonIgnorable(/* par */); break;
+ case 3: name = "TestRulesShifted"; if (exec) TestRulesShifted(/* par */); break;
+ default: name = ""; break;
+ }
+ } else {
+ name = "";
+ }
+}
+
+void UCAConformanceTest::initRbUCA()
+{
+ if(!rbUCA) {
+ UParseError parseError;
+ UChar *ucarules;
+ // preflight rules
+ int32_t size = ucol_getRulesEx(UCA, UCOL_FULL_RULES, NULL, 0);
+ ucarules = (UChar *)malloc(size * sizeof(UChar));
+
+ size = ucol_getRulesEx(UCA, UCOL_FULL_RULES, ucarules, size);
+ rbUCA = ucol_openRules(ucarules, size, UCOL_DEFAULT, UCOL_TERTIARY,
+ &parseError, &status);
+ free(ucarules);
+ if (U_FAILURE(status)) {
+ errln("Failure creating UCA rule-based collator: %s", u_errorName(status));
+ return;
+ }
+ }
+}
+
+void UCAConformanceTest::setCollNonIgnorable(UCollator *coll)
+{
+ ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
+ ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_OFF, &status);
+ ucol_setAttribute(coll, UCOL_CASE_LEVEL, UCOL_OFF, &status);
+ ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_TERTIARY, &status);
+ ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_NON_IGNORABLE, &status);
+}
+
+void UCAConformanceTest::setCollShifted(UCollator *coll)
+{
+ ucol_setAttribute(coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
+ ucol_setAttribute(coll, UCOL_CASE_FIRST, UCOL_OFF, &status);
+ ucol_setAttribute(coll, UCOL_CASE_LEVEL, UCOL_OFF, &status);
+ ucol_setAttribute(coll, UCOL_STRENGTH, UCOL_QUATERNARY, &status);
+ ucol_setAttribute(coll, UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, &status);
+}
+
+void UCAConformanceTest::openTestFile(const char *type)
+{
+ const char *ext = ".txt";
+ if(testFile) {
+ fclose(testFile);
+ }
+ char buffer[1024];
+ uprv_strcpy(buffer, testDataPath);
+ uprv_strcat(buffer, type);
+ int32_t bufLen = (int32_t)uprv_strlen(buffer);
+
+ // we try to open 3 files:
+ // path/CollationTest_type.txt
+ // path/CollationTest_type_SHORT.txt
+ // path/CollationTest_type_STUB.txt
+ // we are going to test with the first one that we manage to open.
+
+ uprv_strcpy(buffer+bufLen, ext);
+
+ testFile = fopen(buffer, "rb");
+
+ if(testFile == 0) {
+ uprv_strcpy(buffer+bufLen, "_SHORT");
+ uprv_strcat(buffer, ext);
+ testFile = fopen(buffer, "rb");
+
+ if(testFile == 0) {
+ uprv_strcpy(buffer+bufLen, "_STUB");
+ uprv_strcat(buffer, ext);
+ testFile = fopen(buffer, "rb");
+
+ if (testFile == 0) {
+ *(buffer+bufLen) = 0;
+ errln("ERROR: could not open any of the conformance test files, tried opening base %s\n", buffer);
+ return;
+ } else {
+ infoln(
+ "INFO: Working with the stub file.\n"
+ "If you need the full conformance test, please\n"
+ "download the appropriate data files from:\n"
+ "http://source.icu-project.org/repos/icu/tools/trunk/unicodetools/com/ibm/text/data/");
+ }
+ }
+ }
+}
+
+void UCAConformanceTest::testConformance(UCollator *coll)
+{
+ if(testFile == 0) {
+ return;
+ }
+
+ int32_t line = 0;
+
+ UChar b1[1024], b2[1024];
+ char lineB[1024];
+ UChar *buffer = b1, *oldB = NULL;
+ uint8_t sk1[1024], sk2[1024];
+ uint8_t *oldSk = NULL, *newSk = sk1;
+ int32_t resLen = 0, oldLen = 0;
+ int32_t buflen = 0, oldBlen = 0;
+ uint32_t first = 0;
+ uint32_t offset = 0;
+ UnicodeString oldS, newS;
+
+
+ while (fgets(lineB, 1024, testFile) != NULL) {
+ offset = 0;
+
+ line++;
+ if(*lineB == 0 || strlen(lineB) < 3 || lineB[0] == '#') {
+ continue;
+ }
+ offset = u_parseString(lineB, buffer, 1024, &first, &status);
+ buflen = offset;
+ buffer[offset++] = 0;
+
+ resLen = ucol_getSortKey(coll, buffer, buflen, newSk, 1024);
+
+ int32_t res = 0, cmpres = 0, cmpres2 = 0;
+
+ if(oldSk != NULL) {
+ res = strcmp((char *)oldSk, (char *)newSk);
+ cmpres = ucol_strcoll(coll, oldB, oldBlen, buffer, buflen);
+ cmpres2 = ucol_strcoll(coll, buffer, buflen, oldB, oldBlen);
+
+ if(cmpres != -cmpres2) {
+ errln("Compare result not symmetrical on line %i", line);
+ }
+
+ if(((res&0x80000000) != (cmpres&0x80000000)) || (res == 0 && cmpres != 0) || (res != 0 && cmpres == 0)) {
+ errln("Difference between ucol_strcoll and sortkey compare on line %i", line);
+ logln("Data line %s", lineB);
+ }
+
+ if(res > 0) {
+ errln("Line %i is not greater or equal than previous line", line);
+ logln("Data line %s", lineB);
+ prettify(CollationKey(oldSk, oldLen), oldS);
+ prettify(CollationKey(newSk, resLen), newS);
+ logln("Keys: "+oldS+" and "+newS);
+ } else if(res == 0) { /* equal */
+ res = u_strcmpCodePointOrder(oldB, buffer);
+ if (res == 0) {
+ errln("Probable error in test file on line %i (comparing identical strings)", line);
+ logln("Data line %s", lineB);
+ } else if (res > 0) {
+ errln("Sortkeys are identical, but code point comapare gives >0 on line %i", line);
+ logln("Data line %s", lineB);
+ }
+ }
+ }
+
+ oldSk = newSk;
+ oldLen = resLen;
+
+ newSk = (newSk == sk1)?sk2:sk1;
+ oldB = buffer;
+ oldBlen = buflen;
+ buffer = (buffer == b1)?b2:b1;
+ }
+}
+
+void UCAConformanceTest::TestTableNonIgnorable(/* par */) {
+ setCollNonIgnorable(UCA);
+ openTestFile("NON_IGNORABLE");
+ testConformance(UCA);
+}
+
+void UCAConformanceTest::TestTableShifted(/* par */) {
+ setCollShifted(UCA);
+ openTestFile("SHIFTED");
+ testConformance(UCA);
+}
+
+void UCAConformanceTest::TestRulesNonIgnorable(/* par */) {
+ initRbUCA();
+
+ if(U_SUCCESS(status)) {
+ setCollNonIgnorable(rbUCA);
+ openTestFile("NON_IGNORABLE");
+ testConformance(rbUCA);
+ }
+}
+
+void UCAConformanceTest::TestRulesShifted(/* par */) {
+ logln("This test is currently disabled, as it is impossible to "
+ "wholly represent fractional UCA using tailoring rules.");
+ return;
+
+ initRbUCA();
+
+ if(U_SUCCESS(status)) {
+ setCollShifted(rbUCA);
+ openTestFile("SHIFTED");
+ testConformance(rbUCA);
+ }
+}
+
+#endif /* #if !UCONFIG_NO_COLLATION */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ucaconf.h b/Build/source/libs/icu/icu-xetex/test/intltest/ucaconf.h
new file mode 100644
index 00000000000..7e3368cb6c6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ucaconf.h
@@ -0,0 +1,52 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+/**
+ * UCAConformanceTest performs conformance tests defined in the data
+ * files. ICU ships with stub data files, as the whole test are too
+ * long. To do the whole test, download the test files.
+ */
+
+#ifndef _UCACONF_TST
+#define _UCACONF_TST
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_COLLATION
+
+#include "unicode/tblcoll.h"
+#include "tscoll.h"
+
+#include <stdio.h>
+
+class UCAConformanceTest: public IntlTestCollator {
+public:
+ UCAConformanceTest();
+ virtual ~UCAConformanceTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par = NULL */);
+
+ void TestTableNonIgnorable(/* par */);
+ void TestTableShifted(/* par */);
+ void TestRulesNonIgnorable(/* par */);
+ void TestRulesShifted(/* par */);
+private:
+ void initRbUCA();
+ void setCollNonIgnorable(UCollator *coll);
+ void setCollShifted(UCollator *coll);
+ void testConformance(UCollator *coll);
+ void openTestFile(const char *type);
+
+ UCollator *UCA;
+ UCollator *rbUCA;
+ FILE *testFile;
+ UErrorCode status;
+ char testDataPath[1024];
+};
+
+#endif /* #if !UCONFIG_NO_COLLATION */
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ucdtest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/ucdtest.cpp
new file mode 100644
index 00000000000..e7195c25292
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ucdtest.cpp
@@ -0,0 +1,217 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/ustring.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/putil.h"
+#include "cstring.h"
+#include "uparse.h"
+#include "ucdtest.h"
+
+#define LENGTHOF(array) (sizeof(array)/sizeof(array[0]))
+
+UnicodeTest::UnicodeTest()
+{
+}
+
+UnicodeTest::~UnicodeTest()
+{
+}
+
+void UnicodeTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite UnicodeTest: ");
+ switch (index) {
+ case 0: name = "TestAdditionalProperties"; if(exec) TestAdditionalProperties(); break;
+ default: name = ""; break; //needed to end loop
+ }
+}
+
+//====================================================
+// private data used by the tests
+//====================================================
+
+// test DerivedCoreProperties.txt -------------------------------------------
+
+// copied from genprops.c
+static int32_t
+getTokenIndex(const char *const tokens[], int32_t countTokens, const char *s) {
+ const char *t, *z;
+ int32_t i, j;
+
+ s=u_skipWhitespace(s);
+ for(i=0; i<countTokens; ++i) {
+ t=tokens[i];
+ if(t!=NULL) {
+ for(j=0;; ++j) {
+ if(t[j]!=0) {
+ if(s[j]!=t[j]) {
+ break;
+ }
+ } else {
+ z=u_skipWhitespace(s+j);
+ if(*z==';' || *z==0) {
+ return i;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+static const char *const
+derivedCorePropsNames[]={
+ "Math",
+ "Alphabetic",
+ "Lowercase",
+ "Uppercase",
+ "ID_Start",
+ "ID_Continue",
+ "XID_Start",
+ "XID_Continue",
+ "Default_Ignorable_Code_Point",
+ "Grapheme_Extend",
+ "Grapheme_Link", /* Unicode 5 moves this property here from PropList.txt */
+ "Grapheme_Base"
+};
+
+static const UProperty
+derivedCorePropsIndex[]={
+ UCHAR_MATH,
+ UCHAR_ALPHABETIC,
+ UCHAR_LOWERCASE,
+ UCHAR_UPPERCASE,
+ UCHAR_ID_START,
+ UCHAR_ID_CONTINUE,
+ UCHAR_XID_START,
+ UCHAR_XID_CONTINUE,
+ UCHAR_DEFAULT_IGNORABLE_CODE_POINT,
+ UCHAR_GRAPHEME_EXTEND,
+ UCHAR_GRAPHEME_LINK,
+ UCHAR_GRAPHEME_BASE
+};
+
+U_CFUNC void U_CALLCONV
+derivedCorePropsLineFn(void *context,
+ char *fields[][2], int32_t /* fieldCount */,
+ UErrorCode *pErrorCode)
+{
+ UnicodeTest *me=(UnicodeTest *)context;
+ uint32_t start, end;
+ int32_t i;
+
+ u_parseCodePointRange(fields[0][0], &start, &end, pErrorCode);
+ if(U_FAILURE(*pErrorCode)) {
+ me->errln("UnicodeTest: syntax error in DerivedCoreProperties.txt field 0 at %s\n", fields[0][0]);
+ return;
+ }
+
+ /* parse derived binary property name, ignore unknown names */
+ i=getTokenIndex(derivedCorePropsNames, LENGTHOF(derivedCorePropsNames), fields[1][0]);
+ if(i<0) {
+ me->errln("UnicodeTest warning: unknown property name '%s' in \n", fields[1][0]);
+ return;
+ }
+
+ me->derivedCoreProps[i].add(start, end);
+}
+
+void UnicodeTest::TestAdditionalProperties() {
+ // test DerivedCoreProperties.txt
+ if(LENGTHOF(derivedCoreProps)<LENGTHOF(derivedCorePropsNames)) {
+ errln("error: UnicodeTest::derivedCoreProps[] too short, need at least %d UnicodeSets\n",
+ LENGTHOF(derivedCorePropsNames));
+ return;
+ }
+ if(LENGTHOF(derivedCorePropsIndex)!=LENGTHOF(derivedCorePropsNames)) {
+ errln("error in ucdtest.cpp: LENGTHOF(derivedCorePropsIndex)!=LENGTHOF(derivedCorePropsNames)\n");
+ return;
+ }
+
+ char newPath[256];
+ char backupPath[256];
+ char *fields[2][2];
+ UErrorCode errorCode=U_ZERO_ERROR;
+
+ /* Look inside ICU_DATA first */
+ strcpy(newPath, pathToDataDirectory());
+ strcat(newPath, "unidata" U_FILE_SEP_STRING "DerivedCoreProperties.txt");
+
+ // As a fallback, try to guess where the source data was located
+ // at the time ICU was built, and look there.
+# ifdef U_TOPSRCDIR
+ strcpy(backupPath, U_TOPSRCDIR U_FILE_SEP_STRING "data");
+# else
+ strcpy(backupPath, loadTestData(errorCode));
+ strcat(backupPath, U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING ".." U_FILE_SEP_STRING "data");
+# endif
+ strcat(backupPath, U_FILE_SEP_STRING);
+ strcat(backupPath, "unidata" U_FILE_SEP_STRING "DerivedCoreProperties.txt");
+
+ u_parseDelimitedFile(newPath, ';', fields, 2, derivedCorePropsLineFn, this, &errorCode);
+
+ if(errorCode==U_FILE_ACCESS_ERROR) {
+ errorCode=U_ZERO_ERROR;
+ u_parseDelimitedFile(backupPath, ';', fields, 2, derivedCorePropsLineFn, this, &errorCode);
+ }
+ if(U_FAILURE(errorCode)) {
+ errln("error parsing DerivedCoreProperties.txt: %s\n", u_errorName(errorCode));
+ return;
+ }
+
+ // now we have all derived core properties in the UnicodeSets
+ // run them all through the API
+ int32_t rangeCount, range;
+ uint32_t i;
+ UChar32 start, end;
+ int32_t noErrors = 0;
+
+ // test all TRUE properties
+ for(i=0; i<LENGTHOF(derivedCorePropsNames); ++i) {
+ rangeCount=derivedCoreProps[i].getRangeCount();
+ for(range=0; range<rangeCount; ++range) {
+ start=derivedCoreProps[i].getRangeStart(range);
+ end=derivedCoreProps[i].getRangeEnd(range);
+ for(; start<=end; ++start) {
+ if(!u_hasBinaryProperty(start, derivedCorePropsIndex[i])) {
+ errln("UnicodeTest error: u_hasBinaryProperty(U+%04lx, %s)==FALSE is wrong\n", start, derivedCorePropsNames[i]);
+ if(noErrors++ > 100) {
+ errln("Too many errors, moving to the next test");
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ noErrors = 0;
+ // invert all properties
+ for(i=0; i<LENGTHOF(derivedCorePropsNames); ++i) {
+ derivedCoreProps[i].complement();
+ }
+
+ // test all FALSE properties
+ for(i=0; i<LENGTHOF(derivedCorePropsNames); ++i) {
+ rangeCount=derivedCoreProps[i].getRangeCount();
+ for(range=0; range<rangeCount; ++range) {
+ start=derivedCoreProps[i].getRangeStart(range);
+ end=derivedCoreProps[i].getRangeEnd(range);
+ for(; start<=end; ++start) {
+ if(u_hasBinaryProperty(start, derivedCorePropsIndex[i])) {
+ errln("UnicodeTest error: u_hasBinaryProperty(U+%04lx, %s)==TRUE is wrong\n", start, derivedCorePropsNames[i]);
+ if(noErrors++ > 100) {
+ errln("Too many errors, moving to the next test");
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ucdtest.h b/Build/source/libs/icu/icu-xetex/test/intltest/ucdtest.h
new file mode 100644
index 00000000000..6695a878755
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ucdtest.h
@@ -0,0 +1,45 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2004, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "unicode/uniset.h"
+#include "intltest.h"
+
+/** Helper function for TestUnicodeData */
+U_CFUNC void U_CALLCONV unicodeDataLineFn(void *context,
+ char *fields[][2], int32_t fieldCount,
+ UErrorCode *pErrorCode);
+
+U_CFUNC void U_CALLCONV
+derivedCorePropsLineFn(void *context,
+ char *fields[][2], int32_t fieldCount,
+ UErrorCode *pErrorCode);
+
+/**
+ * Test API and functionality of class Unicode
+ **/
+class UnicodeTest: public IntlTest {
+public:
+ UnicodeTest();
+ virtual ~UnicodeTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ void TestAdditionalProperties();
+
+private:
+
+ friend void U_CALLCONV unicodeDataLineFn(void *context,
+ char *fields[][2], int32_t fieldCount,
+ UErrorCode *pErrorCode);
+
+ friend void U_CALLCONV
+ derivedCorePropsLineFn(void *context,
+ char *fields[][2], int32_t fieldCount,
+ UErrorCode *pErrorCode);
+
+ UnicodeSet derivedCoreProps[30];
+};
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/uobjtest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/uobjtest.cpp
new file mode 100644
index 00000000000..4d4b0f8a978
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/uobjtest.cpp
@@ -0,0 +1,466 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "uobjtest.h"
+#include "cmemory.h" // UAlignedMemory
+#include <string.h>
+#include <stdio.h>
+
+/**
+ *
+ * Test for UObject, currently only the classID.
+ *
+ * Usage
+ * TESTCLASSID_ABSTRACT(Bar)
+ * -- Bar is expected to be abstract. Only the static ID will be tested.
+ *
+ * TESTCLASSID_DEFAULT(Foo)
+ * -- Foo will be default-constructed.
+ *
+ * TESTCLASSID_CTOR(Foo, (1, 2, 3, status))
+ * -- Second argument is (parenthesized) constructor argument.
+ * Will be called as: new Foo ( 1, 2, 3, status) [status is tested]
+ *
+ * TESTCLASSID_FACTORY(Foo, fooCreateFunction(status) )
+ * -- call fooCreateFunction. 'status' will be tested & reset
+ *
+ * TESTCLASSID_FACTORY_HIDDEN(class, factory)
+ * -- call factory. Class is not available from a header.
+ * 'status' will be tested & reset. This only tests uniqueness.
+ */
+
+
+#define TESTCLASSID_FACTORY(c, f) { delete testClass(f, #c, #f, c ::getStaticClassID()); if(U_FAILURE(status)) { errln(UnicodeString(#c " - " #f " - got err status ") + UnicodeString(u_errorName(status))); status = U_ZERO_ERROR; } }
+#define TESTCLASSID_TRANSLIT(c, t) { delete testClass(Transliterator::createInstance(UnicodeString(t), UTRANS_FORWARD,parseError,status), #c, "Transliterator: " #t, c ::getStaticClassID()); if(U_FAILURE(status)) { errln(UnicodeString(#c " - Transliterator: " #t " - got err status ") + UnicodeString(u_errorName(status))); status = U_ZERO_ERROR; } }
+#define TESTCLASSID_CTOR(c, x) { delete testClass(new c x, #c, "new " #c #x, c ::getStaticClassID()); if(U_FAILURE(status)) { errln(UnicodeString(#c " - new " #x " - got err status ") + UnicodeString(u_errorName(status))); status = U_ZERO_ERROR; } }
+#define TESTCLASSID_DEFAULT(c) delete testClass(new c, #c, "new " #c , c::getStaticClassID())
+#define TESTCLASSID_ABSTRACT(c) testClass(NULL, #c, NULL, c::getStaticClassID())
+#define TESTCLASSID_FACTORY_HIDDEN(c, f) {UObject *objVar = f; delete testClass(objVar, #c, #f, objVar->getDynamicClassID()); if(U_FAILURE(status)) { errln(UnicodeString(#c " - " #f " - got err status ") + UnicodeString(u_errorName(status))); status = U_ZERO_ERROR; } }
+
+#define MAX_CLASS_ID 200
+
+static UClassID ids[MAX_CLASS_ID];
+static const char *ids_factory[MAX_CLASS_ID];
+static const char *ids_class[MAX_CLASS_ID];
+static uint32_t ids_count = 0;
+
+UObject *UObjectTest::testClass(UObject *obj,
+ const char *className, const char *factory,
+ UClassID staticID)
+{
+ uint32_t i;
+ UnicodeString what = UnicodeString(className) + " * x= " + UnicodeString(factory?factory:" ABSTRACT ") + "; ";
+ UClassID dynamicID = NULL;
+
+ if(ids_count >= MAX_CLASS_ID) {
+ char count[100];
+ sprintf(count, " (currently %d) ", MAX_CLASS_ID);
+ errln("FAIL: Fatal: Ran out of IDs! Increase MAX_CLASS_ID." + UnicodeString(count) + what);
+ return obj;
+ }
+
+ if(obj) {
+ dynamicID = obj->getDynamicClassID();
+ }
+
+ {
+ char tmp[500];
+ sprintf(tmp, " [static=%p, dynamic=%p] ", staticID, dynamicID);
+ logln(what + tmp);
+ }
+
+ if(staticID == NULL) {
+ errln("FAIL: staticID == NULL!" + what);
+ }
+
+ if(factory != NULL) { /* NULL factory means: abstract */
+ if(!obj) {
+ errln( "FAIL: ==NULL!" + what);
+ return obj;
+ }
+
+ if(dynamicID == NULL) {
+ errln("FAIL: dynamicID == NULL!" + what);
+ }
+
+ if(dynamicID != staticID) {
+ errln("FAIL: dynamicID != staticID!" + what );
+ }
+ }
+
+ // Bail out if static ID is null. Error message was already printed.
+ if(staticID == NULL) {
+ return obj;
+ }
+
+ for(i=0;i<ids_count;i++) {
+ if(staticID == ids[i]) {
+ if(!strcmp(ids_class[i], className)) {
+ logln("OK: ID found is the same as " + UnicodeString(ids_class[i]) + UnicodeString(" *y= ") + ids_factory[i] + what);
+ return obj;
+ } else {
+ errln("FAIL: ID is the same as " + UnicodeString(ids_class[i]) + UnicodeString(" *y= ") + ids_factory[i] + what);
+ return obj;
+ }
+ }
+ }
+
+ ids[ids_count] = staticID;
+ ids_factory[ids_count] = factory;
+ ids_class[ids_count] = className;
+ ids_count++;
+
+ return obj;
+}
+
+
+// begin actual #includes for things to be tested
+//
+// The following script will generate the #includes needed here:
+//
+// find common i18n -name '*.h' -print | xargs fgrep ClassID | cut -d: -f1 | cut -d\/ -f2- | sort | uniq | sed -e 's%.*%#include "&"%'
+
+
+#include "unicode/utypes.h"
+
+// Internal Things (woo)
+#include "cpdtrans.h"
+#include "rbt.h"
+#include "rbt_data.h"
+#include "nultrans.h"
+#include "anytrans.h"
+#include "digitlst.h"
+#include "esctrn.h"
+#include "funcrepl.h"
+#include "servnotf.h"
+#include "serv.h"
+#include "servloc.h"
+#include "name2uni.h"
+#include "nfsubs.h"
+#include "nortrans.h"
+#include "quant.h"
+#include "remtrans.h"
+#include "strmatch.h"
+#include "strrepl.h"
+#include "titletrn.h"
+#include "tolowtrn.h"
+#include "toupptrn.h"
+#include "unesctrn.h"
+#include "uni2name.h"
+#include "uvector.h"
+#include "uvectr32.h"
+#include "currfmt.h"
+#include "buddhcal.h"
+#include "islamcal.h"
+#include "japancal.h"
+#include "hebrwcal.h"
+#include "persncal.h"
+#include "windtfmt.h"
+#include "winnmfmt.h"
+#include "ustrenum.h"
+#include "olsontz.h"
+#include "reldtfmt.h"
+
+// External Things
+#include "unicode/brkiter.h"
+#include "unicode/calendar.h"
+#include "unicode/caniter.h"
+#include "unicode/chariter.h"
+#include "unicode/choicfmt.h"
+#include "unicode/coleitr.h"
+#include "unicode/coll.h"
+#include "unicode/curramt.h"
+#include "unicode/datefmt.h"
+#include "unicode/dcfmtsym.h"
+#include "unicode/decimfmt.h"
+#include "unicode/dtfmtsym.h"
+#include "unicode/fieldpos.h"
+#include "unicode/fmtable.h"
+#include "unicode/format.h"
+#include "unicode/gregocal.h"
+#include "unicode/locid.h"
+#include "unicode/msgfmt.h"
+#include "unicode/normlzr.h"
+#include "unicode/numfmt.h"
+#include "unicode/parsepos.h"
+#include "unicode/rbbi.h"
+#include "unicode/rbnf.h"
+#include "unicode/regex.h"
+#include "unicode/resbund.h"
+#include "unicode/schriter.h"
+#include "unicode/simpletz.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/sortkey.h"
+#include "unicode/stsearch.h"
+#include "unicode/tblcoll.h"
+#include "unicode/timezone.h"
+#include "unicode/translit.h"
+#include "unicode/uchriter.h"
+#include "unicode/unifilt.h"
+#include "unicode/unifunct.h"
+#include "unicode/uniset.h"
+#include "unicode/unistr.h"
+#include "unicode/uobject.h"
+#include "unicode/usetiter.h"
+//#include "unicode/bidi.h"
+//#include "unicode/convert.h"
+
+// END includes =============================================================
+
+#define UOBJTEST_TEST_INTERNALS 0 /* do NOT test Internal things - their functions aren't exported on Win32 */
+
+#if !UCONFIG_NO_SERVICE
+/* The whole purpose of this class is to expose the constructor, and gain access to the superclasses RTTI. */
+class TestLocaleKeyFactory : public LocaleKeyFactory {
+public:
+ TestLocaleKeyFactory(int32_t coverage) : LocaleKeyFactory(coverage) {}
+};
+#endif
+
+void UObjectTest::testIDs()
+{
+ ids_count = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ static const UChar SMALL_STR[] = {0x51, 0x51, 0x51, 0}; // "QQQ"
+
+#if !UCONFIG_NO_TRANSLITERATION || !UCONFIG_NO_FORMATTING
+ UParseError parseError;
+#endif
+
+
+#if !UCONFIG_NO_NORMALIZATION
+ TESTCLASSID_FACTORY(CanonicalIterator, new CanonicalIterator(UnicodeString("abc"), status));
+#endif
+ //TESTCLASSID_DEFAULT(CollationElementIterator);
+#if !UCONFIG_NO_COLLATION
+ TESTCLASSID_DEFAULT(CollationKey);
+ TESTCLASSID_FACTORY(UStringEnumeration, Collator::getKeywords(status));
+ //TESTCLASSID_FACTORY_HIDDEN(CollationLocaleListEnumeration, Collator::getAvailableLocales());
+#endif
+ //TESTCLASSID_FACTORY(CompoundTransliterator, Transliterator::createInstance(UnicodeString("Any-Jex;Hangul-Jamo"), UTRANS_FORWARD, parseError, status));
+
+#if !UCONFIG_NO_FORMATTING
+ /* TESTCLASSID_FACTORY(NFSubstitution, NFSubstitution::makeSubstitution(8, */
+ /* TESTCLASSID_DEFAULT(DigitList); UMemory but not UObject*/
+ TESTCLASSID_ABSTRACT(NumberFormat);
+ TESTCLASSID_CTOR(RuleBasedNumberFormat, (UnicodeString("%default: -x: minus >>;"), parseError, status));
+ TESTCLASSID_CTOR(ChoiceFormat, (UNICODE_STRING_SIMPLE("0#are no files|1#is one file|1<are many files"), status));
+ TESTCLASSID_CTOR(MessageFormat, (UnicodeString(), status));
+ TESTCLASSID_CTOR(DateFormatSymbols, (status));
+ TESTCLASSID_FACTORY(RelativeDateFormat, DateFormat::createDateInstance(DateFormat::kFullRelative, Locale::getUS()));
+ TESTCLASSID_CTOR(DecimalFormatSymbols, (status));
+ TESTCLASSID_DEFAULT(FieldPosition);
+ TESTCLASSID_DEFAULT(Formattable);
+ TESTCLASSID_CTOR(CurrencyAmount, (1.0, SMALL_STR, status));
+ TESTCLASSID_CTOR(CurrencyUnit, (SMALL_STR, status));
+ TESTCLASSID_CTOR(CurrencyFormat, (Locale::getUS(), status));
+ TESTCLASSID_FACTORY(GregorianCalendar, Calendar::createInstance(Locale("@calendar=gregorian"), status));
+ TESTCLASSID_FACTORY(BuddhistCalendar, Calendar::createInstance(Locale("@calendar=buddhist"), status));
+ TESTCLASSID_FACTORY(IslamicCalendar, Calendar::createInstance(Locale("@calendar=islamic"), status));
+ TESTCLASSID_FACTORY(JapaneseCalendar, Calendar::createInstance(Locale("@calendar=japanese"), status));
+ TESTCLASSID_FACTORY(HebrewCalendar, Calendar::createInstance(Locale("@calendar=hebrew"), status));
+ TESTCLASSID_FACTORY(PersianCalendar, Calendar::createInstance(Locale("@calendar=persian"), status));
+#ifdef U_WINDOWS
+ TESTCLASSID_FACTORY(Win32DateFormat, DateFormat::createDateInstance(DateFormat::kFull, Locale("@compat=host")));
+ TESTCLASSID_FACTORY(Win32NumberFormat, NumberFormat::createInstance(Locale("@compat=host"), status));
+#endif
+#endif
+
+#if !UCONFIG_NO_BREAK_ITERATION
+ /* TESTCLASSID_ABSTRACT(BreakIterator); No staticID! */
+ TESTCLASSID_FACTORY(RuleBasedBreakIterator, BreakIterator::createLineInstance("mt",status));
+ //TESTCLASSID_FACTORY(DictionaryBasedBreakIterator, BreakIterator::createLineInstance("th",status));
+
+#if !UCONFIG_NO_SERVICE
+ TESTCLASSID_FACTORY_HIDDEN(ICULocaleService, BreakIterator::getAvailableLocales());
+#endif
+#endif
+
+ //TESTCLASSID_DEFAULT(GregorianCalendar);
+
+#if !UCONFIG_NO_TRANSLITERATION
+ TESTCLASSID_TRANSLIT(AnyTransliterator, "Any-Latin");
+ TESTCLASSID_TRANSLIT(CompoundTransliterator, "Latin-Greek");
+ TESTCLASSID_TRANSLIT(EscapeTransliterator, "Any-Hex");
+ TESTCLASSID_TRANSLIT(LowercaseTransliterator, "Lower");
+ TESTCLASSID_TRANSLIT(NameUnicodeTransliterator, "Name-Any");
+ TESTCLASSID_TRANSLIT(NormalizationTransliterator, "NFD");
+ TESTCLASSID_TRANSLIT(NullTransliterator, "Null");
+ TESTCLASSID_TRANSLIT(RemoveTransliterator, "Remove");
+ TESTCLASSID_FACTORY(RuleBasedTransliterator, Transliterator::createFromRules(UnicodeString("abcd"),UnicodeString("a>b;"),UTRANS_FORWARD,parseError,status));
+ TESTCLASSID_TRANSLIT(TitlecaseTransliterator, "Title");
+ TESTCLASSID_TRANSLIT(UnescapeTransliterator, "Hex-Any");
+ TESTCLASSID_TRANSLIT(UnicodeNameTransliterator, "Any-Name");
+ TESTCLASSID_TRANSLIT(UppercaseTransliterator, "Upper");
+ TESTCLASSID_CTOR(CaseMapTransliterator, (UnicodeString(), NULL));
+ TESTCLASSID_ABSTRACT(Transliterator);
+ TESTCLASSID_FACTORY_HIDDEN(TransliteratorRegistry::Enumeration, Transliterator::getAvailableIDs(status));
+
+#if UOBJTEST_TEST_INTERNALS
+ TESTCLASSID_CTOR(Quantifier, (NULL, 0, 0));
+ TESTCLASSID_CTOR(FunctionReplacer, (NULL,NULL));
+ TESTCLASSID_CTOR(StringMatcher, (UnicodeString("x"), 0,0,0,TransliterationRuleData(status)));
+ TESTCLASSID_CTOR(StringReplacer,(UnicodeString(),new TransliterationRuleData(status)));
+#endif
+#endif
+
+ TESTCLASSID_FACTORY(Locale, new Locale("123"));
+ TESTCLASSID_FACTORY_HIDDEN(KeywordEnumeration, Locale("@a=b").createKeywords(status));
+
+ //TESTCLASSID_DEFAULT(Normalizer);
+
+ //TESTCLASSID_DEFAULT(NumeratorSubstitution);
+
+#if !UCONFIG_NO_TRANSLITERATION
+ TESTCLASSID_DEFAULT(ParsePosition);
+#endif
+
+
+// NO_REG_EX
+ //TESTCLASSID_DEFAULT(RegexCompile);
+ //TESTCLASSID_DEFAULT(RegexMatcher);
+ //TESTCLASSID_DEFAULT(RegexPattern);
+
+ //TESTCLASSID_DEFAULT(ReplaceableGlue);
+ TESTCLASSID_FACTORY(ResourceBundle, new ResourceBundle(UnicodeString(), status) );
+ //TESTCLASSID_DEFAULT(RuleBasedTransliterator);
+
+ //TESTCLASSID_DEFAULT(SimpleFwdCharIterator);
+ //TESTCLASSID_DEFAULT(StringReplacer);
+ //TESTCLASSID_DEFAULT(StringSearch);
+
+ //TESTCLASSID_DEFAULT(TestMultipleKeyStringFactory);
+ //TESTCLASSID_DEFAULT(TestReplaceable);
+
+#if !UCONFIG_NO_FORMATTING
+ TESTCLASSID_ABSTRACT(TimeZone);
+ TESTCLASSID_FACTORY(OlsonTimeZone, TimeZone::createTimeZone(UnicodeString("America/Los_Angeles")));
+ TESTCLASSID_FACTORY_HIDDEN(KeywordEnumeration, TimeZone::createEnumeration());
+#endif
+
+ TESTCLASSID_DEFAULT(UnicodeString);
+ TESTCLASSID_CTOR(UnicodeSet, (0, 1));
+ TESTCLASSID_ABSTRACT(UnicodeFilter);
+ TESTCLASSID_ABSTRACT(UnicodeFunctor);
+ TESTCLASSID_CTOR(UnicodeSetIterator,(UnicodeSet(0,1)));
+ TESTCLASSID_CTOR(UStack, (status));
+ TESTCLASSID_CTOR(UVector, (status));
+ TESTCLASSID_CTOR(UVector32, (status));
+
+#if !UCONFIG_NO_SERVICE
+ TESTCLASSID_CTOR(SimpleFactory, (NULL, UnicodeString("foo")));
+ TESTCLASSID_DEFAULT(EventListener);
+ TESTCLASSID_DEFAULT(ICUResourceBundleFactory);
+ //TESTCLASSID_DEFAULT(Key); // does not exist?
+ UnicodeString baz("baz");
+ UnicodeString bat("bat");
+ TESTCLASSID_FACTORY(LocaleKey, LocaleKey::createWithCanonicalFallback(&baz, &bat, LocaleKey::KIND_ANY, status));
+ TESTCLASSID_CTOR(SimpleLocaleKeyFactory, (NULL, UnicodeString("bar"), 8, 12) );
+ TESTCLASSID_CTOR(TestLocaleKeyFactory, (42)); // Test replacement for LocaleKeyFactory
+//#if UOBJTEST_TEST_INTERNALS
+// TESTCLASSID_CTOR(LocaleKeyFactory, (42));
+//#endif
+#endif
+
+#if UOBJTEST_DUMP_IDS
+ int i;
+ for(i=0;i<ids_count;i++) {
+ char junk[800];
+ sprintf(junk, " %4d:\t%p\t%s\t%s\n",
+ i, ids[i], ids_class[i], ids_factory[i]);
+ logln(UnicodeString(junk));
+ }
+#endif
+}
+
+void UObjectTest::testUMemory() {
+ // additional tests for code coverage
+#if U_OVERRIDE_CXX_ALLOCATION && U_HAVE_PLACEMENT_NEW
+ UAlignedMemory stackMemory[sizeof(UnicodeString)/sizeof(UAlignedMemory)+1];
+ UnicodeString *p;
+ enum { len=20 };
+
+ p=new(stackMemory) UnicodeString(len, (UChar32)0x20ac, len);
+ if((void *)p!=(void *)stackMemory) {
+ errln("placement new did not place the object at the expected address");
+ }
+ if(p->length()!=len || p->charAt(0)!=0x20ac || p->charAt(len-1)!=0x20ac) {
+ errln("constructor used with placement new did not work right");
+ }
+
+ /*
+ * It is not possible to simply say
+ * delete(p, stackMemory);
+ * which results in a call to the normal, non-placement delete operator.
+ *
+ * Via a search on google.com for "c++ placement delete" I found
+ * http://cpptips.hyperformix.com/cpptips/placement_del3
+ * which says:
+ *
+ * TITLE: using placement delete
+ *
+ * (Newsgroups: comp.std.c++, 27 Aug 97)
+ *
+ * ISJ: isj@image.dk
+ *
+ * > I do not completely understand how placement works on operator delete.
+ * > ...
+ * There is no delete-expression which will invoke a placement
+ * form of operator delete. You can still call the function
+ * explicitly. Example:
+ * ...
+ * // destroy object and delete space manually
+ * p->~T();
+ * operator delete(p, 12);
+ *
+ * ... so that's what I am doing here.
+ * markus 20031216
+ */
+ // destroy object and delete space manually
+ p->~UnicodeString();
+ UnicodeString::operator delete(p, stackMemory);
+
+ // Jitterbug 4452, for coverage
+ UnicodeString *pa = new UnicodeString[2];
+ if ( !pa[0].isEmpty() || !pa[1].isEmpty()){
+ errln("constructor used with array new did not work right");
+ }
+ delete [] pa;
+#endif
+
+ // try to call the compiler-generated UMemory::operator=(class UMemory const &)
+ UMemory m, n;
+ m=n;
+}
+
+void UObjectTest::TestMFCCompatibility() {
+#if U_HAVE_DEBUG_LOCATION_NEW
+ /* Make sure that it compiles with MFC's debuggable new usage. */
+ UnicodeString *str = new(__FILE__, __LINE__) UnicodeString();
+ str->append((UChar)0x0040); // Is it usable?
+ if(str->charAt(0) != 0x0040) {
+ errln("debug new doesn't work.");
+ }
+ UnicodeString::operator delete(str, __FILE__, __LINE__);
+#endif
+}
+
+/* --------------- */
+
+#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break;
+
+
+void UObjectTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /* par */ )
+{
+ switch (index) {
+
+ CASE(0, testIDs);
+ CASE(1, testUMemory);
+ CASE(2, TestMFCCompatibility);
+
+ default: name = ""; break; //needed to end loop
+ }
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/uobjtest.h b/Build/source/libs/icu/icu-xetex/test/intltest/uobjtest.h
new file mode 100644
index 00000000000..6c4dd48e6de
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/uobjtest.h
@@ -0,0 +1,42 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2005, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+
+#ifndef _UOBJECTTEST_
+#define _UOBJECTTEST_
+
+#include "intltest.h"
+
+/**
+ * Test uobjtest.h
+ **/
+class UObjectTest : public IntlTest {
+ // IntlTest override
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par );
+private:
+ // tests
+ void testIDs();
+ void testUMemory();
+ void TestMFCCompatibility();
+
+ //helper
+
+ /**
+ * @param obj The UObject to be tested
+ * @param className The name of the class being tested
+ * @param factory String version of obj, for exanple "new UFoo(1,3,4)". NULL if object is abstract.
+ * @param staticID The result of class :: getStaticClassID
+ * @return Returns obj, suitable for deletion
+ */
+ UObject *testClass(UObject *obj,
+ const char *className, const char *factory,
+ UClassID staticID);
+
+
+};
+
+#endif
+//eof
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/usettest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/usettest.cpp
new file mode 100644
index 00000000000..bcdd5ad3112
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/usettest.cpp
@@ -0,0 +1,3773 @@
+/*
+********************************************************************************
+* Copyright (C) 1999-2007 International Business Machines Corporation and
+* others. All Rights Reserved.
+********************************************************************************
+* Date Name Description
+* 10/20/99 alan Creation.
+* 03/22/2000 Madhu Added additional tests
+********************************************************************************
+*/
+
+#include <stdio.h>
+
+#include <string.h>
+#include "unicode/utypes.h"
+#include "usettest.h"
+#include "unicode/ucnv.h"
+#include "unicode/uniset.h"
+#include "unicode/uchar.h"
+#include "unicode/usetiter.h"
+#include "unicode/ustring.h"
+#include "unicode/parsepos.h"
+#include "unicode/symtable.h"
+#include "unicode/uversion.h"
+#include "hash.h"
+
+#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
+
+#define TEST_ASSERT_SUCCESS(status) {if (U_FAILURE(status)) { \
+ errln("fail in file \"%s\", line %d: \"%s\"", __FILE__, __LINE__, \
+ u_errorName(status));}}
+
+#define TEST_ASSERT(expr) {if (!(expr)) { \
+ errln("fail in file \"%s\", line %d", __FILE__, __LINE__); }}
+
+UnicodeString operator+(const UnicodeString& left, const UnicodeSet& set) {
+ UnicodeString pat;
+ set.toPattern(pat);
+ return left + UnicodeSetTest::escape(pat);
+}
+
+#define CASE(id,test) case id: \
+ name = #test; \
+ if (exec) { \
+ logln(#test "---"); \
+ logln(); \
+ test(); \
+ } \
+ break
+
+UnicodeSetTest::UnicodeSetTest() : utf8Cnv(NULL) {
+}
+
+UConverter *UnicodeSetTest::openUTF8Converter() {
+ if(utf8Cnv==NULL) {
+ UErrorCode errorCode=U_ZERO_ERROR;
+ utf8Cnv=ucnv_open("UTF-8", &errorCode);
+ }
+ return utf8Cnv;
+}
+
+UnicodeSetTest::~UnicodeSetTest() {
+ ucnv_close(utf8Cnv);
+}
+
+void
+UnicodeSetTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ // if (exec) logln((UnicodeString)"TestSuite UnicodeSetTest");
+ switch (index) {
+ CASE(0,TestPatterns);
+ CASE(1,TestAddRemove);
+ CASE(2,TestCategories);
+ CASE(3,TestCloneEqualHash);
+ CASE(4,TestMinimalRep);
+ CASE(5,TestAPI);
+ CASE(6,TestScriptSet);
+ CASE(7,TestPropertySet);
+ CASE(8,TestClone);
+ CASE(9,TestExhaustive);
+ CASE(10,TestToPattern);
+ CASE(11,TestIndexOf);
+ CASE(12,TestStrings);
+ CASE(13,Testj2268);
+ CASE(14,TestCloseOver);
+ CASE(15,TestEscapePattern);
+ CASE(16,TestInvalidCodePoint);
+ CASE(17,TestSymbolTable);
+ CASE(18,TestSurrogate);
+ CASE(19,TestPosixClasses);
+ CASE(20,TestIteration);
+ CASE(21,TestFreezable);
+ CASE(22,TestSpan);
+ CASE(23,TestStringSpan);
+ default: name = ""; break;
+ }
+}
+
+static const char NOT[] = "%%%%";
+
+/**
+ * UVector was improperly copying contents
+ * This code will crash this is still true
+ */
+void UnicodeSetTest::Testj2268() {
+ UnicodeSet t;
+ t.add(UnicodeString("abc"));
+ UnicodeSet test(t);
+ UnicodeString ustrPat;
+ test.toPattern(ustrPat, TRUE);
+}
+
+/**
+ * Test toPattern().
+ */
+void UnicodeSetTest::TestToPattern() {
+ UErrorCode ec = U_ZERO_ERROR;
+
+ // Test that toPattern() round trips with syntax characters and
+ // whitespace.
+ {
+ static const char* OTHER_TOPATTERN_TESTS[] = {
+ "[[:latin:]&[:greek:]]",
+ "[[:latin:]-[:greek:]]",
+ "[:nonspacing mark:]",
+ NULL
+ };
+
+ for (int32_t j=0; OTHER_TOPATTERN_TESTS[j]!=NULL; ++j) {
+ ec = U_ZERO_ERROR;
+ UnicodeSet s(OTHER_TOPATTERN_TESTS[j], ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: bad pattern " + OTHER_TOPATTERN_TESTS[j]);
+ continue;
+ }
+ checkPat(OTHER_TOPATTERN_TESTS[j], s);
+ }
+
+ for (UChar32 i = 0; i <= 0x10FFFF; ++i) {
+ if ((i <= 0xFF && !u_isalpha(i)) || u_isspace(i)) {
+
+ // check various combinations to make sure they all work.
+ if (i != 0 && !toPatternAux(i, i)){
+ continue;
+ }
+ if (!toPatternAux(0, i)){
+ continue;
+ }
+ if (!toPatternAux(i, 0xFFFF)){
+ continue;
+ }
+ }
+ }
+ }
+
+ // Test pattern behavior of multicharacter strings.
+ {
+ ec = U_ZERO_ERROR;
+ UnicodeSet* s = new UnicodeSet("[a-z {aa} {ab}]", ec);
+
+ // This loop isn't a loop. It's here to make the compiler happy.
+ // If you're curious, try removing it and changing the 'break'
+ // statements (except for the last) to goto's.
+ for (;;) {
+ if (U_FAILURE(ec)) break;
+ const char* exp1[] = {"aa", "ab", NOT, "ac", NULL};
+ expectToPattern(*s, "[a-z{aa}{ab}]", exp1);
+
+ s->add("ac");
+ const char* exp2[] = {"aa", "ab", "ac", NOT, "xy", NULL};
+ expectToPattern(*s, "[a-z{aa}{ab}{ac}]", exp2);
+
+ s->applyPattern("[a-z {\\{l} {r\\}}]", ec);
+ if (U_FAILURE(ec)) break;
+ const char* exp3[] = {"{l", "r}", NOT, "xy", NULL};
+ expectToPattern(*s, "[a-z{r\\}}{\\{l}]", exp3);
+
+ s->add("[]");
+ const char* exp4[] = {"{l", "r}", "[]", NOT, "xy", NULL};
+ expectToPattern(*s, "[a-z{\\[\\]}{r\\}}{\\{l}]", exp4);
+
+ s->applyPattern("[a-z {\\u4E01\\u4E02}{\\n\\r}]", ec);
+ if (U_FAILURE(ec)) break;
+ const char* exp5[] = {"\\u4E01\\u4E02", "\n\r", NULL};
+ expectToPattern(*s, "[a-z{\\u000A\\u000D}{\\u4E01\\u4E02}]", exp5);
+
+ // j2189
+ s->clear();
+ s->add(UnicodeString("abc", ""));
+ s->add(UnicodeString("abc", ""));
+ const char* exp6[] = {"abc", NOT, "ab", NULL};
+ expectToPattern(*s, "[{abc}]", exp6);
+
+ break;
+ }
+
+ if (U_FAILURE(ec)) errln("FAIL: pattern parse error");
+ delete s;
+ }
+
+ // JB#3400: For 2 character ranges prefer [ab] to [a-b]
+ UnicodeSet s;
+ s.add((UChar)97, (UChar)98); // 'a', 'b'
+ expectToPattern(s, "[ab]", NULL);
+}
+
+UBool UnicodeSetTest::toPatternAux(UChar32 start, UChar32 end) {
+
+ // use Integer.toString because Utility.hex doesn't handle ints
+ UnicodeString pat = "";
+ // TODO do these in hex
+ //String source = "0x" + Integer.toString(start,16).toUpperCase();
+ //if (start != end) source += "..0x" + Integer.toString(end,16).toUpperCase();
+ UnicodeString source;
+ source = source + (uint32_t)start;
+ if (start != end)
+ source = source + ".." + (uint32_t)end;
+ UnicodeSet testSet;
+ testSet.add(start, end);
+ return checkPat(source, testSet);
+}
+
+UBool UnicodeSetTest::checkPat(const UnicodeString& source,
+ const UnicodeSet& testSet) {
+ // What we want to make sure of is that a pattern generated
+ // by toPattern(), with or without escaped unprintables, can
+ // be passed back into the UnicodeSet constructor.
+ UnicodeString pat0;
+
+ testSet.toPattern(pat0, TRUE);
+
+ if (!checkPat(source + " (escaped)", testSet, pat0)) return FALSE;
+
+ //String pat1 = unescapeLeniently(pat0);
+ //if (!checkPat(source + " (in code)", testSet, pat1)) return false;
+
+ UnicodeString pat2;
+ testSet.toPattern(pat2, FALSE);
+ if (!checkPat(source, testSet, pat2)) return FALSE;
+
+ //String pat3 = unescapeLeniently(pat2);
+ // if (!checkPat(source + " (in code)", testSet, pat3)) return false;
+
+ //logln(source + " => " + pat0 + ", " + pat1 + ", " + pat2 + ", " + pat3);
+ logln((UnicodeString)source + " => " + pat0 + ", " + pat2);
+ return TRUE;
+}
+
+UBool UnicodeSetTest::checkPat(const UnicodeString& source,
+ const UnicodeSet& testSet,
+ const UnicodeString& pat) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeSet testSet2(pat, ec);
+ if (testSet2 != testSet) {
+ errln((UnicodeString)"Fail toPattern: " + source + " => " + pat);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void
+UnicodeSetTest::TestPatterns(void) {
+ UnicodeSet set;
+ expectPattern(set, UnicodeString("[[a-m]&[d-z]&[k-y]]", ""), "km");
+ expectPattern(set, UnicodeString("[[a-z]-[m-y]-[d-r]]", ""), "aczz");
+ expectPattern(set, UnicodeString("[a\\-z]", ""), "--aazz");
+ expectPattern(set, UnicodeString("[-az]", ""), "--aazz");
+ expectPattern(set, UnicodeString("[az-]", ""), "--aazz");
+ expectPattern(set, UnicodeString("[[[a-z]-[aeiou]i]]", ""), "bdfnptvz");
+
+ // Throw in a test of complement
+ set.complement();
+ UnicodeString exp;
+ exp.append((UChar)0x0000).append("aeeoouu").append((UChar)(0x007a+1)).append((UChar)0xFFFF);
+ expectPairs(set, exp);
+}
+
+void
+UnicodeSetTest::TestCategories(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ const char* pat = " [:Lu:] "; // Whitespace ok outside [:..:]
+ UnicodeSet set(pat, status);
+ if (U_FAILURE(status)) {
+ errln((UnicodeString)"Fail: Can't construct set with " + pat);
+ } else {
+ expectContainment(set, pat, "ABC", "abc");
+ }
+
+ UChar32 i;
+ int32_t failures = 0;
+ // Make sure generation of L doesn't pollute cached Lu set
+ // First generate L, then Lu
+ set.applyPattern("[:L:]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ for (i=0; i<0x200; ++i) {
+ UBool l = u_isalpha((UChar)i);
+ if (l != set.contains(i)) {
+ errln((UnicodeString)"FAIL: L contains " + (unsigned short)i + " = " +
+ set.contains(i));
+ if (++failures == 10) break;
+ }
+ }
+
+ set.applyPattern("[:Lu:]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ for (i=0; i<0x200; ++i) {
+ UBool lu = (u_charType((UChar)i) == U_UPPERCASE_LETTER);
+ if (lu != set.contains(i)) {
+ errln((UnicodeString)"FAIL: Lu contains " + (unsigned short)i + " = " +
+ set.contains(i));
+ if (++failures == 20) break;
+ }
+ }
+}
+void
+UnicodeSetTest::TestCloneEqualHash(void) {
+ UErrorCode status = U_ZERO_ERROR;
+ // set1 and set2 used to be built with the obsolete constructor taking
+ // UCharCategory values; replaced with pattern constructors
+ // markus 20030502
+ UnicodeSet *set1=new UnicodeSet("\\p{Lowercase Letter}", status); // :Ll: Letter, lowercase
+ UnicodeSet *set1a=new UnicodeSet("[:Ll:]", status); // Letter, lowercase
+ if (U_FAILURE(status)){
+ errln((UnicodeString)"FAIL: Can't construst set with category->Ll");
+ return;
+ }
+ UnicodeSet *set2=new UnicodeSet("\\p{Decimal Number}", status); //Number, Decimal digit
+ UnicodeSet *set2a=new UnicodeSet("[:Nd:]", status); //Number, Decimal digit
+ if (U_FAILURE(status)){
+ errln((UnicodeString)"FAIL: Can't construct set with category->Nd");
+ return;
+ }
+
+ if (*set1 != *set1a) {
+ errln("FAIL: category constructor for Ll broken");
+ }
+ if (*set2 != *set2a) {
+ errln("FAIL: category constructor for Nd broken");
+ }
+ delete set1a;
+ delete set2a;
+
+ logln("Testing copy construction");
+ UnicodeSet *set1copy=new UnicodeSet(*set1);
+ if(*set1 != *set1copy || *set1 == *set2 ||
+ getPairs(*set1) != getPairs(*set1copy) ||
+ set1->hashCode() != set1copy->hashCode()){
+ errln("FAIL : Error in copy construction");
+ return;
+ }
+
+ logln("Testing =operator");
+ UnicodeSet set1equal=*set1;
+ UnicodeSet set2equal=*set2;
+ if(set1equal != *set1 || set1equal != *set1copy || set2equal != *set2 ||
+ set2equal == *set1 || set2equal == *set1copy || set2equal == set1equal){
+ errln("FAIL: Error in =operator");
+ }
+
+ logln("Testing clone()");
+ UnicodeSet *set1clone=(UnicodeSet*)set1->clone();
+ UnicodeSet *set2clone=(UnicodeSet*)set2->clone();
+ if(*set1clone != *set1 || *set1clone != *set1copy || *set1clone != set1equal ||
+ *set2clone != *set2 || *set2clone == *set1copy || *set2clone != set2equal ||
+ *set2clone == *set1 || *set2clone == set1equal || *set2clone == *set1clone){
+ errln("FAIL: Error in clone");
+ }
+
+ logln("Testing hashcode");
+ if(set1->hashCode() != set1equal.hashCode() || set1->hashCode() != set1clone->hashCode() ||
+ set2->hashCode() != set2equal.hashCode() || set2->hashCode() != set2clone->hashCode() ||
+ set1copy->hashCode() != set1equal.hashCode() || set1copy->hashCode() != set1clone->hashCode() ||
+ set1->hashCode() == set2->hashCode() || set1copy->hashCode() == set2->hashCode() ||
+ set2->hashCode() == set1clone->hashCode() || set2->hashCode() == set1equal.hashCode() ){
+ errln("FAIL: Error in hashCode()");
+ }
+
+ delete set1;
+ delete set1copy;
+ delete set2;
+ delete set1clone;
+ delete set2clone;
+
+
+}
+void
+UnicodeSetTest::TestAddRemove(void) {
+ UnicodeSet set; // Construct empty set
+ doAssert(set.isEmpty() == TRUE, "set should be empty");
+ doAssert(set.size() == 0, "size should be 0");
+ set.complement();
+ doAssert(set.size() == 0x110000, "size should be 0x110000");
+ set.clear();
+ set.add(0x0061, 0x007a);
+ expectPairs(set, "az");
+ doAssert(set.isEmpty() == FALSE, "set should not be empty");
+ doAssert(set.size() != 0, "size should not be equal to 0");
+ doAssert(set.size() == 26, "size should be equal to 26");
+ set.remove(0x006d, 0x0070);
+ expectPairs(set, "alqz");
+ doAssert(set.size() == 22, "size should be equal to 22");
+ set.remove(0x0065, 0x0067);
+ expectPairs(set, "adhlqz");
+ doAssert(set.size() == 19, "size should be equal to 19");
+ set.remove(0x0064, 0x0069);
+ expectPairs(set, "acjlqz");
+ doAssert(set.size() == 16, "size should be equal to 16");
+ set.remove(0x0063, 0x0072);
+ expectPairs(set, "absz");
+ doAssert(set.size() == 10, "size should be equal to 10");
+ set.add(0x0066, 0x0071);
+ expectPairs(set, "abfqsz");
+ doAssert(set.size() == 22, "size should be equal to 22");
+ set.remove(0x0061, 0x0067);
+ expectPairs(set, "hqsz");
+ set.remove(0x0061, 0x007a);
+ expectPairs(set, "");
+ doAssert(set.isEmpty() == TRUE, "set should be empty");
+ doAssert(set.size() == 0, "size should be 0");
+ set.add(0x0061);
+ doAssert(set.isEmpty() == FALSE, "set should not be empty");
+ doAssert(set.size() == 1, "size should not be equal to 1");
+ set.add(0x0062);
+ set.add(0x0063);
+ expectPairs(set, "ac");
+ doAssert(set.size() == 3, "size should not be equal to 3");
+ set.add(0x0070);
+ set.add(0x0071);
+ expectPairs(set, "acpq");
+ doAssert(set.size() == 5, "size should not be equal to 5");
+ set.clear();
+ expectPairs(set, "");
+ doAssert(set.isEmpty() == TRUE, "set should be empty");
+ doAssert(set.size() == 0, "size should be 0");
+
+ // Try removing an entire set from another set
+ expectPattern(set, "[c-x]", "cx");
+ UnicodeSet set2;
+ expectPattern(set2, "[f-ky-za-bc[vw]]", "acfkvwyz");
+ set.removeAll(set2);
+ expectPairs(set, "deluxx");
+
+ // Try adding an entire set to another set
+ expectPattern(set, "[jackiemclean]", "aacceein");
+ expectPattern(set2, "[hitoshinamekatajamesanderson]", "aadehkmort");
+ set.addAll(set2);
+ expectPairs(set, "aacehort");
+ doAssert(set.containsAll(set2) == TRUE, "set should contain all the elements in set2");
+
+ // Try retaining an set of elements contained in another set (intersection)
+ UnicodeSet set3;
+ expectPattern(set3, "[a-c]", "ac");
+ doAssert(set.containsAll(set3) == FALSE, "set doesn't contain all the elements in set3");
+ set3.remove(0x0062);
+ expectPairs(set3, "aacc");
+ doAssert(set.containsAll(set3) == TRUE, "set should contain all the elements in set3");
+ set.retainAll(set3);
+ expectPairs(set, "aacc");
+ doAssert(set.size() == set3.size(), "set.size() should be set3.size()");
+ doAssert(set.containsAll(set3) == TRUE, "set should contain all the elements in set3");
+ set.clear();
+ doAssert(set.size() != set3.size(), "set.size() != set3.size()");
+
+ // Test commutativity
+ expectPattern(set, "[hitoshinamekatajamesanderson]", "aadehkmort");
+ expectPattern(set2, "[jackiemclean]", "aacceein");
+ set.addAll(set2);
+ expectPairs(set, "aacehort");
+ doAssert(set.containsAll(set2) == TRUE, "set should contain all the elements in set2");
+
+
+
+
+}
+
+/**
+ * Make sure minimal representation is maintained.
+ */
+void UnicodeSetTest::TestMinimalRep() {
+ UErrorCode status = U_ZERO_ERROR;
+ // This is pretty thoroughly tested by checkCanonicalRep()
+ // run against the exhaustive operation results. Use the code
+ // here for debugging specific spot problems.
+
+ // 1 overlap against 2
+ UnicodeSet set("[h-km-q]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ UnicodeSet set2("[i-o]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ set.addAll(set2);
+ expectPairs(set, "hq");
+ // right
+ set.applyPattern("[a-m]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ set2.applyPattern("[e-o]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ set.addAll(set2);
+ expectPairs(set, "ao");
+ // left
+ set.applyPattern("[e-o]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ set2.applyPattern("[a-m]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ set.addAll(set2);
+ expectPairs(set, "ao");
+ // 1 overlap against 3
+ set.applyPattern("[a-eg-mo-w]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ set2.applyPattern("[d-q]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ set.addAll(set2);
+ expectPairs(set, "aw");
+}
+
+void UnicodeSetTest::TestAPI() {
+ UErrorCode status = U_ZERO_ERROR;
+ // default ct
+ UnicodeSet set;
+ if (!set.isEmpty() || set.getRangeCount() != 0) {
+ errln((UnicodeString)"FAIL, set should be empty but isn't: " +
+ set);
+ }
+
+ // clear(), isEmpty()
+ set.add(0x0061);
+ if (set.isEmpty()) {
+ errln((UnicodeString)"FAIL, set shouldn't be empty but is: " +
+ set);
+ }
+ set.clear();
+ if (!set.isEmpty()) {
+ errln((UnicodeString)"FAIL, set should be empty but isn't: " +
+ set);
+ }
+
+ // size()
+ set.clear();
+ if (set.size() != 0) {
+ errln((UnicodeString)"FAIL, size should be 0, but is " + set.size() +
+ ": " + set);
+ }
+ set.add(0x0061);
+ if (set.size() != 1) {
+ errln((UnicodeString)"FAIL, size should be 1, but is " + set.size() +
+ ": " + set);
+ }
+ set.add(0x0031, 0x0039);
+ if (set.size() != 10) {
+ errln((UnicodeString)"FAIL, size should be 10, but is " + set.size() +
+ ": " + set);
+ }
+
+ // contains(first, last)
+ set.clear();
+ set.applyPattern("[A-Y 1-8 b-d l-y]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ for (int32_t i = 0; i<set.getRangeCount(); ++i) {
+ UChar32 a = set.getRangeStart(i);
+ UChar32 b = set.getRangeEnd(i);
+ if (!set.contains(a, b)) {
+ errln((UnicodeString)"FAIL, should contain " + (unsigned short)a + '-' + (unsigned short)b +
+ " but doesn't: " + set);
+ }
+ if (set.contains((UChar32)(a-1), b)) {
+ errln((UnicodeString)"FAIL, shouldn't contain " +
+ (unsigned short)(a-1) + '-' + (unsigned short)b +
+ " but does: " + set);
+ }
+ if (set.contains(a, (UChar32)(b+1))) {
+ errln((UnicodeString)"FAIL, shouldn't contain " +
+ (unsigned short)a + '-' + (unsigned short)(b+1) +
+ " but does: " + set);
+ }
+ }
+
+ // Ported InversionList test.
+ UnicodeSet a((UChar32)3,(UChar32)10);
+ UnicodeSet b((UChar32)7,(UChar32)15);
+ UnicodeSet c;
+
+ logln((UnicodeString)"a [3-10]: " + a);
+ logln((UnicodeString)"b [7-15]: " + b);
+ c = a;
+ c.addAll(b);
+ UnicodeSet exp((UChar32)3,(UChar32)15);
+ if (c == exp) {
+ logln((UnicodeString)"c.set(a).add(b): " + c);
+ } else {
+ errln((UnicodeString)"FAIL: c.set(a).add(b) = " + c + ", expect " + exp);
+ }
+ c.complement();
+ exp.set((UChar32)0, (UChar32)2);
+ exp.add((UChar32)16, UnicodeSet::MAX_VALUE);
+ if (c == exp) {
+ logln((UnicodeString)"c.complement(): " + c);
+ } else {
+ errln((UnicodeString)"FAIL: c.complement() = " + c + ", expect " + exp);
+ }
+ c.complement();
+ exp.set((UChar32)3, (UChar32)15);
+ if (c == exp) {
+ logln((UnicodeString)"c.complement(): " + c);
+ } else {
+ errln((UnicodeString)"FAIL: c.complement() = " + c + ", expect " + exp);
+ }
+ c = a;
+ c.complementAll(b);
+ exp.set((UChar32)3,(UChar32)6);
+ exp.add((UChar32)11,(UChar32) 15);
+ if (c == exp) {
+ logln((UnicodeString)"c.set(a).exclusiveOr(b): " + c);
+ } else {
+ errln((UnicodeString)"FAIL: c.set(a).exclusiveOr(b) = " + c + ", expect " + exp);
+ }
+
+ exp = c;
+ bitsToSet(setToBits(c), c);
+ if (c == exp) {
+ logln((UnicodeString)"bitsToSet(setToBits(c)): " + c);
+ } else {
+ errln((UnicodeString)"FAIL: bitsToSet(setToBits(c)) = " + c + ", expect " + exp);
+ }
+
+ // Additional tests for coverage JB#2118
+ //UnicodeSet::complement(class UnicodeString const &)
+ //UnicodeSet::complementAll(class UnicodeString const &)
+ //UnicodeSet::containsNone(class UnicodeSet const &)
+ //UnicodeSet::containsNone(long,long)
+ //UnicodeSet::containsSome(class UnicodeSet const &)
+ //UnicodeSet::containsSome(long,long)
+ //UnicodeSet::removeAll(class UnicodeString const &)
+ //UnicodeSet::retain(long)
+ //UnicodeSet::retainAll(class UnicodeString const &)
+ //UnicodeSet::serialize(unsigned short *,long,enum UErrorCode &)
+ //UnicodeSetIterator::getString(void)
+ set.clear();
+ set.complement("ab");
+ exp.applyPattern("[{ab}]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ if (set != exp) { errln("FAIL: complement(\"ab\")"); return; }
+
+ UnicodeSetIterator iset(set);
+ if (!iset.next() || !iset.isString()) {
+ errln("FAIL: UnicodeSetIterator::next/isString");
+ } else if (iset.getString() != "ab") {
+ errln("FAIL: UnicodeSetIterator::getString");
+ }
+
+ set.add((UChar32)0x61, (UChar32)0x7A);
+ set.complementAll("alan");
+ exp.applyPattern("[{ab}b-kmo-z]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ if (set != exp) { errln("FAIL: complementAll(\"alan\")"); return; }
+
+ exp.applyPattern("[a-z]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ if (set.containsNone(exp)) { errln("FAIL: containsNone(UnicodeSet)"); }
+ if (!set.containsSome(exp)) { errln("FAIL: containsSome(UnicodeSet)"); }
+ exp.applyPattern("[aln]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ if (!set.containsNone(exp)) { errln("FAIL: containsNone(UnicodeSet)"); }
+ if (set.containsSome(exp)) { errln("FAIL: containsSome(UnicodeSet)"); }
+
+ if (set.containsNone((UChar32)0x61, (UChar32)0x7A)) {
+ errln("FAIL: containsNone(UChar32, UChar32)");
+ }
+ if (!set.containsSome((UChar32)0x61, (UChar32)0x7A)) {
+ errln("FAIL: containsSome(UChar32, UChar32)");
+ }
+ if (!set.containsNone((UChar32)0x41, (UChar32)0x5A)) {
+ errln("FAIL: containsNone(UChar32, UChar32)");
+ }
+ if (set.containsSome((UChar32)0x41, (UChar32)0x5A)) {
+ errln("FAIL: containsSome(UChar32, UChar32)");
+ }
+
+ set.removeAll("liu");
+ exp.applyPattern("[{ab}b-hj-kmo-tv-z]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ if (set != exp) { errln("FAIL: removeAll(\"liu\")"); return; }
+
+ set.retainAll("star");
+ exp.applyPattern("[rst]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ if (set != exp) { errln("FAIL: retainAll(\"star\")"); return; }
+
+ set.retain((UChar32)0x73);
+ exp.applyPattern("[s]", status);
+ if (U_FAILURE(status)) { errln("FAIL"); return; }
+ if (set != exp) { errln("FAIL: retain('s')"); return; }
+
+ uint16_t buf[32];
+ int32_t slen = set.serialize(buf, sizeof(buf)/sizeof(buf[0]), status);
+ if (U_FAILURE(status)) { errln("FAIL: serialize"); return; }
+ if (slen != 3 || buf[0] != 2 || buf[1] != 0x73 || buf[2] != 0x74) {
+ errln("FAIL: serialize");
+ return;
+ }
+}
+
+void UnicodeSetTest::TestIteration() {
+ UErrorCode ec = U_ZERO_ERROR;
+ int i = 0;
+ int outerLoop;
+
+ // 6 code points, 3 ranges, 2 strings, 8 total elements
+ // Iteration will access them in sorted order - a, b, c, y, z, U0001abcd, "str1", "str2"
+ UnicodeSet set("[zabyc\\U0001abcd{str1}{str2}]", ec);
+ TEST_ASSERT_SUCCESS(ec);
+ UnicodeSetIterator it(set);
+
+ for (outerLoop=0; outerLoop<3; outerLoop++) {
+ // Run the test multiple times, to check that iterator.reset() is working.
+ for (i=0; i<10; i++) {
+ UBool nextv = it.next();
+ UBool isString = it.isString();
+ int32_t codePoint = it.getCodepoint();
+ //int32_t codePointEnd = it.getCodepointEnd();
+ UnicodeString s = it.getString();
+ switch (i) {
+ case 0:
+ TEST_ASSERT(nextv == TRUE);
+ TEST_ASSERT(isString == FALSE);
+ TEST_ASSERT(codePoint==0x61);
+ TEST_ASSERT(s == "a");
+ break;
+ case 1:
+ TEST_ASSERT(nextv == TRUE);
+ TEST_ASSERT(isString == FALSE);
+ TEST_ASSERT(codePoint==0x62);
+ TEST_ASSERT(s == "b");
+ break;
+ case 2:
+ TEST_ASSERT(nextv == TRUE);
+ TEST_ASSERT(isString == FALSE);
+ TEST_ASSERT(codePoint==0x63);
+ TEST_ASSERT(s == "c");
+ break;
+ case 3:
+ TEST_ASSERT(nextv == TRUE);
+ TEST_ASSERT(isString == FALSE);
+ TEST_ASSERT(codePoint==0x79);
+ TEST_ASSERT(s == "y");
+ break;
+ case 4:
+ TEST_ASSERT(nextv == TRUE);
+ TEST_ASSERT(isString == FALSE);
+ TEST_ASSERT(codePoint==0x7a);
+ TEST_ASSERT(s == "z");
+ break;
+ case 5:
+ TEST_ASSERT(nextv == TRUE);
+ TEST_ASSERT(isString == FALSE);
+ TEST_ASSERT(codePoint==0x1abcd);
+ TEST_ASSERT(s == UnicodeString((UChar32)0x1abcd));
+ break;
+ case 6:
+ TEST_ASSERT(nextv == TRUE);
+ TEST_ASSERT(isString == TRUE);
+ TEST_ASSERT(s == "str1");
+ break;
+ case 7:
+ TEST_ASSERT(nextv == TRUE);
+ TEST_ASSERT(isString == TRUE);
+ TEST_ASSERT(s == "str2");
+ break;
+ case 8:
+ TEST_ASSERT(nextv == FALSE);
+ break;
+ case 9:
+ TEST_ASSERT(nextv == FALSE);
+ break;
+ }
+ }
+ it.reset(); // prepare to run the iteration again.
+ }
+}
+
+
+
+
+void UnicodeSetTest::TestStrings() {
+ UErrorCode ec = U_ZERO_ERROR;
+
+ UnicodeSet* testList[] = {
+ UnicodeSet::createFromAll("abc"),
+ new UnicodeSet("[a-c]", ec),
+
+ &(UnicodeSet::createFrom("ch")->add('a','z').add("ll")),
+ new UnicodeSet("[{ll}{ch}a-z]", ec),
+
+ UnicodeSet::createFrom("ab}c"),
+ new UnicodeSet("[{ab\\}c}]", ec),
+
+ &((new UnicodeSet('a','z'))->add('A', 'Z').retain('M','m').complement('X')),
+ new UnicodeSet("[[a-zA-Z]&[M-m]-[X]]", ec),
+
+ NULL
+ };
+
+ if (U_FAILURE(ec)) {
+ errln("FAIL: couldn't construct test sets");
+ }
+
+ for (int32_t i = 0; testList[i] != NULL; i+=2) {
+ if (U_SUCCESS(ec)) {
+ UnicodeString pat0, pat1;
+ testList[i]->toPattern(pat0, TRUE);
+ testList[i+1]->toPattern(pat1, TRUE);
+ if (*testList[i] == *testList[i+1]) {
+ logln((UnicodeString)"Ok: " + pat0 + " == " + pat1);
+ } else {
+ logln((UnicodeString)"FAIL: " + pat0 + " != " + pat1);
+ }
+ }
+ delete testList[i];
+ delete testList[i+1];
+ }
+}
+
+/**
+ * Test the [:Latin:] syntax.
+ */
+void UnicodeSetTest::TestScriptSet() {
+ expectContainment("[:Latin:]", "aA", CharsToUnicodeString("\\u0391\\u03B1"));
+
+ expectContainment("[:Greek:]", CharsToUnicodeString("\\u0391\\u03B1"), "aA");
+
+ /* Jitterbug 1423 */
+ expectContainment("[[:Common:][:Inherited:]]", CharsToUnicodeString("\\U00003099\\U0001D169\\u0000"), "aA");
+
+}
+
+/**
+ * Test the [:Latin:] syntax.
+ */
+void UnicodeSetTest::TestPropertySet() {
+ static const char* const DATA[] = {
+ // Pattern, Chars IN, Chars NOT in
+
+ "[:Latin:]",
+ "aA",
+ "\\u0391\\u03B1",
+
+ "[\\p{Greek}]",
+ "\\u0391\\u03B1",
+ "aA",
+
+ "\\P{ GENERAL Category = upper case letter }",
+ "abc",
+ "ABC",
+
+ // Combining class: @since ICU 2.2
+ // Check both symbolic and numeric
+ "\\p{ccc=Nukta}",
+ "\\u0ABC",
+ "abc",
+
+ "\\p{Canonical Combining Class = 11}",
+ "\\u05B1",
+ "\\u05B2",
+
+ "[:c c c = iota subscript :]",
+ "\\u0345",
+ "xyz",
+
+ // Bidi class: @since ICU 2.2
+ "\\p{bidiclass=lefttoright}",
+ "abc",
+ "\\u0671\\u0672",
+
+ // Binary properties: @since ICU 2.2
+ "\\p{ideographic}",
+ "\\u4E0A",
+ "x",
+
+ "[:math=false:]",
+ "q)*(",
+ // weiv: )(and * were removed from math in Unicode 4.0.1
+ //"(*+)",
+ "+<>^",
+
+ // JB#1767 \N{}, \p{ASCII}
+ "[:Ascii:]",
+ "abc\\u0000\\u007F",
+ "\\u0080\\u4E00",
+
+ "[\\N{ latin small letter a }[:name= latin small letter z:]]",
+ "az",
+ "qrs",
+
+ // JB#2015
+ "[:any:]",
+ "a\\U0010FFFF",
+ "",
+
+ "[:nv=0.5:]",
+ "\\u00BD\\u0F2A",
+ "\\u00BC",
+
+ // JB#2653: Age
+ "[:Age=1.1:]",
+ "\\u03D6", // 1.1
+ "\\u03D8\\u03D9", // 3.2
+
+ "[:Age=3.1:]",
+ "\\u1800\\u3400\\U0002f800",
+ "\\u0220\\u034f\\u30ff\\u33ff\\ufe73\\U00010000\\U00050000",
+
+ // JB#2350: Case_Sensitive
+ "[:Case Sensitive:]",
+ "A\\u1FFC\\U00010410",
+ ";\\u00B4\\U00010500",
+
+ // JB#2832: C99-compatibility props
+ "[:blank:]",
+ " \\u0009",
+ "1-9A-Z",
+
+ "[:graph:]",
+ "19AZ",
+ " \\u0003\\u0007\\u0009\\u000A\\u000D",
+
+ "[:punct:]",
+ "!@#%&*()[]{}-_\\/;:,.?'\"",
+ "09azAZ",
+
+ "[:xdigit:]",
+ "09afAF",
+ "gG!",
+
+ // Regex compatibility test
+ "[-b]", // leading '-' is literal
+ "-b",
+ "ac",
+
+ "[^-b]", // leading '-' is literal
+ "ac",
+ "-b",
+
+ "[b-]", // trailing '-' is literal
+ "-b",
+ "ac",
+
+ "[^b-]", // trailing '-' is literal
+ "ac",
+ "-b",
+
+ "[a-b-]", // trailing '-' is literal
+ "ab-",
+ "c=",
+
+ "[[a-q]&[p-z]-]", // trailing '-' is literal
+ "pq-",
+ "or=",
+
+ "[\\s|\\)|:|$|\\>]", // from regex tests
+ "s|):$>",
+ "abc",
+
+ "[\\uDC00cd]", // JB#2906: isolated trail at start
+ "cd\\uDC00",
+ "ab\\uD800\\U00010000",
+
+ "[ab\\uD800]", // JB#2906: isolated trail at start
+ "ab\\uD800",
+ "cd\\uDC00\\U00010000",
+
+ "[ab\\uD800cd]", // JB#2906: isolated lead in middle
+ "abcd\\uD800",
+ "ef\\uDC00\\U00010000",
+
+ "[ab\\uDC00cd]", // JB#2906: isolated trail in middle
+ "abcd\\uDC00",
+ "ef\\uD800\\U00010000",
+
+ "[:^lccc=0:]", // Lead canonical class
+ "\\u0300\\u0301",
+ "abcd\\u00c0\\u00c5",
+
+ "[:^tccc=0:]", // Trail canonical class
+ "\\u0300\\u0301\\u00c0\\u00c5",
+ "abcd",
+
+ "[[:^lccc=0:][:^tccc=0:]]", // Lead and trail canonical class
+ "\\u0300\\u0301\\u00c0\\u00c5",
+ "abcd",
+
+ "[[:^lccc=0:]-[:^tccc=0:]]", // Stuff that starts with an accent but ends with a base (none right now)
+ "",
+ "abcd\\u0300\\u0301\\u00c0\\u00c5",
+
+ "[[:ccc=0:]-[:lccc=0:]-[:tccc=0:]]", // Weirdos. Complete canonical class is zero, but both lead and trail are not
+ "\\u0F73\\u0F75\\u0F81",
+ "abcd\\u0300\\u0301\\u00c0\\u00c5",
+
+ "[:Assigned:]",
+ "A\\uE000\\uF8FF\\uFDC7\\U00010000\\U0010FFFD",
+ "\\u0888\\uFDD3\\uFFFE\\U00050005"
+ };
+
+ static const int32_t DATA_LEN = sizeof(DATA)/sizeof(DATA[0]);
+
+ for (int32_t i=0; i<DATA_LEN; i+=3) {
+ expectContainment(DATA[i], CharsToUnicodeString(DATA[i+1]),
+ CharsToUnicodeString(DATA[i+2]));
+ }
+}
+
+/**
+ * Test that Posix style character classes [:digit:], etc.
+ * have the Unicode definitions from TR 18.
+ */
+void UnicodeSetTest::TestPosixClasses() {
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:alpha:]", status);
+ UnicodeSet s2("\\p{Alphabetic}", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:lower:]", status);
+ UnicodeSet s2("\\p{lowercase}", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:upper:]", status);
+ UnicodeSet s2("\\p{Uppercase}", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:punct:]", status);
+ UnicodeSet s2("\\p{gc=Punctuation}", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:digit:]", status);
+ UnicodeSet s2("\\p{gc=DecimalNumber}", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:xdigit:]", status);
+ UnicodeSet s2("[\\p{DecimalNumber}\\p{HexDigit}]", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:alnum:]", status);
+ UnicodeSet s2("[\\p{Alphabetic}\\p{DecimalNumber}]", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:space:]", status);
+ UnicodeSet s2("\\p{Whitespace}", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:blank:]", status);
+ TEST_ASSERT_SUCCESS(status);
+ UnicodeSet s2("[\\p{Whitespace}-[\\u000a\\u000B\\u000c\\u000d\\u0085\\p{LineSeparator}\\p{ParagraphSeparator}]]",
+ status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:cntrl:]", status);
+ TEST_ASSERT_SUCCESS(status);
+ UnicodeSet s2("\\p{Control}", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:graph:]", status);
+ TEST_ASSERT_SUCCESS(status);
+ UnicodeSet s2("[^\\p{Whitespace}\\p{Control}\\p{Surrogate}\\p{Unassigned}]", status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeSet s1("[:print:]", status);
+ TEST_ASSERT_SUCCESS(status);
+ UnicodeSet s2("[[:graph:][:blank:]-[\\p{Control}]]" ,status);
+ TEST_ASSERT_SUCCESS(status);
+ TEST_ASSERT(s1==s2);
+ }
+}
+/**
+ * Test cloning of UnicodeSet. For C++, we test the copy constructor.
+ */
+void UnicodeSetTest::TestClone() {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeSet s("[abcxyz]", ec);
+ UnicodeSet t(s);
+ expectContainment(t, "abc", "def");
+}
+
+/**
+ * Test the indexOf() and charAt() methods.
+ */
+void UnicodeSetTest::TestIndexOf() {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeSet set("[a-cx-y3578]", ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: UnicodeSet constructor");
+ return;
+ }
+ for (int32_t i=0; i<set.size(); ++i) {
+ UChar32 c = set.charAt(i);
+ if (set.indexOf(c) != i) {
+ errln("FAIL: charAt(%d) = %X => indexOf() => %d",
+ i, c, set.indexOf(c));
+ }
+ }
+ UChar32 c = set.charAt(set.size());
+ if (c != -1) {
+ errln("FAIL: charAt(<out of range>) = %X", c);
+ }
+ int32_t j = set.indexOf((UChar32)0x71/*'q'*/);
+ if (j != -1) {
+ errln((UnicodeString)"FAIL: indexOf('q') = " + j);
+ }
+}
+
+/**
+ * Test closure API.
+ */
+void UnicodeSetTest::TestCloseOver() {
+ UErrorCode ec = U_ZERO_ERROR;
+
+ char CASE[] = {(char)USET_CASE_INSENSITIVE};
+ char CASE_MAPPINGS[] = {(char)USET_ADD_CASE_MAPPINGS};
+ const char* DATA[] = {
+ // selector, input, output
+ CASE,
+ "[aq\\u00DF{Bc}{bC}{Fi}]",
+ "[aAqQ\\u00DF\\uFB01{ss}{bc}{fi}]",
+
+ CASE,
+ "[\\u01F1]", // 'DZ'
+ "[\\u01F1\\u01F2\\u01F3]",
+
+ CASE,
+ "[\\u1FB4]",
+ "[\\u1FB4{\\u03AC\\u03B9}]",
+
+ CASE,
+ "[{F\\uFB01}]",
+ "[\\uFB03{ffi}]",
+
+ CASE, // make sure binary search finds limits
+ "[a\\uFF3A]",
+ "[aA\\uFF3A\\uFF5A]",
+
+ CASE,
+ "[a-z]","[A-Za-z\\u017F\\u212A]",
+ CASE,
+ "[abc]","[A-Ca-c]",
+ CASE,
+ "[ABC]","[A-Ca-c]",
+
+ CASE, "[i]", "[iI]",
+
+ CASE, "[\\u0130]", "[\\u0130{i\\u0307}]", // dotted I
+ CASE, "[{i\\u0307}]", "[\\u0130{i\\u0307}]", // i with dot
+
+ CASE, "[\\u0131]", "[\\u0131]", // dotless i
+
+ CASE, "[\\u0390]", "[\\u0390\\u1FD3{\\u03B9\\u0308\\u0301}]",
+
+ CASE, "[\\u03c2]", "[\\u03a3\\u03c2\\u03c3]", // sigmas
+
+ CASE, "[\\u03f2]", "[\\u03f2\\u03f9]", // lunate sigmas
+
+ CASE, "[\\u03f7]", "[\\u03f7\\u03f8]",
+
+ CASE, "[\\u1fe3]", "[\\u03b0\\u1fe3{\\u03c5\\u0308\\u0301}]",
+
+ CASE, "[\\ufb05]", "[\\ufb05\\ufb06{st}]",
+ CASE, "[{st}]", "[\\ufb05\\ufb06{st}]",
+
+ CASE, "[\\U0001044F]", "[\\U00010427\\U0001044F]",
+
+ CASE, "[{a\\u02BE}]", "[\\u1E9A{a\\u02BE}]", // first in sorted table
+
+ CASE, "[{\\u1f7c\\u03b9}]", "[\\u1ff2{\\u1f7c\\u03b9}]", // last in sorted table
+
+ CASE_MAPPINGS,
+ "[aq\\u00DF{Bc}{bC}{Fi}]",
+ "[aAqQ\\u00DF{ss}{Ss}{SS}{Bc}{BC}{bC}{bc}{FI}{Fi}{fi}]",
+
+ CASE_MAPPINGS,
+ "[\\u01F1]", // 'DZ'
+ "[\\u01F1\\u01F2\\u01F3]",
+
+ CASE_MAPPINGS,
+ "[a-z]",
+ "[A-Za-z]",
+
+ NULL
+ };
+
+ UnicodeSet s;
+ UnicodeSet t;
+ UnicodeString buf;
+ for (int32_t i=0; DATA[i]!=NULL; i+=3) {
+ int32_t selector = DATA[i][0];
+ UnicodeString pat(DATA[i+1]);
+ UnicodeString exp(DATA[i+2]);
+ s.applyPattern(pat, ec);
+ s.closeOver(selector);
+ t.applyPattern(exp, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: applyPattern failed");
+ continue;
+ }
+ if (s == t) {
+ logln((UnicodeString)"Ok: " + pat + ".closeOver(" + selector + ") => " + exp);
+ } else {
+ errln((UnicodeString)"FAIL: " + pat + ".closeOver(" + selector + ") => " +
+ s.toPattern(buf, TRUE) + ", expected " + exp);
+ }
+ }
+
+#if 0
+ /*
+ * Unused test code.
+ * This was used to compare the old implementation (using USET_CASE)
+ * with the new one (using 0x100 temporarily)
+ * while transitioning from hardcoded case closure tables in uniset.cpp
+ * (moved to uniset_props.cpp) to building the data by gencase into ucase.icu.
+ * and using ucase.c functions for closure.
+ * See Jitterbug 3432 RFE: Move uniset.cpp data to a data file
+ *
+ * Note: The old and new implementation never fully matched because
+ * the old implementation turned out to not map U+0130 and U+0131 correctly
+ * (dotted I and dotless i) and because the old implementation's data tables
+ * were outdated compared to Unicode 4.0.1 at the time of the change to the
+ * new implementation. (So sigmas and some other characters were not handled
+ * according to the newer Unicode version.)
+ */
+ UnicodeSet sens("[:case_sensitive:]", ec), sens2, s2;
+ UnicodeSetIterator si(sens);
+ UnicodeString str, buf2;
+ const UnicodeString *pStr;
+ UChar32 c;
+ while(si.next()) {
+ if(!si.isString()) {
+ c=si.getCodepoint();
+ s.clear();
+ s.add(c);
+
+ str.setTo(c);
+ str.foldCase();
+ sens2.add(str);
+
+ t=s;
+ s.closeOver(USET_CASE);
+ t.closeOver(0x100);
+ if(s!=t) {
+ errln("FAIL: closeOver(U+%04x) differs: ", c);
+ errln((UnicodeString)"old "+s.toPattern(buf, TRUE)+" new: "+t.toPattern(buf2, TRUE));
+ }
+ }
+ }
+ // remove all code points
+ // should contain all full case folding mapping strings
+ sens2.remove(0, 0x10ffff);
+ si.reset(sens2);
+ while(si.next()) {
+ if(si.isString()) {
+ pStr=&si.getString();
+ s.clear();
+ s.add(*pStr);
+ t=s2=s;
+ s.closeOver(USET_CASE);
+ t.closeOver(0x100);
+ if(s!=t) {
+ errln((UnicodeString)"FAIL: closeOver("+s2.toPattern(buf, TRUE)+") differs: ");
+ errln((UnicodeString)"old "+s.toPattern(buf, TRUE)+" new: "+t.toPattern(buf2, TRUE));
+ }
+ }
+ }
+#endif
+
+ // Test the pattern API
+ s.applyPattern("[abc]", USET_CASE_INSENSITIVE, NULL, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: applyPattern failed");
+ } else {
+ expectContainment(s, "abcABC", "defDEF");
+ }
+ UnicodeSet v("[^abc]", USET_CASE_INSENSITIVE, NULL, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: constructor failed");
+ } else {
+ expectContainment(v, "defDEF", "abcABC");
+ }
+ UnicodeSet cm("[abck]", USET_ADD_CASE_MAPPINGS, NULL, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: construct w/case mappings failed");
+ } else {
+ expectContainment(cm, "abckABCK", CharsToUnicodeString("defDEF\\u212A"));
+ }
+}
+
+void UnicodeSetTest::TestEscapePattern() {
+ const char pattern[] =
+ "[\\uFEFF \\u200A-\\u200E \\U0001D173-\\U0001D17A \\U000F0000-\\U000FFFFD ]";
+ const char exp[] =
+ "[\\u200A-\\u200E\\uFEFF\\U0001D173-\\U0001D17A\\U000F0000-\\U000FFFFD]";
+ // We test this with two passes; in the second pass we
+ // pre-unescape the pattern. Since U+200E is rule whitespace,
+ // this fails -- which is what we expect.
+ for (int32_t pass=1; pass<=2; ++pass) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeString pat(pattern);
+ if (pass==2) {
+ pat = pat.unescape();
+ }
+ // Pattern is only good for pass 1
+ UBool isPatternValid = (pass==1);
+
+ UnicodeSet set(pat, ec);
+ if (U_SUCCESS(ec) != isPatternValid){
+ errln((UnicodeString)"FAIL: applyPattern(" +
+ escape(pat) + ") => " +
+ u_errorName(ec));
+ continue;
+ }
+ if (U_FAILURE(ec)) {
+ continue;
+ }
+ if (set.contains((UChar)0x0644)){
+ errln((UnicodeString)"FAIL: " + escape(pat) + " contains(U+0664)");
+ }
+
+ UnicodeString newpat;
+ set.toPattern(newpat, TRUE);
+ if (newpat == exp) {
+ logln(escape(pat) + " => " + newpat);
+ } else {
+ errln((UnicodeString)"FAIL: " + escape(pat) + " => " + newpat);
+ }
+
+ for (int32_t i=0; i<set.getRangeCount(); ++i) {
+ UnicodeString str("Range ");
+ str.append((UChar)(0x30 + i))
+ .append(": ")
+ .append((UChar32)set.getRangeStart(i))
+ .append(" - ")
+ .append((UChar32)set.getRangeEnd(i));
+ str = str + " (" + set.getRangeStart(i) + " - " +
+ set.getRangeEnd(i) + ")";
+ if (set.getRangeStart(i) < 0) {
+ errln((UnicodeString)"FAIL: " + escape(str));
+ } else {
+ logln(escape(str));
+ }
+ }
+ }
+}
+
+void UnicodeSetTest::expectRange(const UnicodeString& label,
+ const UnicodeSet& set,
+ UChar32 start, UChar32 end) {
+ UnicodeSet exp(start, end);
+ UnicodeString pat;
+ if (set == exp) {
+ logln(label + " => " + set.toPattern(pat, TRUE));
+ } else {
+ UnicodeString xpat;
+ errln((UnicodeString)"FAIL: " + label + " => " +
+ set.toPattern(pat, TRUE) +
+ ", expected " + exp.toPattern(xpat, TRUE));
+ }
+}
+
+void UnicodeSetTest::TestInvalidCodePoint() {
+
+ const UChar32 DATA[] = {
+ // Test range Expected range
+ 0, 0x10FFFF, 0, 0x10FFFF,
+ (UChar32)-1, 8, 0, 8,
+ 8, 0x110000, 8, 0x10FFFF
+ };
+ const int32_t DATA_LENGTH = sizeof(DATA)/sizeof(DATA[0]);
+
+ UnicodeString pat;
+ int32_t i;
+
+ for (i=0; i<DATA_LENGTH; i+=4) {
+ UChar32 start = DATA[i];
+ UChar32 end = DATA[i+1];
+ UChar32 xstart = DATA[i+2];
+ UChar32 xend = DATA[i+3];
+
+ // Try various API using the test code points
+
+ UnicodeSet set(start, end);
+ expectRange((UnicodeString)"ct(" + start + "," + end + ")",
+ set, xstart, xend);
+
+ set.clear();
+ set.set(start, end);
+ expectRange((UnicodeString)"set(" + start + "," + end + ")",
+ set, xstart, xend);
+
+ UBool b = set.contains(start);
+ b = set.contains(start, end);
+ b = set.containsNone(start, end);
+ b = set.containsSome(start, end);
+
+ /*int32_t index = set.indexOf(start);*/
+
+ set.clear();
+ set.add(start);
+ set.add(start, end);
+ expectRange((UnicodeString)"add(" + start + "," + end + ")",
+ set, xstart, xend);
+
+ set.set(0, 0x10FFFF);
+ set.retain(start, end);
+ expectRange((UnicodeString)"retain(" + start + "," + end + ")",
+ set, xstart, xend);
+ set.retain(start);
+
+ set.set(0, 0x10FFFF);
+ set.remove(start);
+ set.remove(start, end);
+ set.complement();
+ expectRange((UnicodeString)"!remove(" + start + "," + end + ")",
+ set, xstart, xend);
+
+ set.set(0, 0x10FFFF);
+ set.complement(start, end);
+ set.complement();
+ expectRange((UnicodeString)"!complement(" + start + "," + end + ")",
+ set, xstart, xend);
+ set.complement(start);
+ }
+
+ const UChar32 DATA2[] = {
+ 0,
+ 0x10FFFF,
+ (UChar32)-1,
+ 0x110000
+ };
+ const int32_t DATA2_LENGTH = sizeof(DATA2)/sizeof(DATA2[0]);
+
+ for (i=0; i<DATA2_LENGTH; ++i) {
+ UChar32 c = DATA2[i], end = 0x10FFFF;
+ UBool valid = (c >= 0 && c <= 0x10FFFF);
+
+ UnicodeSet set(0, 0x10FFFF);
+
+ // For single-codepoint contains, invalid codepoints are NOT contained
+ UBool b = set.contains(c);
+ if (b == valid) {
+ logln((UnicodeString)"[\\u0000-\\U0010FFFF].contains(" + c +
+ ") = " + b);
+ } else {
+ errln((UnicodeString)"FAIL: [\\u0000-\\U0010FFFF].contains(" + c +
+ ") = " + b);
+ }
+
+ // For codepoint range contains, containsNone, and containsSome,
+ // invalid or empty (start > end) ranges have UNDEFINED behavior.
+ b = set.contains(c, end);
+ logln((UnicodeString)"* [\\u0000-\\U0010FFFF].contains(" + c +
+ "," + end + ") = " + b);
+
+ b = set.containsNone(c, end);
+ logln((UnicodeString)"* [\\u0000-\\U0010FFFF].containsNone(" + c +
+ "," + end + ") = " + b);
+
+ b = set.containsSome(c, end);
+ logln((UnicodeString)"* [\\u0000-\\U0010FFFF].containsSome(" + c +
+ "," + end + ") = " + b);
+
+ int32_t index = set.indexOf(c);
+ if ((index >= 0) == valid) {
+ logln((UnicodeString)"[\\u0000-\\U0010FFFF].indexOf(" + c +
+ ") = " + index);
+ } else {
+ errln((UnicodeString)"FAIL: [\\u0000-\\U0010FFFF].indexOf(" + c +
+ ") = " + index);
+ }
+ }
+}
+
+// Used by TestSymbolTable
+class TokenSymbolTable : public SymbolTable {
+public:
+ Hashtable contents;
+
+ TokenSymbolTable(UErrorCode& ec) : contents(FALSE, ec) {
+ contents.setValueDeleter(uhash_deleteUnicodeString);
+ }
+
+ ~TokenSymbolTable() {}
+
+ /**
+ * (Non-SymbolTable API) Add the given variable and value to
+ * the table. Variable should NOT contain leading '$'.
+ */
+ void add(const UnicodeString& var, const UnicodeString& value,
+ UErrorCode& ec) {
+ if (U_SUCCESS(ec)) {
+ contents.put(var, new UnicodeString(value), ec);
+ }
+ }
+
+ /**
+ * SymbolTable API
+ */
+ virtual const UnicodeString* lookup(const UnicodeString& s) const {
+ return (const UnicodeString*) contents.get(s);
+ }
+
+ /**
+ * SymbolTable API
+ */
+ virtual const UnicodeFunctor* lookupMatcher(UChar32 /*ch*/) const {
+ return NULL;
+ }
+
+ /**
+ * SymbolTable API
+ */
+ virtual UnicodeString parseReference(const UnicodeString& text,
+ ParsePosition& pos, int32_t limit) const {
+ int32_t start = pos.getIndex();
+ int32_t i = start;
+ UnicodeString result;
+ while (i < limit) {
+ UChar c = text.charAt(i);
+ if ((i==start && !u_isIDStart(c)) || !u_isIDPart(c)) {
+ break;
+ }
+ ++i;
+ }
+ if (i == start) { // No valid name chars
+ return result; // Indicate failure with empty string
+ }
+ pos.setIndex(i);
+ text.extractBetween(start, i, result);
+ return result;
+ }
+};
+
+void UnicodeSetTest::TestSymbolTable() {
+ // Multiple test cases can be set up here. Each test case
+ // is terminated by null:
+ // var, value, var, value,..., input pat., exp. output pat., null
+ const char* DATA[] = {
+ "us", "a-z", "[0-1$us]", "[0-1a-z]", NULL,
+ "us", "[a-z]", "[0-1$us]", "[0-1[a-z]]", NULL,
+ "us", "\\[a\\-z\\]", "[0-1$us]", "[-01\\[\\]az]", NULL,
+ NULL
+ };
+
+ for (int32_t i=0; DATA[i]!=NULL; ++i) {
+ UErrorCode ec = U_ZERO_ERROR;
+ TokenSymbolTable sym(ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: couldn't construct TokenSymbolTable");
+ continue;
+ }
+
+ // Set up variables
+ while (DATA[i+2] != NULL) {
+ sym.add(DATA[i], DATA[i+1], ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: couldn't add to TokenSymbolTable");
+ continue;
+ }
+ i += 2;
+ }
+
+ // Input pattern and expected output pattern
+ UnicodeString inpat = DATA[i], exppat = DATA[i+1];
+ i += 2;
+
+ ParsePosition pos(0);
+ UnicodeSet us(inpat, pos, USET_IGNORE_SPACE, &sym, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: couldn't construct UnicodeSet");
+ continue;
+ }
+
+ // results
+ if (pos.getIndex() != inpat.length()) {
+ errln((UnicodeString)"Failed to read to end of string \""
+ + inpat + "\": read to "
+ + pos.getIndex() + ", length is "
+ + inpat.length());
+ }
+
+ UnicodeSet us2(exppat, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: couldn't construct expected UnicodeSet");
+ continue;
+ }
+
+ UnicodeString a, b;
+ if (us != us2) {
+ errln((UnicodeString)"Failed, got " + us.toPattern(a, TRUE) +
+ ", expected " + us2.toPattern(b, TRUE));
+ } else {
+ logln((UnicodeString)"Ok, got " + us.toPattern(a, TRUE));
+ }
+ }
+}
+
+void UnicodeSetTest::TestSurrogate() {
+ const char* DATA[] = {
+ // These should all behave identically
+ "[abc\\uD800\\uDC00]",
+ // "[abc\uD800\uDC00]", // Can't do this on C -- only Java
+ "[abc\\U00010000]",
+ 0
+ };
+ for (int i=0; DATA[i] != 0; ++i) {
+ UErrorCode ec = U_ZERO_ERROR;
+ logln((UnicodeString)"Test pattern " + i + " :" + DATA[i]);
+ UnicodeSet set(DATA[i], ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: UnicodeSet constructor");
+ continue;
+ }
+ expectContainment(set,
+ CharsToUnicodeString("abc\\U00010000"),
+ CharsToUnicodeString("\\uD800;\\uDC00")); // split apart surrogate-pair
+ if (set.size() != 4) {
+ errln((UnicodeString)"FAIL: " + DATA[i] + ".size() == " +
+ set.size() + ", expected 4");
+ }
+ }
+}
+
+void UnicodeSetTest::TestExhaustive() {
+ // exhaustive tests. Simulate UnicodeSets with integers.
+ // That gives us very solid tests (except for large memory tests).
+
+ int32_t limit = 128;
+
+ UnicodeSet x, y, z, aa;
+
+ for (int32_t i = 0; i < limit; ++i) {
+ bitsToSet(i, x);
+ logln((UnicodeString)"Testing " + i + ", " + x);
+ _testComplement(i, x, y);
+
+ // AS LONG AS WE ARE HERE, check roundtrip
+ checkRoundTrip(bitsToSet(i, aa));
+
+ for (int32_t j = 0; j < limit; ++j) {
+ _testAdd(i,j, x,y,z);
+ _testXor(i,j, x,y,z);
+ _testRetain(i,j, x,y,z);
+ _testRemove(i,j, x,y,z);
+ }
+ }
+}
+
+void UnicodeSetTest::_testComplement(int32_t a, UnicodeSet& x, UnicodeSet& z) {
+ bitsToSet(a, x);
+ z = x;
+ z.complement();
+ int32_t c = setToBits(z);
+ if (c != (~a)) {
+ errln((UnicodeString)"FAILED: add: ~" + x + " != " + z);
+ errln((UnicodeString)"FAILED: add: ~" + a + " != " + c);
+ }
+ checkCanonicalRep(z, (UnicodeString)"complement " + a);
+}
+
+void UnicodeSetTest::_testAdd(int32_t a, int32_t b, UnicodeSet& x, UnicodeSet& y, UnicodeSet& z) {
+ bitsToSet(a, x);
+ bitsToSet(b, y);
+ z = x;
+ z.addAll(y);
+ int32_t c = setToBits(z);
+ if (c != (a | b)) {
+ errln((UnicodeString)"FAILED: add: " + x + " | " + y + " != " + z);
+ errln((UnicodeString)"FAILED: add: " + a + " | " + b + " != " + c);
+ }
+ checkCanonicalRep(z, (UnicodeString)"add " + a + "," + b);
+}
+
+void UnicodeSetTest::_testRetain(int32_t a, int32_t b, UnicodeSet& x, UnicodeSet& y, UnicodeSet& z) {
+ bitsToSet(a, x);
+ bitsToSet(b, y);
+ z = x;
+ z.retainAll(y);
+ int32_t c = setToBits(z);
+ if (c != (a & b)) {
+ errln((UnicodeString)"FAILED: retain: " + x + " & " + y + " != " + z);
+ errln((UnicodeString)"FAILED: retain: " + a + " & " + b + " != " + c);
+ }
+ checkCanonicalRep(z, (UnicodeString)"retain " + a + "," + b);
+}
+
+void UnicodeSetTest::_testRemove(int32_t a, int32_t b, UnicodeSet& x, UnicodeSet& y, UnicodeSet& z) {
+ bitsToSet(a, x);
+ bitsToSet(b, y);
+ z = x;
+ z.removeAll(y);
+ int32_t c = setToBits(z);
+ if (c != (a &~ b)) {
+ errln((UnicodeString)"FAILED: remove: " + x + " &~ " + y + " != " + z);
+ errln((UnicodeString)"FAILED: remove: " + a + " &~ " + b + " != " + c);
+ }
+ checkCanonicalRep(z, (UnicodeString)"remove " + a + "," + b);
+}
+
+void UnicodeSetTest::_testXor(int32_t a, int32_t b, UnicodeSet& x, UnicodeSet& y, UnicodeSet& z) {
+ bitsToSet(a, x);
+ bitsToSet(b, y);
+ z = x;
+ z.complementAll(y);
+ int32_t c = setToBits(z);
+ if (c != (a ^ b)) {
+ errln((UnicodeString)"FAILED: complement: " + x + " ^ " + y + " != " + z);
+ errln((UnicodeString)"FAILED: complement: " + a + " ^ " + b + " != " + c);
+ }
+ checkCanonicalRep(z, (UnicodeString)"complement " + a + "," + b);
+}
+
+/**
+ * Check that ranges are monotonically increasing and non-
+ * overlapping.
+ */
+void UnicodeSetTest::checkCanonicalRep(const UnicodeSet& set, const UnicodeString& msg) {
+ int32_t n = set.getRangeCount();
+ if (n < 0) {
+ errln((UnicodeString)"FAIL result of " + msg +
+ ": range count should be >= 0 but is " +
+ n /*+ " for " + set.toPattern())*/);
+ return;
+ }
+ UChar32 last = 0;
+ for (int32_t i=0; i<n; ++i) {
+ UChar32 start = set.getRangeStart(i);
+ UChar32 end = set.getRangeEnd(i);
+ if (start > end) {
+ errln((UnicodeString)"FAIL result of " + msg +
+ ": range " + (i+1) +
+ " start > end: " + (int)start + ", " + (int)end +
+ " for " + set);
+ }
+ if (i > 0 && start <= last) {
+ errln((UnicodeString)"FAIL result of " + msg +
+ ": range " + (i+1) +
+ " overlaps previous range: " + (int)start + ", " + (int)end +
+ " for " + set);
+ }
+ last = end;
+ }
+}
+
+/**
+ * Convert a bitmask to a UnicodeSet.
+ */
+UnicodeSet& UnicodeSetTest::bitsToSet(int32_t a, UnicodeSet& result) {
+ result.clear();
+ for (UChar32 i = 0; i < 32; ++i) {
+ if ((a & (1<<i)) != 0) {
+ result.add(i);
+ }
+ }
+ return result;
+}
+
+/**
+ * Convert a UnicodeSet to a bitmask. Only the characters
+ * U+0000 to U+0020 are represented in the bitmask.
+ */
+int32_t UnicodeSetTest::setToBits(const UnicodeSet& x) {
+ int32_t result = 0;
+ for (int32_t i = 0; i < 32; ++i) {
+ if (x.contains((UChar32)i)) {
+ result |= (1<<i);
+ }
+ }
+ return result;
+}
+
+/**
+ * Return the representation of an inversion list based UnicodeSet
+ * as a pairs list. Ranges are listed in ascending Unicode order.
+ * For example, the set [a-zA-M3] is represented as "33AMaz".
+ */
+UnicodeString UnicodeSetTest::getPairs(const UnicodeSet& set) {
+ UnicodeString pairs;
+ for (int32_t i=0; i<set.getRangeCount(); ++i) {
+ UChar32 start = set.getRangeStart(i);
+ UChar32 end = set.getRangeEnd(i);
+ if (end > 0xFFFF) {
+ end = 0xFFFF;
+ i = set.getRangeCount(); // Should be unnecessary
+ }
+ pairs.append((UChar)start).append((UChar)end);
+ }
+ return pairs;
+}
+
+/**
+ * Basic consistency check for a few items.
+ * That the iterator works, and that we can create a pattern and
+ * get the same thing back
+ */
+void UnicodeSetTest::checkRoundTrip(const UnicodeSet& s) {
+ UErrorCode ec = U_ZERO_ERROR;
+
+ UnicodeSet t(s);
+ checkEqual(s, t, "copy ct");
+
+ t = s;
+ checkEqual(s, t, "operator=");
+
+ copyWithIterator(t, s, FALSE);
+ checkEqual(s, t, "iterator roundtrip");
+
+ copyWithIterator(t, s, TRUE); // try range
+ checkEqual(s, t, "iterator roundtrip");
+
+ UnicodeString pat; s.toPattern(pat, FALSE);
+ t.applyPattern(pat, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: applyPattern");
+ return;
+ } else {
+ checkEqual(s, t, "toPattern(false)");
+ }
+
+ s.toPattern(pat, TRUE);
+ t.applyPattern(pat, ec);
+ if (U_FAILURE(ec)) {
+ errln("FAIL: applyPattern");
+ return;
+ } else {
+ checkEqual(s, t, "toPattern(true)");
+ }
+}
+
+void UnicodeSetTest::copyWithIterator(UnicodeSet& t, const UnicodeSet& s, UBool withRange) {
+ t.clear();
+ UnicodeSetIterator it(s);
+ if (withRange) {
+ while (it.nextRange()) {
+ if (it.isString()) {
+ t.add(it.getString());
+ } else {
+ t.add(it.getCodepoint(), it.getCodepointEnd());
+ }
+ }
+ } else {
+ while (it.next()) {
+ if (it.isString()) {
+ t.add(it.getString());
+ } else {
+ t.add(it.getCodepoint());
+ }
+ }
+ }
+}
+
+UBool UnicodeSetTest::checkEqual(const UnicodeSet& s, const UnicodeSet& t, const char* message) {
+ UnicodeString source; s.toPattern(source, TRUE);
+ UnicodeString result; t.toPattern(result, TRUE);
+ if (s != t) {
+ errln((UnicodeString)"FAIL: " + message
+ + "; source = " + source
+ + "; result = " + result
+ );
+ return FALSE;
+ } else {
+ logln((UnicodeString)"Ok: " + message
+ + "; source = " + source
+ + "; result = " + result
+ );
+ }
+ return TRUE;
+}
+
+void
+UnicodeSetTest::expectContainment(const UnicodeString& pat,
+ const UnicodeString& charsIn,
+ const UnicodeString& charsOut) {
+ UErrorCode ec = U_ZERO_ERROR;
+ UnicodeSet set(pat, ec);
+ if (U_FAILURE(ec)) {
+ errln((UnicodeString)"FAIL: pattern \"" +
+ pat + "\" => " + u_errorName(ec));
+ return;
+ }
+ expectContainment(set, pat, charsIn, charsOut);
+}
+
+void
+UnicodeSetTest::expectContainment(const UnicodeSet& set,
+ const UnicodeString& charsIn,
+ const UnicodeString& charsOut) {
+ UnicodeString pat;
+ set.toPattern(pat);
+ expectContainment(set, pat, charsIn, charsOut);
+}
+
+void
+UnicodeSetTest::expectContainment(const UnicodeSet& set,
+ const UnicodeString& setName,
+ const UnicodeString& charsIn,
+ const UnicodeString& charsOut) {
+ UnicodeString bad;
+ UChar32 c;
+ int32_t i;
+
+ for (i=0; i<charsIn.length(); i+=U16_LENGTH(c)) {
+ c = charsIn.char32At(i);
+ if (!set.contains(c)) {
+ bad.append(c);
+ }
+ }
+ if (bad.length() > 0) {
+ errln((UnicodeString)"Fail: set " + setName + " does not contain " + prettify(bad) +
+ ", expected containment of " + prettify(charsIn));
+ } else {
+ logln((UnicodeString)"Ok: set " + setName + " contains " + prettify(charsIn));
+ }
+
+ bad.truncate(0);
+ for (i=0; i<charsOut.length(); i+=U16_LENGTH(c)) {
+ c = charsOut.char32At(i);
+ if (set.contains(c)) {
+ bad.append(c);
+ }
+ }
+ if (bad.length() > 0) {
+ errln((UnicodeString)"Fail: set " + setName + " contains " + prettify(bad) +
+ ", expected non-containment of " + prettify(charsOut));
+ } else {
+ logln((UnicodeString)"Ok: set " + setName + " does not contain " + prettify(charsOut));
+ }
+}
+
+void
+UnicodeSetTest::expectPattern(UnicodeSet& set,
+ const UnicodeString& pattern,
+ const UnicodeString& expectedPairs){
+ UErrorCode status = U_ZERO_ERROR;
+ set.applyPattern(pattern, status);
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: applyPattern(\"") + pattern +
+ "\") failed");
+ return;
+ } else {
+ if (getPairs(set) != expectedPairs ) {
+ errln(UnicodeString("FAIL: applyPattern(\"") + pattern +
+ "\") => pairs \"" +
+ escape(getPairs(set)) + "\", expected \"" +
+ escape(expectedPairs) + "\"");
+ } else {
+ logln(UnicodeString("Ok: applyPattern(\"") + pattern +
+ "\") => pairs \"" +
+ escape(getPairs(set)) + "\"");
+ }
+ }
+ // the result of calling set.toPattern(), which is the string representation of
+ // this set(set), is passed to a UnicodeSet constructor, and tested that it
+ // will produce another set that is equal to this one.
+ UnicodeString temppattern;
+ set.toPattern(temppattern);
+ UnicodeSet *tempset=new UnicodeSet(temppattern, status);
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: applyPattern(\""+ pattern + "\").toPattern() => " + temppattern + " => invalid pattern"));
+ return;
+ }
+ if(*tempset != set || getPairs(*tempset) != getPairs(set)){
+ errln(UnicodeString("FAIL: applyPattern(\""+ pattern + "\").toPattern() => " + temppattern + " => pairs \""+ escape(getPairs(*tempset)) + "\", expected pairs \"" +
+ escape(getPairs(set)) + "\""));
+ } else{
+ logln(UnicodeString("Ok: applyPattern(\""+ pattern + "\").toPattern() => " + temppattern + " => pairs \"" + escape(getPairs(*tempset)) + "\""));
+ }
+
+ delete tempset;
+
+}
+
+void
+UnicodeSetTest::expectPairs(const UnicodeSet& set, const UnicodeString& expectedPairs) {
+ if (getPairs(set) != expectedPairs) {
+ errln(UnicodeString("FAIL: Expected pair list \"") +
+ escape(expectedPairs) + "\", got \"" +
+ escape(getPairs(set)) + "\"");
+ }
+}
+
+void UnicodeSetTest::expectToPattern(const UnicodeSet& set,
+ const UnicodeString& expPat,
+ const char** expStrings) {
+ UnicodeString pat;
+ set.toPattern(pat, TRUE);
+ if (pat == expPat) {
+ logln((UnicodeString)"Ok: toPattern() => \"" + pat + "\"");
+ } else {
+ errln((UnicodeString)"FAIL: toPattern() => \"" + pat + "\", expected \"" + expPat + "\"");
+ return;
+ }
+ if (expStrings == NULL) {
+ return;
+ }
+ UBool in = TRUE;
+ for (int32_t i=0; expStrings[i] != NULL; ++i) {
+ if (expStrings[i] == NOT) { // sic; pointer comparison
+ in = FALSE;
+ continue;
+ }
+ UnicodeString s = CharsToUnicodeString(expStrings[i]);
+ UBool contained = set.contains(s);
+ if (contained == in) {
+ logln((UnicodeString)"Ok: " + expPat +
+ (contained ? " contains {" : " does not contain {") +
+ escape(expStrings[i]) + "}");
+ } else {
+ errln((UnicodeString)"FAIL: " + expPat +
+ (contained ? " contains {" : " does not contain {") +
+ escape(expStrings[i]) + "}");
+ }
+ }
+}
+
+static UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
+
+void
+UnicodeSetTest::doAssert(UBool condition, const char *message)
+{
+ if (!condition) {
+ errln(UnicodeString("ERROR : ") + message);
+ }
+}
+
+UnicodeString
+UnicodeSetTest::escape(const UnicodeString& s) {
+ UnicodeString buf;
+ for (int32_t i=0; i<s.length(); )
+ {
+ UChar32 c = s.char32At(i);
+ if (0x0020 <= c && c <= 0x007F) {
+ buf += c;
+ } else {
+ if (c <= 0xFFFF) {
+ buf += (UChar)0x5c; buf += (UChar)0x75;
+ } else {
+ buf += (UChar)0x5c; buf += (UChar)0x55;
+ buf += toHexString((c & 0xF0000000) >> 28);
+ buf += toHexString((c & 0x0F000000) >> 24);
+ buf += toHexString((c & 0x00F00000) >> 20);
+ buf += toHexString((c & 0x000F0000) >> 16);
+ }
+ buf += toHexString((c & 0xF000) >> 12);
+ buf += toHexString((c & 0x0F00) >> 8);
+ buf += toHexString((c & 0x00F0) >> 4);
+ buf += toHexString(c & 0x000F);
+ }
+ i += U16_LENGTH(c);
+ }
+ return buf;
+}
+
+void UnicodeSetTest::TestFreezable() {
+ UErrorCode errorCode=U_ZERO_ERROR;
+ UnicodeString idPattern=UNICODE_STRING("[:ID_Continue:]", 15);
+ UnicodeSet idSet(idPattern, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("FAIL: unable to create UnicodeSet([:ID_Continue:]) - %s", u_errorName(errorCode));
+ return;
+ }
+
+ UnicodeString wsPattern=UNICODE_STRING("[:White_Space:]", 15);
+ UnicodeSet wsSet(wsPattern, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("FAIL: unable to create UnicodeSet([:White_Space:]) - %s", u_errorName(errorCode));
+ return;
+ }
+
+ idSet.add(idPattern);
+ UnicodeSet frozen(idSet);
+ frozen.freeze();
+
+ if(idSet.isFrozen() || !frozen.isFrozen()) {
+ errln("FAIL: isFrozen() is wrong");
+ }
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: a copy-constructed frozen set differs from its original");
+ }
+
+ frozen=wsSet;
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: a frozen set was modified by operator=");
+ }
+
+ UnicodeSet frozen2(frozen);
+ if(frozen2!=frozen || frozen2!=idSet) {
+ errln("FAIL: a copied frozen set differs from its frozen original");
+ }
+ if(!frozen2.isFrozen()) {
+ errln("FAIL: copy-constructing a frozen set results in a thawed one");
+ }
+ UnicodeSet frozen3(5, 55); // Set to some values to really test assignment below, not copy construction.
+ if(frozen3.contains(0, 4) || !frozen3.contains(5, 55) || frozen3.contains(56, 0x10ffff)) {
+ errln("FAIL: UnicodeSet(5, 55) failed");
+ }
+ frozen3=frozen;
+ if(!frozen3.isFrozen()) {
+ errln("FAIL: copying a frozen set results in a thawed one");
+ }
+
+ UnicodeSet *cloned=(UnicodeSet *)frozen.clone();
+ if(!cloned->isFrozen() || *cloned!=frozen || cloned->containsSome(0xd802, 0xd805)) {
+ errln("FAIL: clone() failed");
+ }
+ cloned->add(0xd802, 0xd805);
+ if(cloned->containsSome(0xd802, 0xd805)) {
+ errln("FAIL: unable to modify clone");
+ }
+ delete cloned;
+
+ UnicodeSet *thawed=(UnicodeSet *)frozen.cloneAsThawed();
+ if(thawed->isFrozen() || *thawed!=frozen || thawed->containsSome(0xd802, 0xd805)) {
+ errln("FAIL: cloneAsThawed() failed");
+ }
+ thawed->add(0xd802, 0xd805);
+ if(!thawed->contains(0xd802, 0xd805)) {
+ errln("FAIL: unable to modify thawed clone");
+ }
+ delete thawed;
+
+ frozen.set(5, 55);
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: UnicodeSet::set() modified a frozen set");
+ }
+
+ frozen.clear();
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: UnicodeSet::clear() modified a frozen set");
+ }
+
+ frozen.closeOver(USET_CASE_INSENSITIVE);
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: UnicodeSet::closeOver() modified a frozen set");
+ }
+
+ frozen.compact();
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: UnicodeSet::compact() modified a frozen set");
+ }
+
+ ParsePosition pos;
+ frozen.
+ applyPattern(wsPattern, errorCode).
+ applyPattern(wsPattern, USET_IGNORE_SPACE, NULL, errorCode).
+ applyPattern(wsPattern, pos, USET_IGNORE_SPACE, NULL, errorCode).
+ applyIntPropertyValue(UCHAR_CANONICAL_COMBINING_CLASS, 230, errorCode).
+ applyPropertyAlias(UNICODE_STRING_SIMPLE("Assigned"), UnicodeString(), errorCode);
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: UnicodeSet::applyXYZ() modified a frozen set");
+ }
+
+ frozen.
+ add(0xd800).
+ add(0xd802, 0xd805).
+ add(wsPattern).
+ addAll(idPattern).
+ addAll(wsSet);
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: UnicodeSet::addXYZ() modified a frozen set");
+ }
+
+ frozen.
+ retain(0x62).
+ retain(0x64, 0x69).
+ retainAll(wsPattern).
+ retainAll(wsSet);
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: UnicodeSet::retainXYZ() modified a frozen set");
+ }
+
+ frozen.
+ remove(0x62).
+ remove(0x64, 0x69).
+ remove(idPattern).
+ removeAll(idPattern).
+ removeAll(idSet);
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: UnicodeSet::removeXYZ() modified a frozen set");
+ }
+
+ frozen.
+ complement().
+ complement(0x62).
+ complement(0x64, 0x69).
+ complement(idPattern).
+ complementAll(idPattern).
+ complementAll(idSet);
+ if(frozen!=idSet || !(frozen==idSet)) {
+ errln("FAIL: UnicodeSet::complementXYZ() modified a frozen set");
+ }
+}
+
+// Test span() etc. -------------------------------------------------------- ***
+
+// Append the UTF-8 version of the string to t and return the appended UTF-8 length.
+static int32_t
+appendUTF8(const UChar *s, int32_t length, char *t, int32_t capacity) {
+ UErrorCode errorCode=U_ZERO_ERROR;
+ int32_t length8=0;
+ u_strToUTF8(t, capacity, &length8, s, length, &errorCode);
+ if(U_SUCCESS(errorCode)) {
+ return length8;
+ } else {
+ // The string contains an unpaired surrogate.
+ // Ignore this string.
+ return 0;
+ }
+}
+
+class UnicodeSetWithStringsIterator;
+
+// Make the strings in a UnicodeSet easily accessible.
+class UnicodeSetWithStrings {
+public:
+ UnicodeSetWithStrings(const UnicodeSet &normalSet) :
+ set(normalSet), stringsLength(0), hasSurrogates(FALSE) {
+ int32_t size=set.size();
+ if(size>0 && set.charAt(size-1)<0) {
+ // If a set's last element is not a code point, then it must contain strings.
+ // Iterate over the set, skip all code point ranges, and cache the strings.
+ // Convert them to UTF-8 for spanUTF8().
+ UnicodeSetIterator iter(set);
+ const UnicodeString *s;
+ char *s8=utf8;
+ int32_t length8, utf8Count=0;
+ while(iter.nextRange() && stringsLength<LENGTHOF(strings)) {
+ if(iter.isString()) {
+ // Store the pointer to the set's string element
+ // which we happen to know is a stable pointer.
+ strings[stringsLength]=s=&iter.getString();
+ utf8Count+=
+ utf8Lengths[stringsLength]=length8=
+ appendUTF8(s->getBuffer(), s->length(),
+ s8, (int32_t)(sizeof(utf8)-utf8Count));
+ if(length8==0) {
+ hasSurrogates=TRUE; // Contains unpaired surrogates.
+ }
+ s8+=length8;
+ ++stringsLength;
+ }
+ }
+ }
+ }
+
+ const UnicodeSet &getSet() const {
+ return set;
+ }
+
+ UBool hasStrings() const {
+ return (UBool)(stringsLength>0);
+ }
+
+ UBool hasStringsWithSurrogates() const {
+ return hasSurrogates;
+ }
+
+private:
+ friend class UnicodeSetWithStringsIterator;
+
+ const UnicodeSet &set;
+
+ const UnicodeString *strings[20];
+ int32_t stringsLength;
+ UBool hasSurrogates;
+
+ char utf8[1024];
+ int32_t utf8Lengths[20];
+
+ int32_t nextStringIndex;
+ int32_t nextUTF8Start;
+};
+
+class UnicodeSetWithStringsIterator {
+public:
+ UnicodeSetWithStringsIterator(const UnicodeSetWithStrings &set) :
+ fSet(set), nextStringIndex(0), nextUTF8Start(0) {
+ }
+
+ void reset() {
+ nextStringIndex=nextUTF8Start=0;
+ }
+
+ const UnicodeString *nextString() {
+ if(nextStringIndex<fSet.stringsLength) {
+ return fSet.strings[nextStringIndex++];
+ } else {
+ return NULL;
+ }
+ }
+
+ // Do not mix with calls to nextString().
+ const char *nextUTF8(int32_t &length) {
+ if(nextStringIndex<fSet.stringsLength) {
+ const char *s8=fSet.utf8+nextUTF8Start;
+ nextUTF8Start+=length=fSet.utf8Lengths[nextStringIndex++];
+ return s8;
+ } else {
+ length=0;
+ return NULL;
+ }
+ }
+
+private:
+ const UnicodeSetWithStrings &fSet;
+ int32_t nextStringIndex;
+ int32_t nextUTF8Start;
+};
+
+// Compare 16-bit Unicode strings (which may be malformed UTF-16)
+// at code point boundaries.
+// That is, each edge of a match must not be in the middle of a surrogate pair.
+static inline UBool
+matches16CPB(const UChar *s, int32_t start, int32_t limit, const UnicodeString &t) {
+ s+=start;
+ limit-=start;
+ int32_t length=t.length();
+ return 0==t.compare(s, length) &&
+ !(0<start && U16_IS_LEAD(s[-1]) && U16_IS_TRAIL(s[0])) &&
+ !(length<limit && U16_IS_LEAD(s[length-1]) && U16_IS_TRAIL(s[length]));
+}
+
+// Implement span() with contains() for comparison.
+static int32_t containsSpanUTF16(const UnicodeSetWithStrings &set, const UChar *s, int32_t length,
+ USetSpanCondition spanCondition) {
+ const UnicodeSet &realSet(set.getSet());
+ if(!set.hasStrings()) {
+ if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+ spanCondition=USET_SPAN_CONTAINED; // Pin to 0/1 values.
+ }
+
+ UChar32 c;
+ int32_t start=0, prev;
+ while((prev=start)<length) {
+ U16_NEXT(s, start, length, c);
+ if(realSet.contains(c)!=spanCondition) {
+ break;
+ }
+ }
+ return prev;
+ } else if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+ UnicodeSetWithStringsIterator iter(set);
+ UChar32 c;
+ int32_t start, next;
+ for(start=next=0; start<length;) {
+ U16_NEXT(s, next, length, c);
+ if(realSet.contains(c)) {
+ break;
+ }
+ const UnicodeString *str;
+ iter.reset();
+ while((str=iter.nextString())!=NULL) {
+ if(str->length()<=(length-start) && matches16CPB(s, start, length, *str)) {
+ // spanNeedsStrings=TRUE;
+ return start;
+ }
+ }
+ start=next;
+ }
+ return start;
+ } else /* USET_SPAN_CONTAINED or USET_SPAN_SIMPLE */ {
+ UnicodeSetWithStringsIterator iter(set);
+ UChar32 c;
+ int32_t start, next, maxSpanLimit=0;
+ for(start=next=0; start<length;) {
+ U16_NEXT(s, next, length, c);
+ if(!realSet.contains(c)) {
+ next=start; // Do not span this single, not-contained code point.
+ }
+ const UnicodeString *str;
+ iter.reset();
+ while((str=iter.nextString())!=NULL) {
+ if(str->length()<=(length-start) && matches16CPB(s, start, length, *str)) {
+ // spanNeedsStrings=TRUE;
+ int32_t matchLimit=start+str->length();
+ if(matchLimit==length) {
+ return length;
+ }
+ if(spanCondition==USET_SPAN_CONTAINED) {
+ // Iterate for the shortest match at each position.
+ // Recurse for each but the shortest match.
+ if(next==start) {
+ next=matchLimit; // First match from start.
+ } else {
+ if(matchLimit<next) {
+ // Remember shortest match from start for iteration.
+ int32_t temp=next;
+ next=matchLimit;
+ matchLimit=temp;
+ }
+ // Recurse for non-shortest match from start.
+ int32_t spanLength=containsSpanUTF16(set, s+matchLimit, length-matchLimit,
+ USET_SPAN_CONTAINED);
+ if((matchLimit+spanLength)>maxSpanLimit) {
+ maxSpanLimit=matchLimit+spanLength;
+ if(maxSpanLimit==length) {
+ return length;
+ }
+ }
+ }
+ } else /* spanCondition==USET_SPAN_SIMPLE */ {
+ if(matchLimit>next) {
+ // Remember longest match from start.
+ next=matchLimit;
+ }
+ }
+ }
+ }
+ if(next==start) {
+ break; // No match from start.
+ }
+ start=next;
+ }
+ if(start>maxSpanLimit) {
+ return start;
+ } else {
+ return maxSpanLimit;
+ }
+ }
+}
+
+static int32_t containsSpanBackUTF16(const UnicodeSetWithStrings &set, const UChar *s, int32_t length,
+ USetSpanCondition spanCondition) {
+ if(length==0) {
+ return 0;
+ }
+ const UnicodeSet &realSet(set.getSet());
+ if(!set.hasStrings()) {
+ if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+ spanCondition=USET_SPAN_CONTAINED; // Pin to 0/1 values.
+ }
+
+ UChar32 c;
+ int32_t prev=length;
+ do {
+ U16_PREV(s, 0, length, c);
+ if(realSet.contains(c)!=spanCondition) {
+ break;
+ }
+ } while((prev=length)>0);
+ return prev;
+ } else if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+ UnicodeSetWithStringsIterator iter(set);
+ UChar32 c;
+ int32_t prev=length, length0=length;
+ do {
+ U16_PREV(s, 0, length, c);
+ if(realSet.contains(c)) {
+ break;
+ }
+ const UnicodeString *str;
+ iter.reset();
+ while((str=iter.nextString())!=NULL) {
+ if(str->length()<=prev && matches16CPB(s, prev-str->length(), length0, *str)) {
+ // spanNeedsStrings=TRUE;
+ return prev;
+ }
+ }
+ } while((prev=length)>0);
+ return prev;
+ } else /* USET_SPAN_CONTAINED or USET_SPAN_SIMPLE */ {
+ UnicodeSetWithStringsIterator iter(set);
+ UChar32 c;
+ int32_t prev=length, minSpanStart=length, length0=length;
+ do {
+ U16_PREV(s, 0, length, c);
+ if(!realSet.contains(c)) {
+ length=prev; // Do not span this single, not-contained code point.
+ }
+ const UnicodeString *str;
+ iter.reset();
+ while((str=iter.nextString())!=NULL) {
+ if(str->length()<=prev && matches16CPB(s, prev-str->length(), length0, *str)) {
+ // spanNeedsStrings=TRUE;
+ int32_t matchStart=prev-str->length();
+ if(matchStart==0) {
+ return 0;
+ }
+ if(spanCondition==USET_SPAN_CONTAINED) {
+ // Iterate for the shortest match at each position.
+ // Recurse for each but the shortest match.
+ if(length==prev) {
+ length=matchStart; // First match from prev.
+ } else {
+ if(matchStart>length) {
+ // Remember shortest match from prev for iteration.
+ int32_t temp=length;
+ length=matchStart;
+ matchStart=temp;
+ }
+ // Recurse for non-shortest match from prev.
+ int32_t spanStart=containsSpanBackUTF16(set, s, matchStart,
+ USET_SPAN_CONTAINED);
+ if(spanStart<minSpanStart) {
+ minSpanStart=spanStart;
+ if(minSpanStart==0) {
+ return 0;
+ }
+ }
+ }
+ } else /* spanCondition==USET_SPAN_SIMPLE */ {
+ if(matchStart<length) {
+ // Remember longest match from prev.
+ length=matchStart;
+ }
+ }
+ }
+ }
+ if(length==prev) {
+ break; // No match from prev.
+ }
+ } while((prev=length)>0);
+ if(prev<minSpanStart) {
+ return prev;
+ } else {
+ return minSpanStart;
+ }
+ }
+}
+
+static int32_t containsSpanUTF8(const UnicodeSetWithStrings &set, const char *s, int32_t length,
+ USetSpanCondition spanCondition) {
+ const UnicodeSet &realSet(set.getSet());
+ if(!set.hasStrings()) {
+ if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+ spanCondition=USET_SPAN_CONTAINED; // Pin to 0/1 values.
+ }
+
+ UChar32 c;
+ int32_t start=0, prev;
+ while((prev=start)<length) {
+ U8_NEXT(s, start, length, c);
+ if(c<0) {
+ c=0xfffd;
+ }
+ if(realSet.contains(c)!=spanCondition) {
+ break;
+ }
+ }
+ return prev;
+ } else if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+ UnicodeSetWithStringsIterator iter(set);
+ UChar32 c;
+ int32_t start, next;
+ for(start=next=0; start<length;) {
+ U8_NEXT(s, next, length, c);
+ if(c<0) {
+ c=0xfffd;
+ }
+ if(realSet.contains(c)) {
+ break;
+ }
+ const char *s8;
+ int32_t length8;
+ iter.reset();
+ while((s8=iter.nextUTF8(length8))!=NULL) {
+ if(length8!=0 && length8<=(length-start) && 0==memcmp(s+start, s8, length8)) {
+ // spanNeedsStrings=TRUE;
+ return start;
+ }
+ }
+ start=next;
+ }
+ return start;
+ } else /* USET_SPAN_CONTAINED or USET_SPAN_SIMPLE */ {
+ UnicodeSetWithStringsIterator iter(set);
+ UChar32 c;
+ int32_t start, next, maxSpanLimit=0;
+ for(start=next=0; start<length;) {
+ U8_NEXT(s, next, length, c);
+ if(c<0) {
+ c=0xfffd;
+ }
+ if(!realSet.contains(c)) {
+ next=start; // Do not span this single, not-contained code point.
+ }
+ const char *s8;
+ int32_t length8;
+ iter.reset();
+ while((s8=iter.nextUTF8(length8))!=NULL) {
+ if(length8!=0 && length8<=(length-start) && 0==memcmp(s+start, s8, length8)) {
+ // spanNeedsStrings=TRUE;
+ int32_t matchLimit=start+length8;
+ if(matchLimit==length) {
+ return length;
+ }
+ if(spanCondition==USET_SPAN_CONTAINED) {
+ // Iterate for the shortest match at each position.
+ // Recurse for each but the shortest match.
+ if(next==start) {
+ next=matchLimit; // First match from start.
+ } else {
+ if(matchLimit<next) {
+ // Remember shortest match from start for iteration.
+ int32_t temp=next;
+ next=matchLimit;
+ matchLimit=temp;
+ }
+ // Recurse for non-shortest match from start.
+ int32_t spanLength=containsSpanUTF8(set, s+matchLimit, length-matchLimit,
+ USET_SPAN_CONTAINED);
+ if((matchLimit+spanLength)>maxSpanLimit) {
+ maxSpanLimit=matchLimit+spanLength;
+ if(maxSpanLimit==length) {
+ return length;
+ }
+ }
+ }
+ } else /* spanCondition==USET_SPAN_SIMPLE */ {
+ if(matchLimit>next) {
+ // Remember longest match from start.
+ next=matchLimit;
+ }
+ }
+ }
+ }
+ if(next==start) {
+ break; // No match from start.
+ }
+ start=next;
+ }
+ if(start>maxSpanLimit) {
+ return start;
+ } else {
+ return maxSpanLimit;
+ }
+ }
+}
+
+static int32_t containsSpanBackUTF8(const UnicodeSetWithStrings &set, const char *s, int32_t length,
+ USetSpanCondition spanCondition) {
+ if(length==0) {
+ return 0;
+ }
+ const UnicodeSet &realSet(set.getSet());
+ if(!set.hasStrings()) {
+ if(spanCondition!=USET_SPAN_NOT_CONTAINED) {
+ spanCondition=USET_SPAN_CONTAINED; // Pin to 0/1 values.
+ }
+
+ UChar32 c;
+ int32_t prev=length;
+ do {
+ U8_PREV(s, 0, length, c);
+ if(c<0) {
+ c=0xfffd;
+ }
+ if(realSet.contains(c)!=spanCondition) {
+ break;
+ }
+ } while((prev=length)>0);
+ return prev;
+ } else if(spanCondition==USET_SPAN_NOT_CONTAINED) {
+ UnicodeSetWithStringsIterator iter(set);
+ UChar32 c;
+ int32_t prev=length;
+ do {
+ U8_PREV(s, 0, length, c);
+ if(c<0) {
+ c=0xfffd;
+ }
+ if(realSet.contains(c)) {
+ break;
+ }
+ const char *s8;
+ int32_t length8;
+ iter.reset();
+ while((s8=iter.nextUTF8(length8))!=NULL) {
+ if(length8!=0 && length8<=prev && 0==memcmp(s+prev-length8, s8, length8)) {
+ // spanNeedsStrings=TRUE;
+ return prev;
+ }
+ }
+ } while((prev=length)>0);
+ return prev;
+ } else /* USET_SPAN_CONTAINED or USET_SPAN_SIMPLE */ {
+ UnicodeSetWithStringsIterator iter(set);
+ UChar32 c;
+ int32_t prev=length, minSpanStart=length;
+ do {
+ U8_PREV(s, 0, length, c);
+ if(c<0) {
+ c=0xfffd;
+ }
+ if(!realSet.contains(c)) {
+ length=prev; // Do not span this single, not-contained code point.
+ }
+ const char *s8;
+ int32_t length8;
+ iter.reset();
+ while((s8=iter.nextUTF8(length8))!=NULL) {
+ if(length8!=0 && length8<=prev && 0==memcmp(s+prev-length8, s8, length8)) {
+ // spanNeedsStrings=TRUE;
+ int32_t matchStart=prev-length8;
+ if(matchStart==0) {
+ return 0;
+ }
+ if(spanCondition==USET_SPAN_CONTAINED) {
+ // Iterate for the shortest match at each position.
+ // Recurse for each but the shortest match.
+ if(length==prev) {
+ length=matchStart; // First match from prev.
+ } else {
+ if(matchStart>length) {
+ // Remember shortest match from prev for iteration.
+ int32_t temp=length;
+ length=matchStart;
+ matchStart=temp;
+ }
+ // Recurse for non-shortest match from prev.
+ int32_t spanStart=containsSpanBackUTF8(set, s, matchStart,
+ USET_SPAN_CONTAINED);
+ if(spanStart<minSpanStart) {
+ minSpanStart=spanStart;
+ if(minSpanStart==0) {
+ return 0;
+ }
+ }
+ }
+ } else /* spanCondition==USET_SPAN_SIMPLE */ {
+ if(matchStart<length) {
+ // Remember longest match from prev.
+ length=matchStart;
+ }
+ }
+ }
+ }
+ if(length==prev) {
+ break; // No match from prev.
+ }
+ } while((prev=length)>0);
+ if(prev<minSpanStart) {
+ return prev;
+ } else {
+ return minSpanStart;
+ }
+ }
+}
+
+// spans to be performed and compared
+enum {
+ SPAN_UTF16 =1,
+ SPAN_UTF8 =2,
+ SPAN_UTFS =3,
+
+ SPAN_SET =4,
+ SPAN_COMPLEMENT =8,
+ SPAN_POLARITY =0xc,
+
+ SPAN_FWD =0x10,
+ SPAN_BACK =0x20,
+ SPAN_DIRS =0x30,
+
+ SPAN_CONTAINED =0x100,
+ SPAN_SIMPLE =0x200,
+ SPAN_CONDITION =0x300,
+
+ SPAN_ALL =0x33f
+};
+
+static inline USetSpanCondition invertSpanCondition(USetSpanCondition spanCondition, USetSpanCondition contained) {
+ return spanCondition == USET_SPAN_NOT_CONTAINED ? contained : USET_SPAN_NOT_CONTAINED;
+}
+
+static inline int32_t slen(const void *s, UBool isUTF16) {
+ return isUTF16 ? u_strlen((const UChar *)s) : strlen((const char *)s);
+}
+
+/*
+ * Count spans on a string with the method according to type and set the span limits.
+ * The set may be the complement of the original.
+ * When using spanBack() and comparing with span(), use a span condition for the first spanBack()
+ * according to the expected number of spans.
+ * Sets typeName to an empty string if there is no such type.
+ * Returns -1 if the span option is filtered out.
+ */
+static int32_t getSpans(const UnicodeSetWithStrings &set, UBool isComplement,
+ const void *s, int32_t length, UBool isUTF16,
+ uint32_t whichSpans,
+ int type, const char *&typeName,
+ int32_t limits[], int32_t limitsCapacity,
+ int32_t expectCount) {
+ const UnicodeSet &realSet(set.getSet());
+ int32_t start, count;
+ USetSpanCondition spanCondition, firstSpanCondition, contained;
+ UBool isForward;
+
+ if(type<0 || 7<type) {
+ typeName="";
+ return 0;
+ }
+
+ static const char *const typeNames16[]={
+ "contains", "contains(LM)",
+ "span", "span(LM)",
+ "containsBack", "containsBack(LM)",
+ "spanBack", "spanBack(LM)"
+ };
+
+ static const char *const typeNames8[]={
+ "containsUTF8", "containsUTF8(LM)",
+ "spanUTF8", "spanUTF8(LM)",
+ "containsBackUTF8", "containsBackUTF8(LM)", // not implemented
+ "spanBackUTF8", "spanBackUTF8(LM)"
+ };
+
+ typeName= isUTF16 ? typeNames16[type] : typeNames8[type];
+
+ // filter span options
+ if(type<=3) {
+ // span forward
+ if((whichSpans&SPAN_FWD)==0) {
+ return -1;
+ }
+ isForward=TRUE;
+ } else {
+ // span backward
+ if((whichSpans&SPAN_BACK)==0) {
+ return -1;
+ }
+ isForward=FALSE;
+ }
+ if((type&1)==0) {
+ // use USET_SPAN_CONTAINED
+ if((whichSpans&SPAN_CONTAINED)==0) {
+ return -1;
+ }
+ contained=USET_SPAN_CONTAINED;
+ } else {
+ // use USET_SPAN_SIMPLE
+ if((whichSpans&SPAN_SIMPLE)==0) {
+ return -1;
+ }
+ contained=USET_SPAN_SIMPLE;
+ }
+
+ // Default first span condition for going forward with an uncomplemented set.
+ spanCondition=USET_SPAN_NOT_CONTAINED;
+ if(isComplement) {
+ spanCondition=invertSpanCondition(spanCondition, contained);
+ }
+
+ // First span condition for span(), used to terminate the spanBack() iteration.
+ firstSpanCondition=spanCondition;
+
+ // spanBack(): Its initial span condition is span()'s last span condition,
+ // which is the opposite of span()'s first span condition
+ // if we expect an even number of spans.
+ // (The loop inverts spanCondition (expectCount-1) times
+ // before the expectCount'th span() call.)
+ // If we do not compare forward and backward directions, then we do not have an
+ // expectCount and just start with firstSpanCondition.
+ if(!isForward && (whichSpans&SPAN_FWD)!=0 && (expectCount&1)==0) {
+ spanCondition=invertSpanCondition(spanCondition, contained);
+ }
+
+ count=0;
+ switch(type) {
+ case 0:
+ case 1:
+ start=0;
+ if(length<0) {
+ length=slen(s, isUTF16);
+ }
+ for(;;) {
+ start+= isUTF16 ? containsSpanUTF16(set, (const UChar *)s+start, length-start, spanCondition) :
+ containsSpanUTF8(set, (const char *)s+start, length-start, spanCondition);
+ if(count<limitsCapacity) {
+ limits[count]=start;
+ }
+ ++count;
+ if(start>=length) {
+ break;
+ }
+ spanCondition=invertSpanCondition(spanCondition, contained);
+ }
+ break;
+ case 2:
+ case 3:
+ start=0;
+ for(;;) {
+ start+= isUTF16 ? realSet.span((const UChar *)s+start, length>=0 ? length-start : length, spanCondition) :
+ realSet.spanUTF8((const char *)s+start, length>=0 ? length-start : length, spanCondition);
+ if(count<limitsCapacity) {
+ limits[count]=start;
+ }
+ ++count;
+ if(length>=0 ? start>=length :
+ isUTF16 ? ((const UChar *)s)[start]==0 :
+ ((const char *)s)[start]==0
+ ) {
+ break;
+ }
+ spanCondition=invertSpanCondition(spanCondition, contained);
+ }
+ break;
+ case 4:
+ case 5:
+ if(length<0) {
+ length=slen(s, isUTF16);
+ }
+ for(;;) {
+ ++count;
+ if(count<=limitsCapacity) {
+ limits[limitsCapacity-count]=length;
+ }
+ length= isUTF16 ? containsSpanBackUTF16(set, (const UChar *)s, length, spanCondition) :
+ containsSpanBackUTF8(set, (const char *)s, length, spanCondition);
+ if(length==0 && spanCondition==firstSpanCondition) {
+ break;
+ }
+ spanCondition=invertSpanCondition(spanCondition, contained);
+ }
+ if(count<limitsCapacity) {
+ memmove(limits, limits+(limitsCapacity-count), count*4);
+ }
+ break;
+ case 6:
+ case 7:
+ for(;;) {
+ ++count;
+ if(count<=limitsCapacity) {
+ limits[limitsCapacity-count]= length >=0 ? length : slen(s, isUTF16);
+ }
+ // Note: Length<0 is tested only for the first spanBack().
+ // If we wanted to keep length<0 for all spanBack()s, we would have to
+ // temporarily modify the string by placing a NUL where the previous spanBack() stopped.
+ length= isUTF16 ? realSet.spanBack((const UChar *)s, length, spanCondition) :
+ realSet.spanBackUTF8((const char *)s, length, spanCondition);
+ if(length==0 && spanCondition==firstSpanCondition) {
+ break;
+ }
+ spanCondition=invertSpanCondition(spanCondition, contained);
+ }
+ if(count<limitsCapacity) {
+ memmove(limits, limits+(limitsCapacity-count), count*4);
+ }
+ break;
+ default:
+ typeName="";
+ return -1;
+ }
+
+ return count;
+}
+
+// sets to be tested; odd index=isComplement
+enum {
+ SLOW,
+ SLOW_NOT,
+ FAST,
+ FAST_NOT,
+ SET_COUNT
+};
+
+static const char *const setNames[SET_COUNT]={
+ "slow",
+ "slow.not",
+ "fast",
+ "fast.not"
+};
+
+/*
+ * Verify that we get the same results whether we look at text with contains(),
+ * span() or spanBack(), using unfrozen or frozen versions of the set,
+ * and using the set or its complement (switching the spanConditions accordingly).
+ * The latter verifies that
+ * set.span(spanCondition) == set.complement().span(!spanCondition).
+ *
+ * The expectLimits[] are either provided by the caller (with expectCount>=0)
+ * or returned to the caller (with an input expectCount<0).
+ */
+void UnicodeSetTest::testSpan(const UnicodeSetWithStrings *sets[4],
+ const void *s, int32_t length, UBool isUTF16,
+ uint32_t whichSpans,
+ int32_t expectLimits[], int32_t &expectCount,
+ const char *testName, int32_t index) {
+ int32_t limits[500];
+ int32_t limitsCount;
+ int i, j;
+
+ const char *typeName;
+ int type;
+
+ for(i=0; i<SET_COUNT; ++i) {
+ if((i&1)==0) {
+ // Even-numbered sets are original, uncomplemented sets.
+ if((whichSpans&SPAN_SET)==0) {
+ continue;
+ }
+ } else {
+ // Odd-numbered sets are complemented.
+ if((whichSpans&SPAN_COMPLEMENT)==0) {
+ continue;
+ }
+ }
+ for(type=0;; ++type) {
+ limitsCount=getSpans(*sets[i], (UBool)(i&1),
+ s, length, isUTF16,
+ whichSpans,
+ type, typeName,
+ limits, LENGTHOF(limits), expectCount);
+ if(typeName[0]==0) {
+ break; // All types tried.
+ }
+ if(limitsCount<0) {
+ continue; // Span option filtered out.
+ }
+ if(expectCount<0) {
+ expectCount=limitsCount;
+ if(limitsCount>LENGTHOF(limits)) {
+ errln("FAIL: %s[0x%lx].%s.%s span count=%ld > %ld capacity - too many spans",
+ testName, (long)index, setNames[i], typeName, (long)limitsCount, (long)LENGTHOF(limits));
+ return;
+ }
+ memcpy(expectLimits, limits, limitsCount*4);
+ } else if(limitsCount!=expectCount) {
+ errln("FAIL: %s[0x%lx].%s.%s span count=%ld != %ld",
+ testName, (long)index, setNames[i], typeName, (long)limitsCount, (long)expectCount);
+ } else {
+ for(j=0; j<limitsCount; ++j) {
+ if(limits[j]!=expectLimits[j]) {
+ errln("FAIL: %s[0x%lx].%s.%s span count=%ld limits[%d]=%ld != %ld",
+ testName, (long)index, setNames[i], typeName, (long)limitsCount,
+ j, (long)limits[j], (long)expectLimits[j]);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Compare span() with containsAll()/containsNone(),
+ // but only if we have expectLimits[] from the uncomplemented set.
+ if(isUTF16 && (whichSpans&SPAN_SET)!=0) {
+ const UChar *s16=(const UChar *)s;
+ UnicodeString string;
+ int32_t prev=0, limit, length;
+ for(i=0; i<expectCount; ++i) {
+ limit=expectLimits[i];
+ length=limit-prev;
+ if(length>0) {
+ string.setTo(FALSE, s16+prev, length); // read-only alias
+ if(i&1) {
+ if(!sets[SLOW]->getSet().containsAll(string)) {
+ errln("FAIL: %s[0x%lx].%s.containsAll(%ld..%ld)==FALSE contradicts span()",
+ testName, (long)index, setNames[SLOW], (long)prev, (long)limit);
+ return;
+ }
+ if(!sets[FAST]->getSet().containsAll(string)) {
+ errln("FAIL: %s[0x%lx].%s.containsAll(%ld..%ld)==FALSE contradicts span()",
+ testName, (long)index, setNames[FAST], (long)prev, (long)limit);
+ return;
+ }
+ } else {
+ if(!sets[SLOW]->getSet().containsNone(string)) {
+ errln("FAIL: %s[0x%lx].%s.containsNone(%ld..%ld)==FALSE contradicts span()",
+ testName, (long)index, setNames[SLOW], (long)prev, (long)limit);
+ return;
+ }
+ if(!sets[FAST]->getSet().containsNone(string)) {
+ errln("FAIL: %s[0x%lx].%s.containsNone(%ld..%ld)==FALSE contradicts span()",
+ testName, (long)index, setNames[FAST], (long)prev, (long)limit);
+ return;
+ }
+ }
+ }
+ prev=limit;
+ }
+ }
+}
+
+// Specifically test either UTF-16 or UTF-8.
+void UnicodeSetTest::testSpan(const UnicodeSetWithStrings *sets[4],
+ const void *s, int32_t length, UBool isUTF16,
+ uint32_t whichSpans,
+ const char *testName, int32_t index) {
+ int32_t expectLimits[500];
+ int32_t expectCount=-1;
+ testSpan(sets, s, length, isUTF16, whichSpans, expectLimits, expectCount, testName, index);
+}
+
+UBool stringContainsUnpairedSurrogate(const UChar *s, int32_t length) {
+ UChar c, c2;
+
+ if(length>=0) {
+ while(length>0) {
+ c=*s++;
+ --length;
+ if(0xd800<=c && c<0xe000) {
+ if(c>=0xdc00 || length==0 || !U16_IS_TRAIL(c2=*s++)) {
+ return TRUE;
+ }
+ --length;
+ }
+ }
+ } else {
+ while((c=*s++)!=0) {
+ if(0xd800<=c && c<0xe000) {
+ if(c>=0xdc00 || !U16_IS_TRAIL(c2=*s++)) {
+ return TRUE;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+// Test both UTF-16 and UTF-8 versions of span() etc. on the same sets and text,
+// unless either UTF is turned off in whichSpans.
+// Testing UTF-16 and UTF-8 together requires that surrogate code points
+// have the same contains(c) value as U+FFFD.
+void UnicodeSetTest::testSpanBothUTFs(const UnicodeSetWithStrings *sets[4],
+ const UChar *s16, int32_t length16,
+ uint32_t whichSpans,
+ const char *testName, int32_t index) {
+ int32_t expectLimits[500];
+ int32_t expectCount;
+
+ expectCount=-1; // Get expectLimits[] from testSpan().
+
+ if((whichSpans&SPAN_UTF16)!=0) {
+ testSpan(sets, s16, length16, TRUE, whichSpans, expectLimits, expectCount, testName, index);
+ }
+ if((whichSpans&SPAN_UTF8)==0) {
+ return;
+ }
+
+ // Convert s16[] and expectLimits[] to UTF-8.
+ uint8_t s8[3000];
+ int32_t offsets[3000];
+
+ const UChar *s16Limit=s16+length16;
+ char *t=(char *)s8;
+ char *tLimit=t+sizeof(s8);
+ int32_t *o=offsets;
+ UErrorCode errorCode=U_ZERO_ERROR;
+
+ // Convert with substitution: Turn unpaired surrogates into U+FFFD.
+ ucnv_fromUnicode(openUTF8Converter(), &t, tLimit, &s16, s16Limit, o, TRUE, &errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("FAIL: %s[0x%lx] ucnv_fromUnicode(to UTF-8) fails with %s",
+ testName, (long)index, u_errorName(errorCode));
+ ucnv_resetFromUnicode(utf8Cnv);
+ return;
+ }
+ int32_t length8=(int32_t)(t-(char *)s8);
+
+ // Convert expectLimits[].
+ int32_t i, j, expect;
+ for(i=j=0; i<expectCount; ++i) {
+ expect=expectLimits[i];
+ if(expect==length16) {
+ expectLimits[i]=length8;
+ } else {
+ while(offsets[j]<expect) {
+ ++j;
+ }
+ expectLimits[i]=j;
+ }
+ }
+
+ testSpan(sets, s8, length8, FALSE, whichSpans, expectLimits, expectCount, testName, index);
+}
+
+static UChar32 nextCodePoint(UChar32 c) {
+ // Skip some large and boring ranges.
+ switch(c) {
+ case 0x3441:
+ return 0x4d7f;
+ case 0x5100:
+ return 0x9f00;
+ case 0xb040:
+ return 0xd780;
+ case 0xe041:
+ return 0xf8fe;
+ case 0x10100:
+ return 0x20000;
+ case 0x20041:
+ return 0xe0000;
+ case 0xe0101:
+ return 0x10fffd;
+ default:
+ return c+1;
+ }
+}
+
+// Verify that all implementations represent the same set.
+void UnicodeSetTest::testSpanContents(const UnicodeSetWithStrings *sets[4], uint32_t whichSpans, const char *testName) {
+ // contains(U+FFFD) is inconsistent with contains(some surrogates),
+ // or the set contains strings with unpaired surrogates which don't translate to valid UTF-8:
+ // Skip the UTF-8 part of the test - if the string contains surrogates -
+ // because it is likely to produce a different result.
+ UBool inconsistentSurrogates=
+ (!(sets[0]->getSet().contains(0xfffd) ?
+ sets[0]->getSet().contains(0xd800, 0xdfff) :
+ sets[0]->getSet().containsNone(0xd800, 0xdfff)) ||
+ sets[0]->hasStringsWithSurrogates());
+
+ UChar s[1000];
+ int32_t length=0;
+ uint32_t localWhichSpans;
+
+ UChar32 c, first;
+ for(first=c=0;; c=nextCodePoint(c)) {
+ if(c>0x10ffff || length>(LENGTHOF(s)-U16_MAX_LENGTH)) {
+ localWhichSpans=whichSpans;
+ if(stringContainsUnpairedSurrogate(s, length) && inconsistentSurrogates) {
+ localWhichSpans&=~SPAN_UTF8;
+ }
+ testSpanBothUTFs(sets, s, length, localWhichSpans, testName, first);
+ if(c>0x10ffff) {
+ break;
+ }
+ length=0;
+ first=c;
+ }
+ U16_APPEND_UNSAFE(s, length, c);
+ }
+}
+
+// Test with a particular, interesting string.
+// Specify length and try NUL-termination.
+void UnicodeSetTest::testSpanUTF16String(const UnicodeSetWithStrings *sets[4], uint32_t whichSpans, const char *testName) {
+ static const UChar s[]={
+ 0x61, 0x62, 0x20, // Latin, space
+ 0x3b1, 0x3b2, 0x3b3, // Greek
+ 0xd900, // lead surrogate
+ 0x3000, 0x30ab, 0x30ad, // wide space, Katakana
+ 0xdc05, // trail surrogate
+ 0xa0, 0xac00, 0xd7a3, // nbsp, Hangul
+ 0xd900, 0xdc05, // unassigned supplementary
+ 0xd840, 0xdfff, 0xd860, 0xdffe, // Han supplementary
+ 0xd7a4, 0xdc05, 0xd900, 0x2028, // unassigned, surrogates in wrong order, LS
+ 0 // NUL
+ };
+
+ if((whichSpans&SPAN_UTF16)==0) {
+ return;
+ }
+ testSpan(sets, s, -1, TRUE, (whichSpans&~SPAN_UTF8), testName, 0);
+ testSpan(sets, s, LENGTHOF(s)-1, TRUE, (whichSpans&~SPAN_UTF8), testName, 1);
+}
+
+void UnicodeSetTest::testSpanUTF8String(const UnicodeSetWithStrings *sets[4], uint32_t whichSpans, const char *testName) {
+ static const char s[]={
+ "abc" // Latin
+
+ /* trail byte in lead position */
+ "\x80"
+
+ " " // space
+
+ /* truncated multi-byte sequences */
+ "\xd0"
+ "\xe0"
+ "\xe1"
+ "\xed"
+ "\xee"
+ "\xf0"
+ "\xf1"
+ "\xf4"
+ "\xf8"
+ "\xfc"
+
+ "\xCE\xB1\xCE\xB2\xCE\xB3" // Greek
+
+ /* trail byte in lead position */
+ "\x80"
+
+ "\xe0\x80"
+ "\xe0\xa0"
+ "\xe1\x80"
+ "\xed\x80"
+ "\xed\xa0"
+ "\xee\x80"
+ "\xf0\x80"
+ "\xf0\x90"
+ "\xf1\x80"
+ "\xf4\x80"
+ "\xf4\x90"
+ "\xf8\x80"
+ "\xfc\x80"
+
+ "\xE3\x80\x80\xE3\x82\xAB\xE3\x82\xAD" // wide space, Katakana
+
+ /* trail byte in lead position */
+ "\x80"
+
+ "\xf0\x80\x80"
+ "\xf0\x90\x80"
+ "\xf1\x80\x80"
+ "\xf4\x80\x80"
+ "\xf4\x90\x80"
+ "\xf8\x80\x80"
+ "\xfc\x80\x80"
+
+ "\xC2\xA0\xEA\xB0\x80\xED\x9E\xA3" // nbsp, Hangul
+
+ /* trail byte in lead position */
+ "\x80"
+
+ "\xf8\x80\x80\x80"
+ "\xfc\x80\x80\x80"
+
+ "\xF1\x90\x80\x85" // unassigned supplementary
+
+ /* trail byte in lead position */
+ "\x80"
+
+ "\xfc\x80\x80\x80\x80"
+
+ "\xF0\xA0\x8F\xBF\xF0\xA8\x8F\xBE" // Han supplementary
+
+ /* trail byte in lead position */
+ "\x80"
+
+ /* complete sequences but non-shortest forms or out of range etc. */
+ "\xc0\x80"
+ "\xe0\x80\x80"
+ "\xed\xa0\x80"
+ "\xf0\x80\x80\x80"
+ "\xf4\x90\x80\x80"
+ "\xf8\x80\x80\x80\x80"
+ "\xfc\x80\x80\x80\x80\x80"
+ "\xfe"
+ "\xff"
+
+ /* trail byte in lead position */
+ "\x80"
+
+ "\xED\x9E\xA4\xE2\x80\xA8" // unassigned, LS, NUL-terminated
+ };
+
+ if((whichSpans&SPAN_UTF8)==0) {
+ return;
+ }
+ testSpan(sets, s, -1, FALSE, (whichSpans&~SPAN_UTF16), testName, 0);
+ testSpan(sets, s, LENGTHOF(s)-1, FALSE, (whichSpans&~SPAN_UTF16), testName, 1);
+}
+
+// Take a set of span options and multiply them so that
+// each portion only has one of the options a, b and c.
+// If b==0, then the set of options is just modified with mask and a.
+// If b!=0 and c==0, then the set of options is just modified with mask, a and b.
+static int32_t
+addAlternative(uint32_t whichSpans[], int32_t whichSpansCount,
+ uint32_t mask, uint32_t a, uint32_t b, uint32_t c) {
+ uint32_t s;
+ int32_t i;
+
+ for(i=0; i<whichSpansCount; ++i) {
+ s=whichSpans[i]&mask;
+ whichSpans[i]=s|a;
+ if(b!=0) {
+ whichSpans[whichSpansCount+i]=s|b;
+ if(c!=0) {
+ whichSpans[2*whichSpansCount+i]=s|c;
+ }
+ }
+ }
+ return b==0 ? whichSpansCount : c==0 ? 2*whichSpansCount : 3*whichSpansCount;
+}
+
+#define _63_a "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+#define _64_a "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+#define _63_b "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+#define _64_b "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+
+void UnicodeSetTest::TestSpan() {
+ // "[...]" is a UnicodeSet pattern.
+ // "*" performs tests on all Unicode code points and on a selection of
+ // malformed UTF-8/16 strings.
+ // "-options" limits the scope of testing for the current set.
+ // By default, the test verifies that equivalent boundaries are found
+ // for UTF-16 and UTF-8, going forward and backward,
+ // alternating USET_SPAN_NOT_CONTAINED with
+ // either USET_SPAN_CONTAINED or USET_SPAN_SIMPLE.
+ // Single-character options:
+ // 8 -- UTF-16 and UTF-8 boundaries may differ.
+ // Cause: contains(U+FFFD) is inconsistent with contains(some surrogates),
+ // or the set contains strings with unpaired surrogates
+ // which do not translate to valid UTF-8.
+ // c -- set.span() and set.complement().span() boundaries may differ.
+ // Cause: Set strings are not complemented.
+ // b -- span() and spanBack() boundaries may differ.
+ // Cause: Strings in the set overlap, and spanBack(USET_SPAN_CONTAINED)
+ // and spanBack(USET_SPAN_SIMPLE) are defined to
+ // match with non-overlapping substrings.
+ // For example, with a set containing "ab" and "ba",
+ // span() of "aba" yields boundaries { 0, 2, 3 }
+ // because the initial "ab" matches from 0 to 2,
+ // while spanBack() yields boundaries { 0, 1, 3 }
+ // because the final "ba" matches from 1 to 3.
+ // l -- USET_SPAN_CONTAINED and USET_SPAN_SIMPLE boundaries may differ.
+ // Cause: Strings in the set overlap, and a longer match may
+ // require a sequence including non-longest substrings.
+ // For example, with a set containing "ab", "abc" and "cd",
+ // span(contained) of "abcd" spans the entire string
+ // but span(longest match) only spans the first 3 characters.
+ // Each "-options" first resets all options and then applies the specified options.
+ // A "-" without options resets the options.
+ // The options are also reset for each new set.
+ // Other strings will be spanned.
+ static const char *const testdata[]={
+ "[:ID_Continue:]",
+ "*",
+ "[:White_Space:]",
+ "*",
+ "[]",
+ "*",
+ "[\\u0000-\\U0010FFFF]",
+ "*",
+ "[\\u0000\\u0080\\u0800\\U00010000]",
+ "*",
+ "[\\u007F\\u07FF\\uFFFF\\U0010FFFF]",
+ "*",
+ "[[[:ID_Continue:]-[\\u30ab\\u30ad]]{\\u3000\\u30ab}{\\u3000\\u30ab\\u30ad}]",
+ "-c",
+ "*",
+ "[[[:ID_Continue:]-[\\u30ab\\u30ad]]{\\u30ab\\u30ad}{\\u3000\\u30ab\\u30ad}]",
+ "-c",
+ "*",
+
+ // Overlapping strings cause overlapping attempts to match.
+ "[x{xy}{xya}{axy}{ax}]",
+ "-cl",
+
+ // More repetitions of "xya" would take too long with the recursive
+ // reference implementation.
+ // containsAll()=FALSE
+ // test_string 0x14
+ "xx"
+ "xyaxyaxyaxya" // set.complement().span(longest match) will stop here.
+ "xx" // set.complement().span(contained) will stop between the two 'x'es.
+ "xyaxyaxyaxya"
+ "xx"
+ "xyaxyaxyaxya" // span() ends here.
+ "aaa",
+
+ // containsAll()=TRUE
+ // test_string 0x15
+ "xx"
+ "xyaxyaxyaxya"
+ "xx"
+ "xyaxyaxyaxya"
+ "xx"
+ "xyaxyaxyaxy",
+
+ "-bc",
+ // test_string 0x17
+ "byayaxya", // span() -> { 4, 7, 8 } spanBack() -> { 5, 8 }
+ "-c",
+ "byayaxy", // span() -> { 4, 7 } complement.span() -> { 7 }
+ "byayax", // span() -> { 4, 6 } complement.span() -> { 6 }
+ "-",
+ "byaya", // span() -> { 5 }
+ "byay", // span() -> { 4 }
+ "bya", // span() -> { 3 }
+
+ // span(longest match) will not span the whole string.
+ "[a{ab}{bc}]",
+ "-cl",
+ // test_string 0x21
+ "abc",
+
+ "[a{ab}{abc}{cd}]",
+ "-cl",
+ "acdabcdabccd",
+
+ // spanBack(longest match) will not span the whole string.
+ "[c{ab}{bc}]",
+ "-cl",
+ "abc",
+
+ "[d{cd}{bcd}{ab}]",
+ "-cl",
+ "abbcdabcdabd",
+
+ // Test with non-ASCII set strings - test proper handling of surrogate pairs
+ // and UTF-8 trail bytes.
+ // Copies of above test sets and strings, but transliterated to have
+ // different code points with similar trail units.
+ // Previous: a b c d
+ // Unicode: 042B 30AB 200AB 204AB
+ // UTF-16: 042B 30AB D840 DCAB D841 DCAB
+ // UTF-8: D0 AB E3 82 AB F0 A0 82 AB F0 A0 92 AB
+ "[\\u042B{\\u042B\\u30AB}{\\u042B\\u30AB\\U000200AB}{\\U000200AB\\U000204AB}]",
+ "-cl",
+ "\\u042B\\U000200AB\\U000204AB\\u042B\\u30AB\\U000200AB\\U000204AB\\u042B\\u30AB\\U000200AB\\U000200AB\\U000204AB",
+
+ "[\\U000204AB{\\U000200AB\\U000204AB}{\\u30AB\\U000200AB\\U000204AB}{\\u042B\\u30AB}]",
+ "-cl",
+ "\\u042B\\u30AB\\u30AB\\U000200AB\\U000204AB\\u042B\\u30AB\\U000200AB\\U000204AB\\u042B\\u30AB\\U000204AB",
+
+ // Stress bookkeeping and recursion.
+ // The following strings are barely doable with the recursive
+ // reference implementation.
+ // The not-contained character at the end prevents an early exit from the span().
+ "[b{bb}]",
+ "-c",
+ // test_string 0x33
+ "bbbbbbbbbbbbbbbbbbbbbbbb-",
+ // On complement sets, span() and spanBack() get different results
+ // because b is not in the complement set and there is an odd number of b's
+ // in the test string.
+ "-bc",
+ "bbbbbbbbbbbbbbbbbbbbbbbbb-",
+
+ // Test with set strings with an initial or final code point span
+ // longer than 254.
+ "[a{" _64_a _64_a _64_a _64_a "b}"
+ "{a" _64_b _64_b _64_b _64_b "}]",
+ "-c",
+ _64_a _64_a _64_a _63_a "b",
+ _64_a _64_a _64_a _64_a "b",
+ _64_a _64_a _64_a _64_a "aaaabbbb",
+ "a" _64_b _64_b _64_b _63_b,
+ "a" _64_b _64_b _64_b _64_b,
+ "aaaabbbb" _64_b _64_b _64_b _64_b,
+
+ // Test with strings containing unpaired surrogates.
+ // They are not representable in UTF-8, and a leading trail surrogate
+ // and a trailing lead surrogate must not match in the middle of a proper surrogate pair.
+ // U+20001 == \\uD840\\uDC01
+ // U+20400 == \\uD841\\uDC00
+ "[a\\U00020001\\U00020400{ab}{b\\uD840}{\\uDC00a}]",
+ "-8cl",
+ "aaab\\U00020001ba\\U00020400aba\\uD840ab\\uD840\\U00020000b\\U00020000a\\U00020000\\uDC00a\\uDC00babbb"
+ };
+ uint32_t whichSpans[96]={ SPAN_ALL };
+ int32_t whichSpansCount=1;
+
+ UnicodeSet *sets[SET_COUNT]={ NULL };
+ const UnicodeSetWithStrings *sets_with_str[SET_COUNT]={ NULL };
+
+ char testName[1024];
+ char *testNameLimit=testName;
+
+ int32_t i, j;
+ for(i=0; i<LENGTHOF(testdata); ++i) {
+ const char *s=testdata[i];
+ if(s[0]=='[') {
+ // Create new test sets from this pattern.
+ for(j=0; j<SET_COUNT; ++j) {
+ delete sets_with_str[j];
+ delete sets[j];
+ }
+ UErrorCode errorCode=U_ZERO_ERROR;
+ sets[SLOW]=new UnicodeSet(UnicodeString(s, -1, US_INV).unescape(), errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("FAIL: Unable to create UnicodeSet(%s) - %s", s, u_errorName(errorCode));
+ break;
+ }
+ sets[SLOW_NOT]=new UnicodeSet(*sets[SLOW]);
+ sets[SLOW_NOT]->complement();
+ // Intermediate set: Test cloning of a frozen set.
+ UnicodeSet *fast=new UnicodeSet(*sets[SLOW]);
+ fast->freeze();
+ sets[FAST]=(UnicodeSet *)fast->clone();
+ delete fast;
+ UnicodeSet *fastNot=new UnicodeSet(*sets[SLOW_NOT]);
+ fastNot->freeze();
+ sets[FAST_NOT]=(UnicodeSet *)fastNot->clone();
+ delete fastNot;
+
+ for(j=0; j<SET_COUNT; ++j) {
+ sets_with_str[j]=new UnicodeSetWithStrings(*sets[j]);
+ }
+
+ strcpy(testName, s);
+ testNameLimit=strchr(testName, 0);
+ *testNameLimit++=':';
+ *testNameLimit=0;
+
+ whichSpans[0]=SPAN_ALL;
+ whichSpansCount=1;
+ } else if(s[0]=='-') {
+ whichSpans[0]=SPAN_ALL;
+ whichSpansCount=1;
+
+ while(*++s!=0) {
+ switch(*s) {
+ case 'c':
+ whichSpansCount=addAlternative(whichSpans, whichSpansCount,
+ ~SPAN_POLARITY,
+ SPAN_SET,
+ SPAN_COMPLEMENT,
+ 0);
+ break;
+ case 'b':
+ whichSpansCount=addAlternative(whichSpans, whichSpansCount,
+ ~SPAN_DIRS,
+ SPAN_FWD,
+ SPAN_BACK,
+ 0);
+ break;
+ case 'l':
+ // test USET_SPAN_CONTAINED FWD & BACK, and separately
+ // USET_SPAN_SIMPLE only FWD, and separately
+ // USET_SPAN_SIMPLE only BACK
+ whichSpansCount=addAlternative(whichSpans, whichSpansCount,
+ ~(SPAN_DIRS|SPAN_CONDITION),
+ SPAN_DIRS|SPAN_CONTAINED,
+ SPAN_FWD|SPAN_SIMPLE,
+ SPAN_BACK|SPAN_SIMPLE);
+ break;
+ case '8':
+ whichSpansCount=addAlternative(whichSpans, whichSpansCount,
+ ~SPAN_UTFS,
+ SPAN_UTF16,
+ SPAN_UTF8,
+ 0);
+ break;
+ default:
+ errln("FAIL: unrecognized span set option in \"%s\"", testdata[i]);
+ break;
+ }
+ }
+ } else if(0==strcmp(s, "*")) {
+ strcpy(testNameLimit, "bad_string");
+ for(j=0; j<whichSpansCount; ++j) {
+ if(whichSpansCount>1) {
+ sprintf(testNameLimit+10 /* strlen("bad_string") */,
+ "%%0x%3x",
+ whichSpans[j]);
+ }
+ testSpanUTF16String(sets_with_str, whichSpans[j], testName);
+ testSpanUTF8String(sets_with_str, whichSpans[j], testName);
+ }
+
+ strcpy(testNameLimit, "contents");
+ for(j=0; j<whichSpansCount; ++j) {
+ if(whichSpansCount>1) {
+ sprintf(testNameLimit+8 /* strlen("contents") */,
+ "%%0x%3x",
+ whichSpans[j]);
+ }
+ testSpanContents(sets_with_str, whichSpans[j], testName);
+ }
+ } else {
+ UnicodeString string=UnicodeString(s, -1, US_INV).unescape();
+ strcpy(testNameLimit, "test_string");
+ for(j=0; j<whichSpansCount; ++j) {
+ if(whichSpansCount>1) {
+ sprintf(testNameLimit+11 /* strlen("test_string") */,
+ "%%0x%3x",
+ whichSpans[j]);
+ }
+ testSpanBothUTFs(sets_with_str, string.getBuffer(), string.length(), whichSpans[j], testName, i);
+ }
+ }
+ }
+ for(j=0; j<SET_COUNT; ++j) {
+ delete sets_with_str[j];
+ delete sets[j];
+ }
+}
+
+// Test select patterns and strings, and test USET_SPAN_SIMPLE.
+void UnicodeSetTest::TestStringSpan() {
+ static const char *pattern="[x{xy}{xya}{axy}{ax}]";
+ static const char *const string=
+ "xx"
+ "xyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxya"
+ "xx"
+ "xyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxya"
+ "xx"
+ "xyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxyaxy"
+ "aaaa";
+
+ UErrorCode errorCode=U_ZERO_ERROR;
+ UnicodeString pattern16=UnicodeString(pattern, -1, US_INV);
+ UnicodeSet set(pattern16, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("FAIL: Unable to create UnicodeSet(%s) - %s", pattern, u_errorName(errorCode));
+ return;
+ }
+
+ UnicodeString string16=UnicodeString(string, -1, US_INV).unescape();
+
+ if(set.containsAll(string16)) {
+ errln("FAIL: UnicodeSet(%s).containsAll(%s) should be FALSE", pattern, string);
+ }
+
+ // Remove trailing "aaaa".
+ string16.truncate(string16.length()-4);
+ if(!set.containsAll(string16)) {
+ errln("FAIL: UnicodeSet(%s).containsAll(%s[:-4]) should be TRUE", pattern, string);
+ }
+
+ string16=UNICODE_STRING_SIMPLE("byayaxya");
+ const UChar *s16=string16.getBuffer();
+ int32_t length16=string16.length();
+ if( set.span(s16, 8, USET_SPAN_NOT_CONTAINED)!=4 ||
+ set.span(s16, 7, USET_SPAN_NOT_CONTAINED)!=4 ||
+ set.span(s16, 6, USET_SPAN_NOT_CONTAINED)!=4 ||
+ set.span(s16, 5, USET_SPAN_NOT_CONTAINED)!=5 ||
+ set.span(s16, 4, USET_SPAN_NOT_CONTAINED)!=4 ||
+ set.span(s16, 3, USET_SPAN_NOT_CONTAINED)!=3
+ ) {
+ errln("FAIL: UnicodeSet(%s).span(while not) returns the wrong value", pattern);
+ }
+
+ pattern="[a{ab}{abc}{cd}]";
+ pattern16=UnicodeString(pattern, -1, US_INV);
+ set.applyPattern(pattern16, errorCode);
+ if(U_FAILURE(errorCode)) {
+ errln("FAIL: Unable to create UnicodeSet(%s) - %s", pattern, u_errorName(errorCode));
+ return;
+ }
+ string16=UNICODE_STRING_SIMPLE("acdabcdabccd");
+ s16=string16.getBuffer();
+ length16=string16.length();
+ if( set.span(s16, 12, USET_SPAN_CONTAINED)!=12 ||
+ set.span(s16, 12, USET_SPAN_SIMPLE)!=6 ||
+ set.span(s16+7, 5, USET_SPAN_SIMPLE)!=5
+ ) {
+ errln("FAIL: UnicodeSet(%s).span(while longest match) returns the wrong value", pattern);
+ }
+
+ pattern="[d{cd}{bcd}{ab}]";
+ pattern16=UnicodeString(pattern, -1, US_INV);
+ set.applyPattern(pattern16, errorCode).freeze();
+ if(U_FAILURE(errorCode)) {
+ errln("FAIL: Unable to create UnicodeSet(%s) - %s", pattern, u_errorName(errorCode));
+ return;
+ }
+ string16=UNICODE_STRING_SIMPLE("abbcdabcdabd");
+ s16=string16.getBuffer();
+ length16=string16.length();
+ if( set.spanBack(s16, 12, USET_SPAN_CONTAINED)!=0 ||
+ set.spanBack(s16, 12, USET_SPAN_SIMPLE)!=6 ||
+ set.spanBack(s16, 5, USET_SPAN_SIMPLE)!=0
+ ) {
+ errln("FAIL: UnicodeSet(%s).spanBack(while longest match) returns the wrong value", pattern);
+ }
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/usettest.h b/Build/source/libs/icu/icu-xetex/test/intltest/usettest.h
new file mode 100644
index 00000000000..94083406764
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/usettest.h
@@ -0,0 +1,190 @@
+
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************
+**********************************************************************
+* Date Name Description
+* 10/20/99 alan Creation.
+* 03/22/2000 Madhu Added additional tests
+**********************************************************************
+*/
+
+#ifndef _TESTUNISET
+#define _TESTUNISET
+
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#include "unicode/ucnv_err.h"
+#include "intltest.h"
+
+class UnicodeSetWithStrings;
+
+/**
+ * UnicodeSet test
+ */
+class UnicodeSetTest: public IntlTest {
+public:
+ UnicodeSetTest();
+ ~UnicodeSetTest();
+
+private:
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par=NULL);
+
+ void Testj2268();
+
+ /**
+ * Test that toPattern() round trips with syntax characters and
+ * whitespace.
+ */
+ void TestToPattern();
+
+ void TestPatterns(void);
+ void TestCategories(void);
+ void TestAddRemove(void);
+ void TestCloneEqualHash(void);
+
+ /**
+ * Make sure minimal representation is maintained.
+ */
+ void TestMinimalRep(void);
+
+ void TestAPI(void);
+
+ void TestIteration(void);
+
+ void TestStrings(void);
+
+ void TestScriptSet(void);
+
+ /**
+ * Test the [:Latin:] syntax.
+ */
+ void TestPropertySet(void);
+
+ void TestClone(void);
+
+ void TestIndexOf(void);
+
+ void TestExhaustive(void);
+
+ void TestCloseOver(void);
+
+ void TestEscapePattern(void);
+
+ void TestInvalidCodePoint(void);
+
+ void TestSymbolTable(void);
+
+ void TestSurrogate();
+
+ void TestPosixClasses();
+
+ void TestFreezable();
+
+ void TestSpan();
+
+ void TestStringSpan();
+
+private:
+
+ UBool toPatternAux(UChar32 start, UChar32 end);
+
+ UBool checkPat(const UnicodeString& source,
+ const UnicodeSet& testSet);
+
+ UBool checkPat(const UnicodeString& source, const UnicodeSet& testSet, const UnicodeString& pat);
+
+ void _testComplement(int32_t a, UnicodeSet&, UnicodeSet&);
+
+ void _testAdd(int32_t a, int32_t b, UnicodeSet&, UnicodeSet&, UnicodeSet&);
+
+ void _testRetain(int32_t a, int32_t b, UnicodeSet&, UnicodeSet&, UnicodeSet&);
+
+ void _testRemove(int32_t a, int32_t b, UnicodeSet&, UnicodeSet&, UnicodeSet&);
+
+ void _testXor(int32_t a, int32_t b, UnicodeSet&, UnicodeSet&, UnicodeSet&);
+
+ /**
+ * Check that ranges are monotonically increasing and non-
+ * overlapping.
+ */
+ void checkCanonicalRep(const UnicodeSet& set, const UnicodeString& msg);
+
+ /**
+ * Convert a bitmask to a UnicodeSet.
+ */
+ static UnicodeSet& bitsToSet(int32_t a, UnicodeSet&);
+
+ /**
+ * Convert a UnicodeSet to a bitmask. Only the characters
+ * U+0000 to U+0020 are represented in the bitmask.
+ */
+ static int32_t setToBits(const UnicodeSet& x);
+
+ /**
+ * Return the representation of an inversion list based UnicodeSet
+ * as a pairs list. Ranges are listed in ascending Unicode order.
+ * For example, the set [a-zA-M3] is represented as "33AMaz".
+ */
+ static UnicodeString getPairs(const UnicodeSet& set);
+
+ /**
+ * Basic consistency check for a few items.
+ * That the iterator works, and that we can create a pattern and
+ * get the same thing back
+ */
+ void checkRoundTrip(const UnicodeSet& s);
+
+ void copyWithIterator(UnicodeSet& t, const UnicodeSet& s, UBool withRange);
+
+ UBool checkEqual(const UnicodeSet& s, const UnicodeSet& t, const char* message);
+
+ void expectContainment(const UnicodeString& pat,
+ const UnicodeString& charsIn,
+ const UnicodeString& charsOut);
+ void expectContainment(const UnicodeSet& set,
+ const UnicodeString& charsIn,
+ const UnicodeString& charsOut);
+ void expectContainment(const UnicodeSet& set,
+ const UnicodeString& setName,
+ const UnicodeString& charsIn,
+ const UnicodeString& charsOut);
+ void expectPattern(UnicodeSet& set,
+ const UnicodeString& pattern,
+ const UnicodeString& expectedPairs);
+ void expectPairs(const UnicodeSet& set,
+ const UnicodeString& expectedPairs);
+ void expectToPattern(const UnicodeSet& set,
+ const UnicodeString& expPat,
+ const char** expStrings);
+ void expectRange(const UnicodeString& label,
+ const UnicodeSet& set,
+ UChar32 start, UChar32 end);
+ void doAssert(UBool, const char*);
+
+ void testSpan(const UnicodeSetWithStrings *sets[4], const void *s, int32_t length, UBool isUTF16,
+ uint32_t whichSpans,
+ int32_t expectLimits[], int32_t &expectCount,
+ const char *testName, int32_t index);
+ void testSpan(const UnicodeSetWithStrings *sets[4], const void *s, int32_t length, UBool isUTF16,
+ uint32_t whichSpans,
+ const char *testName, int32_t index);
+ void testSpanBothUTFs(const UnicodeSetWithStrings *sets[4],
+ const UChar *s16, int32_t length16,
+ uint32_t whichSpans,
+ const char *testName, int32_t index);
+ void testSpanContents(const UnicodeSetWithStrings *sets[4], uint32_t whichSpans, const char *testName);
+ void testSpanUTF16String(const UnicodeSetWithStrings *sets[4], uint32_t whichSpans, const char *testName);
+ void testSpanUTF8String(const UnicodeSetWithStrings *sets[4], uint32_t whichSpans, const char *testName);
+
+ UConverter *openUTF8Converter();
+
+ UConverter *utf8Cnv;
+
+public:
+ static UnicodeString escape(const UnicodeString& s);
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ustrtest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/ustrtest.cpp
new file mode 100644
index 00000000000..5b50fbaf48e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ustrtest.cpp
@@ -0,0 +1,1703 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#include "ustrtest.h"
+#include "unicode/unistr.h"
+#include "unicode/uchar.h"
+#include "unicode/ustring.h"
+#include "unicode/locid.h"
+#include "unicode/ucnv.h"
+#include "cmemory.h"
+#include "charstr.h"
+
+#if 0
+#include "unicode/ustream.h"
+
+#if U_IOSTREAM_SOURCE >= 199711
+#include <iostream>
+using namespace std;
+#elif U_IOSTREAM_SOURCE >= 198506
+#include <iostream.h>
+#endif
+
+#endif
+
+#define LENGTHOF(array) (int32_t)((sizeof(array)/sizeof((array)[0])))
+
+UnicodeStringTest::~UnicodeStringTest() {}
+
+void UnicodeStringTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char *par)
+{
+ if (exec) logln("TestSuite UnicodeStringTest: ");
+ switch (index) {
+ case 0:
+ name = "StringCaseTest";
+ if (exec) {
+ logln("StringCaseTest---"); logln("");
+ StringCaseTest test;
+ callTest(test, par);
+ }
+ break;
+ case 1: name = "TestBasicManipulation"; if (exec) TestBasicManipulation(); break;
+ case 2: name = "TestCompare"; if (exec) TestCompare(); break;
+ case 3: name = "TestExtract"; if (exec) TestExtract(); break;
+ case 4: name = "TestRemoveReplace"; if (exec) TestRemoveReplace(); break;
+ case 5: name = "TestSearching"; if (exec) TestSearching(); break;
+ case 6: name = "TestSpacePadding"; if (exec) TestSpacePadding(); break;
+ case 7: name = "TestPrefixAndSuffix"; if (exec) TestPrefixAndSuffix(); break;
+ case 8: name = "TestFindAndReplace"; if (exec) TestFindAndReplace(); break;
+ case 9: name = "TestBogus"; if (exec) TestBogus(); break;
+ case 10: name = "TestReverse"; if (exec) TestReverse(); break;
+ case 11: name = "TestMiscellaneous"; if (exec) TestMiscellaneous(); break;
+ case 12: name = "TestStackAllocation"; if (exec) TestStackAllocation(); break;
+ case 13: name = "TestUnescape"; if (exec) TestUnescape(); break;
+ case 14: name = "TestCountChar32"; if (exec) TestCountChar32(); break;
+ case 15: name = "TestStringEnumeration"; if (exec) TestStringEnumeration(); break;
+ case 16: name = "TestCharString"; if (exec) TestCharString(); break;
+ case 17: name = "TestNameSpace"; if (exec) TestNameSpace(); break;
+
+ default: name = ""; break; //needed to end loop
+ }
+}
+
+void
+UnicodeStringTest::TestBasicManipulation()
+{
+ UnicodeString test1("Now is the time for all men to come swiftly to the aid of the party.\n");
+ UnicodeString expectedValue;
+ UnicodeString *c;
+
+ c=(UnicodeString *)test1.clone();
+ test1.insert(24, "good ");
+ expectedValue = "Now is the time for all good men to come swiftly to the aid of the party.\n";
+ if (test1 != expectedValue)
+ errln("insert() failed: expected \"" + expectedValue + "\"\n,got \"" + test1 + "\"");
+
+ c->insert(24, "good ");
+ if(*c != expectedValue) {
+ errln("clone()->insert() failed: expected \"" + expectedValue + "\"\n,got \"" + *c + "\"");
+ }
+ delete c;
+
+ test1.remove(41, 8);
+ expectedValue = "Now is the time for all good men to come to the aid of the party.\n";
+ if (test1 != expectedValue)
+ errln("remove() failed: expected \"" + expectedValue + "\"\n,got \"" + test1 + "\"");
+
+ test1.replace(58, 6, "ir country");
+ expectedValue = "Now is the time for all good men to come to the aid of their country.\n";
+ if (test1 != expectedValue)
+ errln("replace() failed: expected \"" + expectedValue + "\"\n,got \"" + test1 + "\"");
+
+ UChar temp[80];
+ test1.extract(0, 15, temp);
+
+ UnicodeString test2(temp, 15);
+
+ expectedValue = "Now is the time";
+ if (test2 != expectedValue)
+ errln("extract() failed: expected \"" + expectedValue + "\"\n,got \"" + test2 + "\"");
+
+ test2 += " for me to go!\n";
+ expectedValue = "Now is the time for me to go!\n";
+ if (test2 != expectedValue)
+ errln("operator+=() failed: expected \"" + expectedValue + "\"\n,got \"" + test2 + "\"");
+
+ if (test1.length() != 70)
+ errln("length() failed: expected 70, got " + test1.length());
+ if (test2.length() != 30)
+ errln("length() failed: expected 30, got " + test2.length());
+
+ UnicodeString test3;
+ test3.append((UChar32)0x20402);
+ if(test3 != CharsToUnicodeString("\\uD841\\uDC02")){
+ errln((UnicodeString)"append failed for UChar32, expected \"\\\\ud841\\\\udc02\", got " + prettify(test3));
+ }
+ if(test3.length() != 2){
+ errln("append or length failed for UChar32, expected 2, got " + test3.length());
+ }
+ test3.append((UChar32)0x0074);
+ if(test3 != CharsToUnicodeString("\\uD841\\uDC02t")){
+ errln((UnicodeString)"append failed for UChar32, expected \"\\\\uD841\\\\uDC02t\", got " + prettify(test3));
+ }
+ if(test3.length() != 3){
+ errln((UnicodeString)"append or length failed for UChar32, expected 2, got " + test3.length());
+ }
+
+ // test some UChar32 overloads
+ if( test3.setTo((UChar32)0x10330).length() != 2 ||
+ test3.insert(0, (UChar32)0x20100).length() != 4 ||
+ test3.replace(2, 2, (UChar32)0xe0061).length() != 4 ||
+ (test3 = (UChar32)0x14001).length() != 2
+ ) {
+ errln((UnicodeString)"simple UChar32 overloads for replace, insert, setTo or = failed");
+ }
+
+ {
+ // test moveIndex32()
+ UnicodeString s=UNICODE_STRING("\\U0002f999\\U0001d15f\\u00c4\\u1ed0", 32).unescape();
+
+ if(
+ s.moveIndex32(2, -1)!=0 ||
+ s.moveIndex32(2, 1)!=4 ||
+ s.moveIndex32(2, 2)!=5 ||
+ s.moveIndex32(5, -2)!=2 ||
+ s.moveIndex32(0, -1)!=0 ||
+ s.moveIndex32(6, 1)!=6
+ ) {
+ errln("UnicodeString::moveIndex32() failed");
+ }
+
+ if(s.getChar32Start(1)!=0 || s.getChar32Start(2)!=2) {
+ errln("UnicodeString::getChar32Start() failed");
+ }
+
+ if(s.getChar32Limit(1)!=2 || s.getChar32Limit(2)!=2) {
+ errln("UnicodeString::getChar32Limit() failed");
+ }
+ }
+
+ {
+ // test new 2.2 constructors and setTo function that parallel Java's substring function.
+ UnicodeString src("Hello folks how are you?");
+ UnicodeString target1("how are you?");
+ if (target1 != UnicodeString(src, 12)) {
+ errln("UnicodeString(const UnicodeString&, int32_t) failed");
+ }
+ UnicodeString target2("folks");
+ if (target2 != UnicodeString(src, 6, 5)) {
+ errln("UnicodeString(const UnicodeString&, int32_t, int32_t) failed");
+ }
+ if (target1 != target2.setTo(src, 12)) {
+ errln("UnicodeString::setTo(const UnicodeString&, int32_t) failed");
+ }
+ }
+
+ {
+ // op+ is new in ICU 2.8
+ UnicodeString s=UnicodeString("abc", "")+UnicodeString("def", "")+UnicodeString("ghi", "");
+ if(s!=UnicodeString("abcdefghi", "")) {
+ errln("operator+(UniStr, UniStr) failed");
+ }
+ }
+
+ {
+ // tests for Jitterbug 2360
+ // verify that APIs with source pointer + length accept length == -1
+ // mostly test only where modified, only few functions did not already do this
+ if(UnicodeString("abc", -1, "")!=UnicodeString("abc", "")) {
+ errln("UnicodeString(codepageData, dataLength, codepage) does not work with dataLength==-1");
+ }
+
+ UChar buffer[10]={ 0x61, 0x62, 0x20ac, 0xd900, 0xdc05, 0, 0x62, 0xffff, 0xdbff, 0xdfff };
+ UnicodeString s, t(buffer, -1, LENGTHOF(buffer));
+
+ if(s.setTo(buffer, -1, LENGTHOF(buffer)).length()!=u_strlen(buffer)) {
+ errln("UnicodeString.setTo(buffer, length, capacity) does not work with length==-1");
+ }
+ if(t.length()!=u_strlen(buffer)) {
+ errln("UnicodeString(buffer, length, capacity) does not work with length==-1");
+ }
+
+ if(0!=s.caseCompare(buffer, -1, U_FOLD_CASE_DEFAULT)) {
+ errln("UnicodeString.caseCompare(const UChar *, length, options) does not work with length==-1");
+ }
+ if(0!=s.caseCompare(0, s.length(), buffer, U_FOLD_CASE_DEFAULT)) {
+ errln("UnicodeString.caseCompare(start, _length, const UChar *, options) does not work");
+ }
+
+ buffer[u_strlen(buffer)]=0xe4;
+ UnicodeString u(buffer, -1, LENGTHOF(buffer));
+ if(s.setTo(buffer, -1, LENGTHOF(buffer)).length()!=LENGTHOF(buffer)) {
+ errln("UnicodeString.setTo(buffer without NUL, length, capacity) does not work with length==-1");
+ }
+ if(u.length()!=LENGTHOF(buffer)) {
+ errln("UnicodeString(buffer without NUL, length, capacity) does not work with length==-1");
+ }
+
+ static const char cs[]={ 0x61, (char)0xe4, (char)0x85, 0 };
+ UConverter *cnv;
+ UErrorCode errorCode=U_ZERO_ERROR;
+
+ cnv=ucnv_open("ISO-8859-1", &errorCode);
+ UnicodeString v(cs, -1, cnv, errorCode);
+ ucnv_close(cnv);
+ if(v!=UnicodeString("a\\xe4\\x85").unescape()) {
+ errln("UnicodeString(const char *, length, cnv, errorCode) does not work with length==-1");
+ }
+ }
+}
+
+void
+UnicodeStringTest::TestCompare()
+{
+ UnicodeString test1("this is a test");
+ UnicodeString test2("this is a test");
+ UnicodeString test3("this is a test of the emergency broadcast system");
+ UnicodeString test4("never say, \"this is a test\"!!");
+
+ UnicodeString test5((UChar)0x5000);
+ UnicodeString test6((UChar)0x5100);
+
+ UChar uniChars[] = { 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73,
+ 0x20, 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0 };
+ char chars[] = "this is a test";
+
+ // test operator== and operator!=
+ if (test1 != test2 || test1 == test3 || test1 == test4)
+ errln("operator== or operator!= failed");
+
+ // test operator> and operator<
+ if (test1 > test2 || test1 < test2 || !(test1 < test3) || !(test1 > test4) ||
+ !(test5 < test6)
+ ) {
+ errln("operator> or operator< failed");
+ }
+
+ // test operator>= and operator<=
+ if (!(test1 >= test2) || !(test1 <= test2) || !(test1 <= test3) || !(test1 >= test4))
+ errln("operator>= or operator<= failed");
+
+ // test compare(UnicodeString)
+ if (test1.compare(test2) != 0 || test1.compare(test3) >= 0 || test1.compare(test4) <= 0)
+ errln("compare(UnicodeString) failed");
+
+ //test compare(offset, length, UnicodeString)
+ if(test1.compare(0, 14, test2) != 0 ||
+ test3.compare(0, 14, test2) != 0 ||
+ test4.compare(12, 14, test2) != 0 ||
+ test3.compare(0, 18, test1) <=0 )
+ errln("compare(offset, length, UnicodeString) failes");
+
+ // test compare(UChar*)
+ if (test2.compare(uniChars) != 0 || test3.compare(uniChars) <= 0 || test4.compare(uniChars) >= 0)
+ errln("compare(UChar*) failed");
+
+ // test compare(char*)
+ if (test2.compare(chars) != 0 || test3.compare(chars) <= 0 || test4.compare(chars) >= 0)
+ errln("compare(char*) failed");
+
+ // test compare(UChar*, length)
+ if (test1.compare(uniChars, 4) <= 0 || test1.compare(uniChars, 4) <= 0)
+ errln("compare(UChar*, length) failed");
+
+ // test compare(thisOffset, thisLength, that, thatOffset, thatLength)
+ if (test1.compare(0, 14, test2, 0, 14) != 0
+ || test1.compare(0, 14, test3, 0, 14) != 0
+ || test1.compare(0, 14, test4, 12, 14) != 0)
+ errln("1. compare(thisOffset, thisLength, that, thatOffset, thatLength) failed");
+
+ if (test1.compare(10, 4, test2, 0, 4) >= 0
+ || test1.compare(10, 4, test3, 22, 9) <= 0
+ || test1.compare(10, 4, test4, 22, 4) != 0)
+ errln("2. compare(thisOffset, thisLength, that, thatOffset, thatLength) failed");
+
+ // test compareBetween
+ if (test1.compareBetween(0, 14, test2, 0, 14) != 0 || test1.compareBetween(0, 14, test3, 0, 14) != 0
+ || test1.compareBetween(0, 14, test4, 12, 26) != 0)
+ errln("compareBetween failed");
+
+ if (test1.compareBetween(10, 14, test2, 0, 4) >= 0 || test1.compareBetween(10, 14, test3, 22, 31) <= 0
+ || test1.compareBetween(10, 14, test4, 22, 26) != 0)
+ errln("compareBetween failed");
+
+ // test compare() etc. with strings that share a buffer but are not equal
+ test2=test1; // share the buffer, length() too large for the stackBuffer
+ test2.truncate(1); // change only the length, not the buffer
+ if( test1==test2 || test1<=test2 ||
+ test1.compare(test2)<=0 ||
+ test1.compareCodePointOrder(test2)<=0 ||
+ test1.compareCodePointOrder(0, INT32_MAX, test2)<=0 ||
+ test1.compareCodePointOrder(0, INT32_MAX, test2, 0, INT32_MAX)<=0 ||
+ test1.compareCodePointOrderBetween(0, INT32_MAX, test2, 0, INT32_MAX)<=0 ||
+ test1.caseCompare(test2, U_FOLD_CASE_DEFAULT)<=0
+ ) {
+ errln("UnicodeStrings that share a buffer but have different lengths compare as equal");
+ }
+
+ /* test compareCodePointOrder() */
+ {
+ /* these strings are in ascending order */
+ static const UChar strings[][4]={
+ { 0x61, 0 }, /* U+0061 */
+ { 0x20ac, 0xd801, 0 }, /* U+20ac U+d801 */
+ { 0x20ac, 0xd800, 0xdc00, 0 }, /* U+20ac U+10000 */
+ { 0xd800, 0 }, /* U+d800 */
+ { 0xd800, 0xff61, 0 }, /* U+d800 U+ff61 */
+ { 0xdfff, 0 }, /* U+dfff */
+ { 0xff61, 0xdfff, 0 }, /* U+ff61 U+dfff */
+ { 0xff61, 0xd800, 0xdc02, 0 }, /* U+ff61 U+10002 */
+ { 0xd800, 0xdc02, 0 }, /* U+10002 */
+ { 0xd84d, 0xdc56, 0 } /* U+23456 */
+ };
+ UnicodeString u[20]; // must be at least as long as strings[]
+ int32_t i;
+
+ for(i=0; i<(int32_t)(sizeof(strings)/sizeof(strings[0])); ++i) {
+ u[i]=UnicodeString(TRUE, strings[i], -1);
+ }
+
+ for(i=0; i<(int32_t)(sizeof(strings)/sizeof(strings[0])-1); ++i) {
+ if(u[i].compareCodePointOrder(u[i+1])>=0 || u[i].compareCodePointOrder(0, INT32_MAX, u[i+1].getBuffer())>=0) {
+ errln("error: UnicodeString::compareCodePointOrder() fails for string %d and the following one\n", i);
+ }
+ }
+ }
+
+ /* test caseCompare() */
+ {
+ static const UChar
+ _mixed[]= { 0x61, 0x42, 0x131, 0x3a3, 0xdf, 0x130, 0x49, 0xfb03, 0xd93f, 0xdfff, 0 },
+ _otherDefault[]= { 0x41, 0x62, 0x131, 0x3c3, 0x73, 0x53, 0x69, 0x307, 0x69, 0x46, 0x66, 0x49, 0xd93f, 0xdfff, 0 },
+ _otherExcludeSpecialI[]={ 0x41, 0x62, 0x131, 0x3c3, 0x53, 0x73, 0x69, 0x131, 0x66, 0x46, 0x69, 0xd93f, 0xdfff, 0 },
+ _different[]= { 0x41, 0x62, 0x131, 0x3c3, 0x73, 0x53, 0x130, 0x49, 0x46, 0x66, 0x49, 0xd93f, 0xdffd, 0 };
+
+ UnicodeString
+ mixed(TRUE, _mixed, -1),
+ otherDefault(TRUE, _otherDefault, -1),
+ otherExcludeSpecialI(TRUE, _otherExcludeSpecialI, -1),
+ different(TRUE, _different, -1);
+
+ int8_t result;
+
+ /* test caseCompare() */
+ result=mixed.caseCompare(otherDefault, U_FOLD_CASE_DEFAULT);
+ if(result!=0 || 0!=mixed.caseCompareBetween(0, INT32_MAX, otherDefault, 0, INT32_MAX, U_FOLD_CASE_DEFAULT)) {
+ errln("error: mixed.caseCompare(other, default)=%ld instead of 0\n", result);
+ }
+ result=mixed.caseCompare(otherExcludeSpecialI, U_FOLD_CASE_EXCLUDE_SPECIAL_I);
+ if(result!=0) {
+ errln("error: mixed.caseCompare(otherExcludeSpecialI, U_FOLD_CASE_EXCLUDE_SPECIAL_I)=%ld instead of 0\n", result);
+ }
+ result=mixed.caseCompare(otherDefault, U_FOLD_CASE_EXCLUDE_SPECIAL_I);
+ if(result==0 || 0==mixed.caseCompareBetween(0, INT32_MAX, otherDefault, 0, INT32_MAX, U_FOLD_CASE_EXCLUDE_SPECIAL_I)) {
+ errln("error: mixed.caseCompare(other, U_FOLD_CASE_EXCLUDE_SPECIAL_I)=0 instead of !=0\n");
+ }
+
+ /* test caseCompare() */
+ result=mixed.caseCompare(different, U_FOLD_CASE_DEFAULT);
+ if(result<=0) {
+ errln("error: mixed.caseCompare(different, default)=%ld instead of positive\n", result);
+ }
+
+ /* test caseCompare() - include the folded sharp s (U+00df) with different lengths */
+ result=mixed.caseCompare(1, 4, different, 1, 5, U_FOLD_CASE_DEFAULT);
+ if(result!=0 || 0!=mixed.caseCompareBetween(1, 5, different, 1, 6, U_FOLD_CASE_DEFAULT)) {
+ errln("error: mixed.caseCompare(mixed, 1, 4, different, 1, 5, default)=%ld instead of 0\n", result);
+ }
+
+ /* test caseCompare() - stop in the middle of the sharp s (U+00df) */
+ result=mixed.caseCompare(1, 4, different, 1, 4, U_FOLD_CASE_DEFAULT);
+ if(result<=0) {
+ errln("error: mixed.caseCompare(1, 4, different, 1, 4, default)=%ld instead of positive\n", result);
+ }
+ }
+
+ // test that srcLength=-1 is handled in functions that
+ // take input const UChar */int32_t srcLength (j785)
+ {
+ static const UChar u[]={ 0x61, 0x308, 0x62, 0 };
+ UnicodeString s=UNICODE_STRING("a\\u0308b", 8).unescape();
+
+ if(s.compare(u, -1)!=0 || s.compare(0, 999, u, 0, -1)!=0) {
+ errln("error UnicodeString::compare(..., const UChar *, srcLength=-1) does not work");
+ }
+
+ if(s.compareCodePointOrder(u, -1)!=0 || s.compareCodePointOrder(0, 999, u, 0, -1)!=0) {
+ errln("error UnicodeString::compareCodePointOrder(..., const UChar *, srcLength=-1, ...) does not work");
+ }
+
+ if(s.caseCompare(u, -1, U_FOLD_CASE_DEFAULT)!=0 || s.caseCompare(0, 999, u, 0, -1, U_FOLD_CASE_DEFAULT)!=0) {
+ errln("error UnicodeString::caseCompare(..., const UChar *, srcLength=-1, ...) does not work");
+ }
+
+ if(s.indexOf(u, 1, -1, 0, 999)!=1 || s.indexOf(u+1, -1, 0, 999)!=1 || s.indexOf(u+1, -1, 0)!=1) {
+ errln("error UnicodeString::indexOf(const UChar *, srcLength=-1, ...) does not work");
+ }
+
+ if(s.lastIndexOf(u, 1, -1, 0, 999)!=1 || s.lastIndexOf(u+1, -1, 0, 999)!=1 || s.lastIndexOf(u+1, -1, 0)!=1) {
+ errln("error UnicodeString::lastIndexOf(const UChar *, srcLength=-1, ...) does not work");
+ }
+
+ UnicodeString s2, s3;
+ s2.replace(0, 0, u+1, -1);
+ s3.replace(0, 0, u, 1, -1);
+ if(s.compare(1, 999, s2)!=0 || s2!=s3) {
+ errln("error UnicodeString::replace(..., const UChar *, srcLength=-1, ...) does not work");
+ }
+ }
+}
+
+void
+UnicodeStringTest::TestExtract()
+{
+ UnicodeString test1("Now is the time for all good men to come to the aid of their country.", "");
+ UnicodeString test2;
+ UChar test3[13] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 10, 11, 12, 13};
+ char test4[13] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 10, 11, 12, 13};
+ UnicodeString test5;
+ char test6[13] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 10, 11, 12, 13};
+
+ test1.extract(11, 12, test2);
+ test1.extract(11, 12, test3);
+ if (test1.extract(11, 12, test4) != 12 || test4[12] != 0) {
+ errln("UnicodeString.extract(char *) failed to return the correct size of destination buffer.");
+ }
+
+ // test proper pinning in extractBetween()
+ test1.extractBetween(-3, 7, test5);
+ if(test5!=UNICODE_STRING("Now is ", 7)) {
+ errln("UnicodeString.extractBetween(-3, 7) did not pin properly.");
+ }
+
+ test1.extractBetween(11, 23, test5);
+ if (test1.extract(60, 71, test6) != 9) {
+ errln("UnicodeString.extract() failed to return the correct size of destination buffer for end of buffer.");
+ }
+ if (test1.extract(11, 12, test6) != 12) {
+ errln("UnicodeString.extract() failed to return the correct size of destination buffer.");
+ }
+
+ // convert test4 back to Unicode for comparison
+ UnicodeString test4b(test4, 12);
+
+ if (test1.extract(11, 12, (char *)NULL) != 12) {
+ errln("UnicodeString.extract(NULL) failed to return the correct size of destination buffer.");
+ }
+ if (test1.extract(11, -1, test6) != 0) {
+ errln("UnicodeString.extract(-1) failed to stop reading the string.");
+ }
+
+ for (int32_t i = 0; i < 12; i++) {
+ if (test1.charAt((int32_t)(11 + i)) != test2.charAt(i)) {
+ errln(UnicodeString("extracting into a UnicodeString failed at position ") + i);
+ break;
+ }
+ if (test1.charAt((int32_t)(11 + i)) != test3[i]) {
+ errln(UnicodeString("extracting into an array of UChar failed at position ") + i);
+ break;
+ }
+ if (((char)test1.charAt((int32_t)(11 + i))) != test4b.charAt(i)) {
+ errln(UnicodeString("extracting into an array of char failed at position ") + i);
+ break;
+ }
+ if (test1.charAt((int32_t)(11 + i)) != test5.charAt(i)) {
+ errln(UnicodeString("extracting with extractBetween failed at position ") + i);
+ break;
+ }
+ }
+
+ // test preflighting and overflows with invariant conversion
+ if (test1.extract(0, 10, (char *)NULL, "") != 10) {
+ errln("UnicodeString.extract(0, 10, (char *)NULL, \"\") != 10");
+ }
+
+ test4[2] = (char)0xff;
+ if (test1.extract(0, 10, test4, 2, "") != 10) {
+ errln("UnicodeString.extract(0, 10, test4, 2, \"\") != 10");
+ }
+ if (test4[2] != (char)0xff) {
+ errln("UnicodeString.extract(0, 10, test4, 2, \"\") overwrote test4[2]");
+ }
+
+ {
+ // test new, NUL-terminating extract() function
+ UnicodeString s("terminate", "");
+ UChar dest[20]={
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5,
+ 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5
+ };
+ UErrorCode errorCode;
+ int32_t length;
+
+ errorCode=U_ZERO_ERROR;
+ length=s.extract((UChar *)NULL, 0, errorCode);
+ if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=s.length()) {
+ errln("UnicodeString.extract(NULL, 0)==%d (%s) expected %d (U_BUFFER_OVERFLOW_ERROR)", length, s.length(), u_errorName(errorCode));
+ }
+
+ errorCode=U_ZERO_ERROR;
+ length=s.extract(dest, s.length()-1, errorCode);
+ if(errorCode!=U_BUFFER_OVERFLOW_ERROR || length!=s.length()) {
+ errln("UnicodeString.extract(dest too short)==%d (%s) expected %d (U_BUFFER_OVERFLOW_ERROR)",
+ length, u_errorName(errorCode), s.length());
+ }
+
+ errorCode=U_ZERO_ERROR;
+ length=s.extract(dest, s.length(), errorCode);
+ if(errorCode!=U_STRING_NOT_TERMINATED_WARNING || length!=s.length()) {
+ errln("UnicodeString.extract(dest just right without NUL)==%d (%s) expected %d (U_STRING_NOT_TERMINATED_WARNING)",
+ length, u_errorName(errorCode), s.length());
+ }
+ if(dest[length-1]!=s[length-1] || dest[length]!=0xa5) {
+ errln("UnicodeString.extract(dest just right without NUL) did not extract the string correctly");
+ }
+
+ errorCode=U_ZERO_ERROR;
+ length=s.extract(dest, s.length()+1, errorCode);
+ if(errorCode!=U_ZERO_ERROR || length!=s.length()) {
+ errln("UnicodeString.extract(dest large enough)==%d (%s) expected %d (U_ZERO_ERROR)",
+ length, u_errorName(errorCode), s.length());
+ }
+ if(dest[length-1]!=s[length-1] || dest[length]!=0 || dest[length+1]!=0xa5) {
+ errln("UnicodeString.extract(dest large enough) did not extract the string correctly");
+ }
+ }
+
+ {
+ // test new UConverter extract() and constructor
+ UnicodeString s=UNICODE_STRING("\\U0002f999\\U0001d15f\\u00c4\\u1ed0", 32).unescape();
+ char buffer[32];
+ static const char expect[]={
+ (char)0xf0, (char)0xaf, (char)0xa6, (char)0x99,
+ (char)0xf0, (char)0x9d, (char)0x85, (char)0x9f,
+ (char)0xc3, (char)0x84,
+ (char)0xe1, (char)0xbb, (char)0x90
+ };
+ UErrorCode errorCode=U_ZERO_ERROR;
+ UConverter *cnv=ucnv_open("UTF-8", &errorCode);
+ int32_t length;
+
+ if(U_SUCCESS(errorCode)) {
+ // test preflighting
+ if( (length=s.extract(NULL, 0, cnv, errorCode))!=13 ||
+ errorCode!=U_BUFFER_OVERFLOW_ERROR
+ ) {
+ errln("UnicodeString::extract(NULL, UConverter) preflighting failed (length=%ld, %s)",
+ length, u_errorName(errorCode));
+ }
+ errorCode=U_ZERO_ERROR;
+ if( (length=s.extract(buffer, 2, cnv, errorCode))!=13 ||
+ errorCode!=U_BUFFER_OVERFLOW_ERROR
+ ) {
+ errln("UnicodeString::extract(too small, UConverter) preflighting failed (length=%ld, %s)",
+ length, u_errorName(errorCode));
+ }
+
+ // try error cases
+ errorCode=U_ZERO_ERROR;
+ if( s.extract(NULL, 2, cnv, errorCode)==13 || U_SUCCESS(errorCode)) {
+ errln("UnicodeString::extract(UConverter) succeeded with an illegal destination");
+ }
+ errorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ if( s.extract(NULL, 0, cnv, errorCode)==13 || U_SUCCESS(errorCode)) {
+ errln("UnicodeString::extract(UConverter) succeeded with a previous error code");
+ }
+ errorCode=U_ZERO_ERROR;
+
+ // extract for real
+ if( (length=s.extract(buffer, sizeof(buffer), cnv, errorCode))!=13 ||
+ uprv_memcmp(buffer, expect, 13)!=0 ||
+ buffer[13]!=0 ||
+ U_FAILURE(errorCode)
+ ) {
+ errln("UnicodeString::extract(UConverter) conversion failed (length=%ld, %s)",
+ length, u_errorName(errorCode));
+ }
+ // Test again with just the converter name.
+ if( (length=s.extract(0, s.length(), buffer, sizeof(buffer), "UTF-8"))!=13 ||
+ uprv_memcmp(buffer, expect, 13)!=0 ||
+ buffer[13]!=0 ||
+ U_FAILURE(errorCode)
+ ) {
+ errln("UnicodeString::extract(\"UTF-8\") conversion failed (length=%ld, %s)",
+ length, u_errorName(errorCode));
+ }
+
+ // try the constructor
+ UnicodeString t(expect, sizeof(expect), cnv, errorCode);
+ if(U_FAILURE(errorCode) || s!=t) {
+ errln("UnicodeString(UConverter) conversion failed (%s)",
+ u_errorName(errorCode));
+ }
+
+ ucnv_close(cnv);
+ }
+ }
+}
+
+void
+UnicodeStringTest::TestRemoveReplace()
+{
+ UnicodeString test1("The rain in Spain stays mainly on the plain");
+ UnicodeString test2("eat SPAMburgers!");
+ UChar test3[] = { 0x53, 0x50, 0x41, 0x4d, 0x4d, 0 };
+ char test4[] = "SPAM";
+ UnicodeString& test5 = test1;
+
+ test1.replace(4, 4, test2, 4, 4);
+ test1.replace(12, 5, test3, 4);
+ test3[4] = 0;
+ test1.replace(17, 4, test3);
+ test1.replace(23, 4, test4);
+ test1.replaceBetween(37, 42, test2, 4, 8);
+
+ if (test1 != "The SPAM in SPAM SPAMs SPAMly on the SPAM")
+ errln("One of the replace methods failed:\n"
+ " expected \"The SPAM in SPAM SPAMs SPAMly on the SPAM\",\n"
+ " got \"" + test1 + "\"");
+
+ test1.remove(21, 1);
+ test1.removeBetween(26, 28);
+
+ if (test1 != "The SPAM in SPAM SPAM SPAM on the SPAM")
+ errln("One of the remove methods failed:\n"
+ " expected \"The SPAM in SPAM SPAM SPAM on the SPAM\",\n"
+ " got \"" + test1 + "\"");
+
+ for (int32_t i = 0; i < test1.length(); i++) {
+ if (test5[i] != 0x53 && test5[i] != 0x50 && test5[i] != 0x41 && test5[i] != 0x4d && test5[i] != 0x20) {
+ test1.setCharAt(i, 0x78);
+ }
+ }
+
+ if (test1 != "xxx SPAM xx SPAM SPAM SPAM xx xxx SPAM")
+ errln("One of the remove methods failed:\n"
+ " expected \"xxx SPAM xx SPAM SPAM SPAM xx xxx SPAM\",\n"
+ " got \"" + test1 + "\"");
+
+ test1.remove();
+ if (test1.length() != 0)
+ errln("Remove() failed: expected empty string, got \"" + test1 + "\"");
+}
+
+void
+UnicodeStringTest::TestSearching()
+{
+ UnicodeString test1("test test ttest tetest testesteststt");
+ UnicodeString test2("test");
+ UChar testChar = 0x74;
+
+ UChar32 testChar32 = 0x20402;
+ UChar testData[]={
+ // 0 1 2 3 4 5 6 7
+ 0xd841, 0xdc02, 0x0071, 0xdc02, 0xd841, 0x0071, 0xd841, 0xdc02,
+
+ // 8 9 10 11 12 13 14 15
+ 0x0071, 0x0072, 0xd841, 0xdc02, 0x0071, 0xd841, 0xdc02, 0x0071,
+
+ // 16 17 18 19
+ 0xdc02, 0xd841, 0x0073, 0x0000
+ };
+ UnicodeString test3(testData);
+ UnicodeString test4(testChar32);
+
+ uint16_t occurrences = 0;
+ int32_t startPos = 0;
+ for ( ;
+ startPos != -1 && startPos < test1.length();
+ (startPos = test1.indexOf(test2, startPos)) != -1 ? (++occurrences, startPos += 4) : 0)
+ ;
+ if (occurrences != 6)
+ errln("indexOf failed: expected to find 6 occurrences, found " + occurrences);
+
+ for ( occurrences = 0, startPos = 10;
+ startPos != -1 && startPos < test1.length();
+ (startPos = test1.indexOf(test2, startPos)) != -1 ? (++occurrences, startPos += 4) : 0)
+ ;
+ if (occurrences != 4)
+ errln("indexOf with starting offset failed: expected to find 4 occurrences, found " + occurrences);
+
+ int32_t endPos = 28;
+ for ( occurrences = 0, startPos = 5;
+ startPos != -1 && startPos < test1.length();
+ (startPos = test1.indexOf(test2, startPos, endPos - startPos)) != -1 ? (++occurrences, startPos += 4) : 0)
+ ;
+ if (occurrences != 4)
+ errln("indexOf with starting and ending offsets failed: expected to find 4 occurrences, found " + occurrences);
+
+ //using UChar32 string
+ for ( startPos=0, occurrences=0;
+ startPos != -1 && startPos < test3.length();
+ (startPos = test3.indexOf(test4, startPos)) != -1 ? (++occurrences, startPos += 2) : 0)
+ ;
+ if (occurrences != 4)
+ errln((UnicodeString)"indexOf failed: expected to find 4 occurrences, found " + occurrences);
+
+ for ( startPos=10, occurrences=0;
+ startPos != -1 && startPos < test3.length();
+ (startPos = test3.indexOf(test4, startPos)) != -1 ? (++occurrences, startPos += 2) : 0)
+ ;
+ if (occurrences != 2)
+ errln("indexOf failed: expected to find 2 occurrences, found " + occurrences);
+ //---
+
+ for ( occurrences = 0, startPos = 0;
+ startPos != -1 && startPos < test1.length();
+ (startPos = test1.indexOf(testChar, startPos)) != -1 ? (++occurrences, startPos += 1) : 0)
+ ;
+ if (occurrences != 16)
+ errln("indexOf with character failed: expected to find 16 occurrences, found " + occurrences);
+
+ for ( occurrences = 0, startPos = 10;
+ startPos != -1 && startPos < test1.length();
+ (startPos = test1.indexOf(testChar, startPos)) != -1 ? (++occurrences, startPos += 1) : 0)
+ ;
+ if (occurrences != 12)
+ errln("indexOf with character & start offset failed: expected to find 12 occurrences, found " + occurrences);
+
+ for ( occurrences = 0, startPos = 5, endPos = 28;
+ startPos != -1 && startPos < test1.length();
+ (startPos = test1.indexOf(testChar, startPos, endPos - startPos)) != -1 ? (++occurrences, startPos += 1) : 0)
+ ;
+ if (occurrences != 10)
+ errln("indexOf with character & start & end offsets failed: expected to find 10 occurrences, found " + occurrences);
+
+ //testing for UChar32
+ UnicodeString subString;
+ for( occurrences =0, startPos=0; startPos < test3.length(); startPos +=1){
+ subString.append(test3, startPos, test3.length());
+ if(subString.indexOf(testChar32) != -1 ){
+ ++occurrences;
+ }
+ subString.remove();
+ }
+ if (occurrences != 14)
+ errln((UnicodeString)"indexOf failed: expected to find 14 occurrences, found " + occurrences);
+
+ for ( occurrences = 0, startPos = 0;
+ startPos != -1 && startPos < test3.length();
+ (startPos = test3.indexOf(testChar32, startPos)) != -1 ? (++occurrences, startPos += 1) : 0)
+ ;
+ if (occurrences != 4)
+ errln((UnicodeString)"indexOf failed: expected to find 4 occurrences, found " + occurrences);
+
+ endPos=test3.length();
+ for ( occurrences = 0, startPos = 5;
+ startPos != -1 && startPos < test3.length();
+ (startPos = test3.indexOf(testChar32, startPos, endPos - startPos)) != -1 ? (++occurrences, startPos += 1) : 0)
+ ;
+ if (occurrences != 3)
+ errln((UnicodeString)"indexOf with character & start & end offsets failed: expected to find 2 occurrences, found " + occurrences);
+ //---
+
+ if(test1.lastIndexOf(test2)!=29) {
+ errln("test1.lastIndexOf(test2)!=29");
+ }
+
+ if(test1.lastIndexOf(test2, 15)!=29 || test1.lastIndexOf(test2, 29)!=29 || test1.lastIndexOf(test2, 30)!=-1) {
+ errln("test1.lastIndexOf(test2, start) failed");
+ }
+
+ for ( occurrences = 0, startPos = 32;
+ startPos != -1;
+ (startPos = test1.lastIndexOf(test2, 5, startPos - 5)) != -1 ? ++occurrences : 0)
+ ;
+ if (occurrences != 4)
+ errln("lastIndexOf with starting and ending offsets failed: expected to find 4 occurrences, found " + occurrences);
+
+ for ( occurrences = 0, startPos = 32;
+ startPos != -1;
+ (startPos = test1.lastIndexOf(testChar, 5, startPos - 5)) != -1 ? ++occurrences : 0)
+ ;
+ if (occurrences != 11)
+ errln("lastIndexOf with character & start & end offsets failed: expected to find 11 occurrences, found " + occurrences);
+
+ //testing UChar32
+ startPos=test3.length();
+ for ( occurrences = 0;
+ startPos != -1;
+ (startPos = test3.lastIndexOf(testChar32, 5, startPos - 5)) != -1 ? ++occurrences : 0)
+ ;
+ if (occurrences != 3)
+ errln((UnicodeString)"lastIndexOf with character & start & end offsets failed: expected to find 3 occurrences, found " + occurrences);
+
+
+ for ( occurrences = 0, endPos = test3.length(); endPos > 0; endPos -= 1){
+ subString.remove();
+ subString.append(test3, 0, endPos);
+ if(subString.lastIndexOf(testChar32) != -1 ){
+ ++occurrences;
+ }
+ }
+ if (occurrences != 18)
+ errln((UnicodeString)"indexOf failed: expected to find 18 occurrences, found " + occurrences);
+ //---
+
+ // test that indexOf(UChar32) and lastIndexOf(UChar32)
+ // do not find surrogate code points when they are part of matched pairs
+ // (= part of supplementary code points)
+ // Jitterbug 1542
+ if(test3.indexOf((UChar32)0xd841) != 4 || test3.indexOf((UChar32)0xdc02) != 3) {
+ errln("error: UnicodeString::indexOf(UChar32 surrogate) finds a partial supplementary code point");
+ }
+ if( UnicodeString(test3, 0, 17).lastIndexOf((UChar)0xd841, 0) != 4 ||
+ UnicodeString(test3, 0, 17).lastIndexOf((UChar32)0xd841, 2) != 4 ||
+ test3.lastIndexOf((UChar32)0xd841, 0, 17) != 4 || test3.lastIndexOf((UChar32)0xdc02, 0, 17) != 16
+ ) {
+ errln("error: UnicodeString::lastIndexOf(UChar32 surrogate) finds a partial supplementary code point");
+ }
+}
+
+void
+UnicodeStringTest::TestSpacePadding()
+{
+ UnicodeString test1("hello");
+ UnicodeString test2(" there");
+ UnicodeString test3("Hi! How ya doin'? Beautiful day, isn't it?");
+ UnicodeString test4;
+ UBool returnVal;
+ UnicodeString expectedValue;
+
+ returnVal = test1.padLeading(15);
+ expectedValue = " hello";
+ if (returnVal == FALSE || test1 != expectedValue)
+ errln("padLeading() failed: expected \"" + expectedValue + "\", got \"" + test1 + "\".");
+
+ returnVal = test2.padTrailing(15);
+ expectedValue = " there ";
+ if (returnVal == FALSE || test2 != expectedValue)
+ errln("padTrailing() failed: expected \"" + expectedValue + "\", got \"" + test2 + "\".");
+
+ expectedValue = test3;
+ returnVal = test3.padTrailing(15);
+ if (returnVal == TRUE || test3 != expectedValue)
+ errln("padTrailing() failed: expected \"" + expectedValue + "\", got \"" + test3 + "\".");
+
+ expectedValue = "hello";
+ test4.setTo(test1).trim();
+
+ if (test4 != expectedValue || test1 == expectedValue || test4 != expectedValue)
+ errln("trim(UnicodeString&) failed");
+
+ test1.trim();
+ if (test1 != expectedValue)
+ errln("trim() failed: expected \"" + expectedValue + "\", got \"" + test1 + "\".");
+
+ test2.trim();
+ expectedValue = "there";
+ if (test2 != expectedValue)
+ errln("trim() failed: expected \"" + expectedValue + "\", got \"" + test2 + "\".");
+
+ test3.trim();
+ expectedValue = "Hi! How ya doin'? Beautiful day, isn't it?";
+ if (test3 != expectedValue)
+ errln("trim() failed: expected \"" + expectedValue + "\", got \"" + test3 + "\".");
+
+ returnVal = test1.truncate(15);
+ expectedValue = "hello";
+ if (returnVal == TRUE || test1 != expectedValue)
+ errln("truncate() failed: expected \"" + expectedValue + "\", got \"" + test1 + "\".");
+
+ returnVal = test2.truncate(15);
+ expectedValue = "there";
+ if (returnVal == TRUE || test2 != expectedValue)
+ errln("truncate() failed: expected \"" + expectedValue + "\", got \"" + test2 + "\".");
+
+ returnVal = test3.truncate(15);
+ expectedValue = "Hi! How ya doi";
+ if (returnVal == FALSE || test3 != expectedValue)
+ errln("truncate() failed: expected \"" + expectedValue + "\", got \"" + test3 + "\".");
+}
+
+void
+UnicodeStringTest::TestPrefixAndSuffix()
+{
+ UnicodeString test1("Now is the time for all good men to come to the aid of their country.");
+ UnicodeString test2("Now");
+ UnicodeString test3("country.");
+ UnicodeString test4("count");
+
+ if (!test1.startsWith(test2) || !test1.startsWith(test2, 0, test2.length())) {
+ errln("startsWith() failed: \"" + test2 + "\" should be a prefix of \"" + test1 + "\".");
+ }
+
+ if (test1.startsWith(test3) ||
+ test1.startsWith(test3.getBuffer(), test3.length()) ||
+ test1.startsWith(test3.getTerminatedBuffer(), 0, -1)
+ ) {
+ errln("startsWith() failed: \"" + test3 + "\" shouldn't be a prefix of \"" + test1 + "\".");
+ }
+
+ if (test1.endsWith(test2)) {
+ errln("endsWith() failed: \"" + test2 + "\" shouldn't be a suffix of \"" + test1 + "\".");
+ }
+
+ if (!test1.endsWith(test3)) {
+ errln("endsWith(test3) failed: \"" + test3 + "\" should be a suffix of \"" + test1 + "\".");
+ }
+ if (!test1.endsWith(test3, 0, INT32_MAX)) {
+ errln("endsWith(test3, 0, INT32_MAX) failed: \"" + test3 + "\" should be a suffix of \"" + test1 + "\".");
+ }
+
+ if(!test1.endsWith(test3.getBuffer(), test3.length())) {
+ errln("endsWith(test3.getBuffer(), test3.length()) failed: \"" + test3 + "\" should be a suffix of \"" + test1 + "\".");
+ }
+ if(!test1.endsWith(test3.getTerminatedBuffer(), 0, -1)) {
+ errln("endsWith(test3.getTerminatedBuffer(), 0, -1) failed: \"" + test3 + "\" should be a suffix of \"" + test1 + "\".");
+ }
+
+ if (!test3.startsWith(test4)) {
+ errln("endsWith(test4) failed: \"" + test4 + "\" should be a prefix of \"" + test3 + "\".");
+ }
+
+ if (test4.startsWith(test3)) {
+ errln("startsWith(test3) failed: \"" + test3 + "\" shouldn't be a prefix of \"" + test4 + "\".");
+ }
+}
+
+void
+UnicodeStringTest::TestFindAndReplace()
+{
+ UnicodeString test1("One potato, two potato, three potato, four\n");
+ UnicodeString test2("potato");
+ UnicodeString test3("MISSISSIPPI");
+
+ UnicodeString expectedValue;
+
+ test1.findAndReplace(test2, test3);
+ expectedValue = "One MISSISSIPPI, two MISSISSIPPI, three MISSISSIPPI, four\n";
+ if (test1 != expectedValue)
+ errln("findAndReplace failed: expected \"" + expectedValue + "\", got \"" + test1 + "\".");
+ test1.findAndReplace(2, 32, test3, test2);
+ expectedValue = "One potato, two potato, three MISSISSIPPI, four\n";
+ if (test1 != expectedValue)
+ errln("findAndReplace failed: expected \"" + expectedValue + "\", got \"" + test1 + "\".");
+}
+
+void
+UnicodeStringTest::TestReverse()
+{
+ UnicodeString test("backwards words say to used I");
+
+ test.reverse();
+ test.reverse(2, 4);
+ test.reverse(7, 2);
+ test.reverse(10, 3);
+ test.reverse(14, 5);
+ test.reverse(20, 9);
+
+ if (test != "I used to say words backwards")
+ errln("reverse() failed: Expected \"I used to say words backwards\",\n got \""
+ + test + "\"");
+
+ test=UNICODE_STRING("\\U0002f999\\U0001d15f\\u00c4\\u1ed0", 32).unescape();
+ test.reverse();
+ if(test.char32At(0)!=0x1ed0 || test.char32At(1)!=0xc4 || test.char32At(2)!=0x1d15f || test.char32At(4)!=0x2f999) {
+ errln("reverse() failed with supplementary characters");
+ }
+}
+
+void
+UnicodeStringTest::TestMiscellaneous()
+{
+ UnicodeString test1("This is a test");
+ UnicodeString test2("This is a test");
+ UnicodeString test3("Me too!");
+
+ // test getBuffer(minCapacity) and releaseBuffer()
+ test1=UnicodeString(); // make sure that it starts with its stackBuffer
+ UChar *p=test1.getBuffer(20);
+ if(test1.getCapacity()<20) {
+ errln("UnicodeString::getBuffer(20).getCapacity()<20");
+ }
+
+ test1.append((UChar)7); // must not be able to modify the string here
+ test1.setCharAt(3, 7);
+ test1.reverse();
+ if( test1.length()!=0 ||
+ test1.charAt(0)!=0xffff || test1.charAt(3)!=0xffff ||
+ test1.getBuffer(10)!=0 || test1.getBuffer()!=0
+ ) {
+ errln("UnicodeString::getBuffer(minCapacity) allows read or write access to the UnicodeString");
+ }
+
+ p[0]=1;
+ p[1]=2;
+ p[2]=3;
+ test1.releaseBuffer(3);
+ test1.append((UChar)4);
+
+ if(test1.length()!=4 || test1.charAt(0)!=1 || test1.charAt(1)!=2 || test1.charAt(2)!=3 || test1.charAt(3)!=4) {
+ errln("UnicodeString::releaseBuffer(newLength) does not properly reallow access to the UnicodeString");
+ }
+
+ // test releaseBuffer() without getBuffer(minCapacity) - must not have any effect
+ test1.releaseBuffer(1);
+ if(test1.length()!=4 || test1.charAt(0)!=1 || test1.charAt(1)!=2 || test1.charAt(2)!=3 || test1.charAt(3)!=4) {
+ errln("UnicodeString::releaseBuffer(newLength) without getBuffer(minCapacity) changed the UnicodeString");
+ }
+
+ // test getBuffer(const)
+ const UChar *q=test1.getBuffer(), *r=test1.getBuffer();
+ if( test1.length()!=4 ||
+ q[0]!=1 || q[1]!=2 || q[2]!=3 || q[3]!=4 ||
+ r[0]!=1 || r[1]!=2 || r[2]!=3 || r[3]!=4
+ ) {
+ errln("UnicodeString::getBuffer(const) does not return a usable buffer pointer");
+ }
+
+ // test releaseBuffer() with a NUL-terminated buffer
+ test1.getBuffer(20)[2]=0;
+ test1.releaseBuffer(); // implicit -1
+ if(test1.length()!=2 || test1.charAt(0)!=1 || test1.charAt(1) !=2) {
+ errln("UnicodeString::releaseBuffer(-1) does not properly set the length of the UnicodeString");
+ }
+
+ // test releaseBuffer() with a non-NUL-terminated buffer
+ p=test1.getBuffer(256);
+ for(int32_t i=0; i<test1.getCapacity(); ++i) {
+ p[i]=(UChar)1; // fill the buffer with all non-NUL code units
+ }
+ test1.releaseBuffer(); // implicit -1
+ if(test1.length()!=test1.getCapacity() || test1.charAt(1)!=1 || test1.charAt(100)!=1 || test1.charAt(test1.getCapacity()-1)!=1) {
+ errln("UnicodeString::releaseBuffer(-1 but no NUL) does not properly set the length of the UnicodeString");
+ }
+
+ // test getTerminatedBuffer()
+ test1=UnicodeString("This is another test.", "");
+ test2=UnicodeString("This is another test.", "");
+ q=test1.getTerminatedBuffer();
+ if(q[test1.length()]!=0 || test1!=test2 || test2.compare(q, -1)!=0) {
+ errln("getTerminatedBuffer()[length]!=0");
+ }
+
+ const UChar u[]={ 5, 6, 7, 8, 0 };
+ test1.setTo(FALSE, u, 3);
+ q=test1.getTerminatedBuffer();
+ if(q==u || q[0]!=5 || q[1]!=6 || q[2]!=7 || q[3]!=0) {
+ errln("UnicodeString(u[3]).getTerminatedBuffer() returns a bad buffer");
+ }
+
+ test1.setTo(TRUE, u, -1);
+ q=test1.getTerminatedBuffer();
+ if(q!=u || test1.length()!=4 || q[3]!=8 || q[4]!=0) {
+ errln("UnicodeString(u[-1]).getTerminatedBuffer() returns a bad buffer");
+ }
+
+ test1=UNICODE_STRING("la", 2);
+ test1.append(UNICODE_STRING(" lila", 5).getTerminatedBuffer(), 0, -1);
+ if(test1!=UNICODE_STRING("la lila", 7)) {
+ errln("UnicodeString::append(const UChar *, start, length) failed");
+ }
+
+ test1.insert(3, UNICODE_STRING("dudum ", 6), 0, INT32_MAX);
+ if(test1!=UNICODE_STRING("la dudum lila", 13)) {
+ errln("UnicodeString::insert(start, const UniStr &, start, length) failed");
+ }
+
+ static const UChar ucs[]={ 0x68, 0x6d, 0x20, 0 };
+ test1.insert(9, ucs, -1);
+ if(test1!=UNICODE_STRING("la dudum hm lila", 16)) {
+ errln("UnicodeString::insert(start, const UChar *, length) failed");
+ }
+
+ test1.replace(9, 2, (UChar)0x2b);
+ if(test1!=UNICODE_STRING("la dudum + lila", 15)) {
+ errln("UnicodeString::replace(start, length, UChar) failed");
+ }
+
+ if(test1.hasMetaData() || UnicodeString().hasMetaData()) {
+ errln("UnicodeString::hasMetaData() returns TRUE");
+ }
+}
+
+void
+UnicodeStringTest::TestStackAllocation()
+{
+ UChar testString[] ={
+ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x63, 0x72, 0x61, 0x7a, 0x79, 0x20, 0x74, 0x65, 0x73, 0x74, 0x2e, 0 };
+ UChar guardWord = 0x4DED;
+ UnicodeString* test = 0;
+
+ test = new UnicodeString(testString);
+ if (*test != "This is a crazy test.")
+ errln("Test string failed to initialize properly.");
+ if (guardWord != 0x04DED)
+ errln("Test string initialization overwrote guard word!");
+
+ test->insert(8, "only ");
+ test->remove(15, 6);
+ if (*test != "This is only a test.")
+ errln("Manipulation of test string failed to work right.");
+ if (guardWord != 0x4DED)
+ errln("Manipulation of test string overwrote guard word!");
+
+ // we have to deinitialize and release the backing store by calling the destructor
+ // explicitly, since we can't overload operator delete
+ delete test;
+
+ UChar workingBuffer[] = {
+ 0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
+ 0x66, 0x6f, 0x72, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6d, 0x65, 0x6e, 0x20, 0x74, 0x6f, 0x20,
+ 0x63, 0x6f, 0x6d, 0x65, 0xffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ UChar guardWord2 = 0x4DED;
+
+ test = new UnicodeString(workingBuffer, 35, 100);
+ if (*test != "Now is the time for all men to come")
+ errln("Stack-allocated backing store failed to initialize correctly.");
+ if (guardWord2 != 0x4DED)
+ errln("Stack-allocated backing store overwrote guard word!");
+
+ test->insert(24, "good ");
+ if (*test != "Now is the time for all good men to come")
+ errln("insert() on stack-allocated UnicodeString didn't work right");
+ if (guardWord2 != 0x4DED)
+ errln("insert() on stack-allocated UnicodeString overwrote guard word!");
+
+ if (workingBuffer[24] != 0x67)
+ errln("insert() on stack-allocated UnicodeString didn't affect backing store");
+
+ *test += " to the aid of their country.";
+ if (*test != "Now is the time for all good men to come to the aid of their country.")
+ errln("Stack-allocated UnicodeString overflow didn't work");
+ if (guardWord2 != 0x4DED)
+ errln("Stack-allocated UnicodeString overflow overwrote guard word!");
+
+ *test = "ha!";
+ if (*test != "ha!")
+ errln("Assignment to stack-allocated UnicodeString didn't work");
+ if (workingBuffer[0] != 0x4e)
+ errln("Change to UnicodeString after overflow are still affecting original buffer");
+ if (guardWord2 != 0x4DED)
+ errln("Change to UnicodeString after overflow overwrote guard word!");
+
+ // test read-only aliasing with setTo()
+ workingBuffer[0] = 0x20ac;
+ workingBuffer[1] = 0x125;
+ workingBuffer[2] = 0;
+ test->setTo(TRUE, workingBuffer, 2);
+ if(test->length() != 2 || test->charAt(0) != 0x20ac || test->charAt(1) != 0x125) {
+ errln("UnicodeString.setTo(readonly alias) does not alias correctly");
+ }
+
+ UnicodeString *c=(UnicodeString *)test->clone();
+
+ workingBuffer[1] = 0x109;
+ if(test->charAt(1) != 0x109) {
+ errln("UnicodeString.setTo(readonly alias) made a copy: did not see change in buffer");
+ }
+
+ if(c->length() != 2 || c->charAt(1) != 0x125) {
+ errln("clone(alias) did not copy the buffer");
+ }
+ delete c;
+
+ test->setTo(TRUE, workingBuffer, -1);
+ if(test->length() != 2 || test->charAt(0) != 0x20ac || test->charAt(1) != 0x109) {
+ errln("UnicodeString.setTo(readonly alias, length -1) does not alias correctly");
+ }
+
+ test->setTo(FALSE, workingBuffer, -1);
+ if(!test->isBogus()) {
+ errln("UnicodeString.setTo(unterminated readonly alias, length -1) does not result in isBogus()");
+ }
+
+ delete test;
+
+ test=new UnicodeString();
+ UChar buffer[]={0x0061, 0x0062, 0x20ac, 0x0043, 0x0042, 0x0000};
+ test->setTo(buffer, 4, 10);
+ if(test->length() !=4 || test->charAt(0) != 0x0061 || test->charAt(1) != 0x0062 ||
+ test->charAt(2) != 0x20ac || test->charAt(3) != 0x0043){
+ errln((UnicodeString)"UnicodeString.setTo(UChar*, length, capacity) does not work correctly\n" + prettify(*test));
+ }
+ delete test;
+
+
+ // test the UChar32 constructor
+ UnicodeString c32Test((UChar32)0x10ff2a);
+ if( c32Test.length() != UTF_CHAR_LENGTH(0x10ff2a) ||
+ c32Test.char32At(c32Test.length() - 1) != 0x10ff2a
+ ) {
+ errln("The UnicodeString(UChar32) constructor does not work with a 0x10ff2a filler");
+ }
+
+ // test the (new) capacity constructor
+ UnicodeString capTest(5, (UChar32)0x2a, 5);
+ if( capTest.length() != 5 * UTF_CHAR_LENGTH(0x2a) ||
+ capTest.char32At(0) != 0x2a ||
+ capTest.char32At(4) != 0x2a
+ ) {
+ errln("The UnicodeString capacity constructor does not work with an ASCII filler");
+ }
+
+ capTest = UnicodeString(5, (UChar32)0x10ff2a, 5);
+ if( capTest.length() != 5 * UTF_CHAR_LENGTH(0x10ff2a) ||
+ capTest.char32At(0) != 0x10ff2a ||
+ capTest.char32At(4) != 0x10ff2a
+ ) {
+ errln("The UnicodeString capacity constructor does not work with a 0x10ff2a filler");
+ }
+
+ capTest = UnicodeString(5, (UChar32)0, 0);
+ if(capTest.length() != 0) {
+ errln("The UnicodeString capacity constructor does not work with a 0x10ff2a filler");
+ }
+}
+
+/**
+ * Test the unescape() function.
+ */
+void UnicodeStringTest::TestUnescape(void) {
+ UnicodeString IN("abc\\u4567 \\n\\r \\U00101234xyz\\x1\\x{5289}\\x1b");
+ UnicodeString OUT("abc");
+ OUT.append((UChar)0x4567);
+ OUT.append(" ");
+ OUT.append((UChar)0xA);
+ OUT.append((UChar)0xD);
+ OUT.append(" ");
+ OUT.append((UChar32)0x00101234);
+ OUT.append("xyz");
+ OUT.append((UChar32)1).append((UChar32)0x5289).append((UChar)0x1b);
+ UnicodeString result = IN.unescape();
+ if (result != OUT) {
+ errln("FAIL: " + prettify(IN) + ".unescape() -> " +
+ prettify(result) + ", expected " +
+ prettify(OUT));
+ }
+
+ // test that an empty string is returned in case of an error
+ if (!UNICODE_STRING("wrong \\u sequence", 17).unescape().isEmpty()) {
+ errln("FAIL: unescaping of a string with an illegal escape sequence did not return an empty string");
+ }
+}
+
+/* test code point counting functions --------------------------------------- */
+
+/* reference implementation of UnicodeString::hasMoreChar32Than() */
+static int32_t
+_refUnicodeStringHasMoreChar32Than(const UnicodeString &s, int32_t start, int32_t length, int32_t number) {
+ int32_t count=s.countChar32(start, length);
+ return count>number;
+}
+
+/* compare the real function against the reference */
+void
+UnicodeStringTest::_testUnicodeStringHasMoreChar32Than(const UnicodeString &s, int32_t start, int32_t length, int32_t number) {
+ if(s.hasMoreChar32Than(start, length, number)!=_refUnicodeStringHasMoreChar32Than(s, start, length, number)) {
+ errln("hasMoreChar32Than(%d, %d, %d)=%hd is wrong\n",
+ start, length, number, s.hasMoreChar32Than(start, length, number));
+ }
+}
+
+void
+UnicodeStringTest::TestCountChar32(void) {
+ {
+ UnicodeString s=UNICODE_STRING("\\U0002f999\\U0001d15f\\u00c4\\u1ed0", 32).unescape();
+
+ // test countChar32()
+ // note that this also calls and tests u_countChar32(length>=0)
+ if(
+ s.countChar32()!=4 ||
+ s.countChar32(1)!=4 ||
+ s.countChar32(2)!=3 ||
+ s.countChar32(2, 3)!=2 ||
+ s.countChar32(2, 0)!=0
+ ) {
+ errln("UnicodeString::countChar32() failed");
+ }
+
+ // NUL-terminate the string buffer and test u_countChar32(length=-1)
+ const UChar *buffer=s.getTerminatedBuffer();
+ if(
+ u_countChar32(buffer, -1)!=4 ||
+ u_countChar32(buffer+1, -1)!=4 ||
+ u_countChar32(buffer+2, -1)!=3 ||
+ u_countChar32(buffer+3, -1)!=3 ||
+ u_countChar32(buffer+4, -1)!=2 ||
+ u_countChar32(buffer+5, -1)!=1 ||
+ u_countChar32(buffer+6, -1)!=0
+ ) {
+ errln("u_countChar32(length=-1) failed");
+ }
+
+ // test u_countChar32() with bad input
+ if(u_countChar32(NULL, 5)!=0 || u_countChar32(buffer, -2)!=0) {
+ errln("u_countChar32(bad input) failed (returned non-zero counts)");
+ }
+ }
+
+ /* test data and variables for hasMoreChar32Than() */
+ static const UChar str[]={
+ 0x61, 0x62, 0xd800, 0xdc00,
+ 0xd801, 0xdc01, 0x63, 0xd802,
+ 0x64, 0xdc03, 0x65, 0x66,
+ 0xd804, 0xdc04, 0xd805, 0xdc05,
+ 0x67
+ };
+ UnicodeString string(str, LENGTHOF(str));
+ int32_t start, length, number;
+
+ /* test hasMoreChar32Than() */
+ for(length=string.length(); length>=0; --length) {
+ for(start=0; start<=length; ++start) {
+ for(number=-1; number<=((length-start)+2); ++number) {
+ _testUnicodeStringHasMoreChar32Than(string, start, length-start, number);
+ }
+ }
+ }
+
+ /* test hasMoreChar32Than() with pinning */
+ for(start=-1; start<=string.length()+1; ++start) {
+ for(number=-1; number<=((string.length()-start)+2); ++number) {
+ _testUnicodeStringHasMoreChar32Than(string, start, 0x7fffffff, number);
+ }
+ }
+
+ /* test hasMoreChar32Than() with a bogus string */
+ string.setToBogus();
+ for(length=-1; length<=1; ++length) {
+ for(start=-1; start<=length; ++start) {
+ for(number=-1; number<=((length-start)+2); ++number) {
+ _testUnicodeStringHasMoreChar32Than(string, start, length-start, number);
+ }
+ }
+ }
+}
+
+void
+UnicodeStringTest::TestBogus() {
+ UnicodeString test1("This is a test");
+ UnicodeString test2("This is a test");
+ UnicodeString test3("Me too!");
+
+ // test isBogus() and setToBogus()
+ if (test1.isBogus() || test2.isBogus() || test3.isBogus()) {
+ errln("A string returned TRUE for isBogus()!");
+ }
+
+ // NULL pointers are treated like empty strings
+ // use other illegal arguments to make a bogus string
+ test3.setTo(FALSE, test1.getBuffer(), -2);
+ if(!test3.isBogus()) {
+ errln("A bogus string returned FALSE for isBogus()!");
+ }
+ if (test1.hashCode() != test2.hashCode() || test1.hashCode() == test3.hashCode()) {
+ errln("hashCode() failed");
+ }
+ if(test3.getBuffer()!=0 || test3.getBuffer(20)!=0 || test3.getTerminatedBuffer()!=0) {
+ errln("bogus.getBuffer()!=0");
+ }
+ if (test1.indexOf(test3) != -1) {
+ errln("bogus.indexOf() != -1");
+ }
+ if (test1.lastIndexOf(test3) != -1) {
+ errln("bogus.lastIndexOf() != -1");
+ }
+ if (test1.caseCompare(test3, U_FOLD_CASE_DEFAULT) != 1 || test3.caseCompare(test1, U_FOLD_CASE_DEFAULT) != -1) {
+ errln("caseCompare() doesn't work with bogus strings");
+ }
+ if (test1.compareCodePointOrder(test3) != 1 || test3.compareCodePointOrder(test1) != -1) {
+ errln("compareCodePointOrder() doesn't work with bogus strings");
+ }
+
+ // verify that non-assignment modifications fail and do not revive a bogus string
+ test3.setToBogus();
+ test3.append((UChar)0x61);
+ if(!test3.isBogus() || test3.getBuffer()!=0) {
+ errln("bogus.append('a') worked but must not");
+ }
+
+ test3.setToBogus();
+ test3.findAndReplace(UnicodeString((UChar)0x61), test2);
+ if(!test3.isBogus() || test3.getBuffer()!=0) {
+ errln("bogus.findAndReplace() worked but must not");
+ }
+
+ test3.setToBogus();
+ test3.trim();
+ if(!test3.isBogus() || test3.getBuffer()!=0) {
+ errln("bogus.trim() revived bogus but must not");
+ }
+
+ test3.setToBogus();
+ test3.remove(1);
+ if(!test3.isBogus() || test3.getBuffer()!=0) {
+ errln("bogus.remove(1) revived bogus but must not");
+ }
+
+ test3.setToBogus();
+ if(!test3.setCharAt(0, 0x62).isBogus() || !test3.isEmpty()) {
+ errln("bogus.setCharAt(0, 'b') worked but must not");
+ }
+
+ test3.setToBogus();
+ if(test3.truncate(1) || !test3.isBogus() || !test3.isEmpty()) {
+ errln("bogus.truncate(1) revived bogus but must not");
+ }
+
+ // verify that assignments revive a bogus string
+ test3.setToBogus();
+ if(!test3.isBogus() || (test3=test1).isBogus() || test3!=test1) {
+ errln("bogus.operator=() failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.fastCopyFrom(test1).isBogus() || test3!=test1) {
+ errln("bogus.fastCopyFrom() failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo(test1).isBogus() || test3!=test1) {
+ errln("bogus.setTo(UniStr) failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo(test1, 0).isBogus() || test3!=test1) {
+ errln("bogus.setTo(UniStr, 0) failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo(test1, 0, 0x7fffffff).isBogus() || test3!=test1) {
+ errln("bogus.setTo(UniStr, 0, len) failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo(test1.getBuffer(), test1.length()).isBogus() || test3!=test1) {
+ errln("bogus.setTo(const UChar *, len) failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo((UChar)0x2028).isBogus() || test3!=UnicodeString((UChar)0x2028)) {
+ errln("bogus.setTo(UChar) failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo((UChar32)0x1d157).isBogus() || test3!=UnicodeString((UChar32)0x1d157)) {
+ errln("bogus.setTo(UChar32) failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo(FALSE, test1.getBuffer(), test1.length()).isBogus() || test3!=test1) {
+ errln("bogus.setTo(readonly alias) failed");
+ }
+
+ // writable alias to another string's buffer: very bad idea, just convenient for this test
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo((UChar *)test1.getBuffer(), test1.length(), test1.getCapacity()).isBogus() || test3!=test1) {
+ errln("bogus.setTo(writable alias) failed");
+ }
+
+ // verify simple, documented ways to turn a bogus string into an empty one
+ test3.setToBogus();
+ if(!test3.isBogus() || (test3=UnicodeString()).isBogus() || !test3.isEmpty()) {
+ errln("bogus.operator=(UnicodeString()) failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo(UnicodeString()).isBogus() || !test3.isEmpty()) {
+ errln("bogus.setTo(UnicodeString()) failed");
+ }
+
+ test3.setToBogus();
+ if(test3.remove().isBogus() || test3.getBuffer()==0 || !test3.isEmpty()) {
+ errln("bogus.remove() failed");
+ }
+
+ test3.setToBogus();
+ if(test3.remove(0, INT32_MAX).isBogus() || test3.getBuffer()==0 || !test3.isEmpty()) {
+ errln("bogus.remove(0, INT32_MAX) failed");
+ }
+
+ test3.setToBogus();
+ if(test3.truncate(0) || test3.isBogus() || !test3.isEmpty()) {
+ errln("bogus.truncate(0) failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo((UChar32)-1).isBogus() || !test3.isEmpty()) {
+ errln("bogus.setTo((UChar32)-1) failed");
+ }
+
+ static const UChar nul=0;
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.setTo(&nul, 0).isBogus() || !test3.isEmpty()) {
+ errln("bogus.setTo(&nul, 0) failed");
+ }
+
+ test3.setToBogus();
+ if(!test3.isBogus() || test3.getBuffer()!=0) {
+ errln("setToBogus() failed to make a string bogus");
+ }
+
+ test3.setToBogus();
+ if(test1.isBogus() || !(test1=test3).isBogus()) {
+ errln("normal=bogus failed to make the left string bogus");
+ }
+
+ // test that NULL primitive input string values are treated like
+ // empty strings, not errors (bogus)
+ test2.setTo((UChar32)0x10005);
+ if(test2.insert(1, NULL, 1).length()!=2) {
+ errln("UniStr.insert(...NULL...) should not modify the string but does");
+ }
+
+ UErrorCode errorCode=U_ZERO_ERROR;
+ UnicodeString
+ test4((const UChar *)NULL),
+ test5(TRUE, (const UChar *)NULL, 1),
+ test6((UChar *)NULL, 5, 5),
+ test7((const char *)NULL, 3, NULL, errorCode);
+ if(test4.isBogus() || test5.isBogus() || test6.isBogus() || test7.isBogus()) {
+ errln("a constructor set to bogus for a NULL input string, should be empty");
+ }
+
+ test4.setTo(NULL, 3);
+ test5.setTo(TRUE, (const UChar *)NULL, 1);
+ test6.setTo((UChar *)NULL, 5, 5);
+ if(test4.isBogus() || test5.isBogus() || test6.isBogus()) {
+ errln("a setTo() set to bogus for a NULL input string, should be empty");
+ }
+
+ // test that bogus==bogus<any
+ if(test1!=test3 || test1.compare(test3)!=0) {
+ errln("bogus==bogus failed");
+ }
+
+ test2.remove();
+ if(test1>=test2 || !(test2>test1) || test1.compare(test2)>=0 || !(test2.compare(test1)>0)) {
+ errln("bogus<empty failed");
+ }
+}
+
+// StringEnumeration ------------------------------------------------------- ***
+// most of StringEnumeration is tested elsewhere
+// this test improves code coverage
+
+static const char *const
+testEnumStrings[]={
+ "a",
+ "b",
+ "c",
+ "this is a long string which helps us test some buffer limits",
+ "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+};
+
+class TestEnumeration : public StringEnumeration {
+public:
+ TestEnumeration() : i(0) {}
+
+ virtual int32_t count(UErrorCode& /*status*/) const {
+ return LENGTHOF(testEnumStrings);
+ }
+
+ virtual const UnicodeString *snext(UErrorCode &status) {
+ if(U_SUCCESS(status) && i<LENGTHOF(testEnumStrings)) {
+ unistr=UnicodeString(testEnumStrings[i++], "");
+ return &unistr;
+ }
+
+ return NULL;
+ }
+
+ virtual void reset(UErrorCode& /*status*/) {
+ i=0;
+ }
+
+ static inline UClassID getStaticClassID() {
+ return (UClassID)&fgClassID;
+ }
+ virtual UClassID getDynamicClassID() const {
+ return getStaticClassID();
+ }
+
+private:
+ static const char fgClassID;
+
+ int32_t i, length;
+};
+
+const char TestEnumeration::fgClassID=0;
+
+void
+UnicodeStringTest::TestStringEnumeration() {
+ UnicodeString s;
+ TestEnumeration ten;
+ int32_t i, length;
+ UErrorCode status;
+
+ const UChar *pu;
+ const char *pc;
+
+ // test the next() default implementation and ensureCharsCapacity()
+ for(i=0; i<LENGTHOF(testEnumStrings); ++i) {
+ status=U_ZERO_ERROR;
+ pc=ten.next(&length, status);
+ s=UnicodeString(testEnumStrings[i], "");
+ if(U_FAILURE(status) || pc==NULL || length!=s.length() || UnicodeString(pc, length, "")!=s) {
+ errln("StringEnumeration.next(%d) failed", i);
+ }
+ }
+ status=U_ZERO_ERROR;
+ if(ten.next(&length, status)!=NULL) {
+ errln("StringEnumeration.next(done)!=NULL");
+ }
+
+ // test the unext() default implementation
+ ten.reset(status);
+ for(i=0; i<LENGTHOF(testEnumStrings); ++i) {
+ status=U_ZERO_ERROR;
+ pu=ten.unext(&length, status);
+ s=UnicodeString(testEnumStrings[i], "");
+ if(U_FAILURE(status) || pu==NULL || length!=s.length() || UnicodeString(TRUE, pu, length)!=s) {
+ errln("StringEnumeration.unext(%d) failed", i);
+ }
+ }
+ status=U_ZERO_ERROR;
+ if(ten.unext(&length, status)!=NULL) {
+ errln("StringEnumeration.unext(done)!=NULL");
+ }
+
+ // test that the default clone() implementation works, and returns NULL
+ if(ten.clone()!=NULL) {
+ errln("StringEnumeration.clone()!=NULL");
+ }
+}
+
+void
+UnicodeStringTest::TestCharString() {
+ static const char originalCStr[] =
+ "This is a large string that is meant to over flow the internal buffer of CharString. At the time of writing this test, the internal buffer is 128 bytes.";
+ CharString chStr(originalCStr);
+ if (strcmp(originalCStr, chStr) != 0) {
+ errln("CharString doesn't work with large strings.");
+ }
+}
+
+/*
+ * Namespace test, to make sure that macros like UNICODE_STRING include the
+ * namespace qualifier.
+ *
+ * Define a (bogus) UnicodeString class in another namespace and check for ambiguity.
+ */
+#if U_HAVE_NAMESPACE
+namespace bogus {
+ class UnicodeString {
+ public:
+ enum EInvariant { kInvariant };
+ UnicodeString() : i(1) {}
+ UnicodeString(UBool /*isTerminated*/, const UChar * /*text*/, int32_t textLength) : i(textLength) {}
+ UnicodeString(const char * /*src*/, int32_t length, enum EInvariant /*inv*/
+) : i(length) {}
+ private:
+ int32_t i;
+ };
+}
+#endif
+
+void
+UnicodeStringTest::TestNameSpace() {
+#if U_HAVE_NAMESPACE
+ // Provoke name collision unless the UnicodeString macros properly
+ // qualify the icu::UnicodeString class.
+ using namespace bogus;
+
+ // Use all UnicodeString macros from unistr.h.
+ icu::UnicodeString s1=icu::UnicodeString("abc", 3, US_INV);
+ icu::UnicodeString s2=UNICODE_STRING("def", 3);
+ icu::UnicodeString s3=UNICODE_STRING_SIMPLE("ghi");
+
+ // Make sure the compiler does not optimize away instantiation of s1, s2, s3.
+ icu::UnicodeString s4=s1+s2+s3;
+ if(s4.length()!=9) {
+ errln("Something wrong with UnicodeString::operator+().");
+ }
+#endif
+}
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/ustrtest.h b/Build/source/libs/icu/icu-xetex/test/intltest/ustrtest.h
new file mode 100644
index 00000000000..697db602786
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/ustrtest.h
@@ -0,0 +1,96 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 1997-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+#ifndef UNICODESTRINGTEST_H
+#define UNICODESTRINGTEST_H
+
+#include "unicode/unistr.h"
+#include "intltest.h"
+
+/**
+ * Perform API and functionality tests for class UnicodeString
+ **/
+class UnicodeStringTest: public IntlTest {
+public:
+ UnicodeStringTest() {}
+ virtual ~UnicodeStringTest();
+
+ void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ /**
+ * Test some basic methods (insert, remove, replace, ...)
+ **/
+ void TestBasicManipulation(void);
+ /**
+ * Test the methods for comparison
+ **/
+ void TestCompare(void);
+ /**
+ * Test the methods for extracting
+ **/
+ void TestExtract(void);
+ /**
+ * More extensively test methods for removing and replacing
+ **/
+ void TestRemoveReplace(void);
+ /**
+ * Test language specific case conversions
+ **/
+ void TestSearching(void);
+ /**
+ * Test methods for padding, trimmimg and truncating
+ **/
+ void TestSpacePadding(void);
+ /**
+ * Test methods startsWith and endsWith
+ **/
+ void TestPrefixAndSuffix(void);
+ /**
+ * Test method findAndReplace
+ **/
+ void TestFindAndReplace(void);
+ /**
+ * Test method reverse
+ **/
+ void TestReverse(void);
+ /**
+ * Test a few miscellaneous methods (isBogus, hashCode,...)
+ **/
+ void TestMiscellaneous(void);
+ /**
+ * Test the functionality of allocating UnicodeStrings on the stack
+ **/
+ void TestStackAllocation(void);
+ /**
+ * Test the unescape() function.
+ */
+ void TestUnescape(void);
+
+ void _testUnicodeStringHasMoreChar32Than(const UnicodeString &s, int32_t start, int32_t length, int32_t number);
+ void TestCountChar32(void);
+ void TestBogus();
+ void TestStringEnumeration();
+ void TestCharString(void);
+ void TestNameSpace(void);
+};
+
+class StringCaseTest: public IntlTest {
+public:
+ StringCaseTest() {}
+ virtual ~StringCaseTest();
+
+ void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
+
+ void TestCaseConversion();
+
+ void TestCasingImpl(const UnicodeString &input,
+ const UnicodeString &output,
+ int32_t whichCase,
+ void *iter, const char *localeID, uint32_t options);
+ void TestCasing();
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/utxttest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/utxttest.cpp
new file mode 100644
index 00000000000..d6264d9e6be
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/utxttest.cpp
@@ -0,0 +1,1400 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2005-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/************************************************************************
+* Tests for the UText and UTextIterator text abstraction classses
+*
+************************************************************************/
+
+#include "unicode/utypes.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unicode/utext.h>
+#include <unicode/utf8.h>
+#include <unicode/ustring.h>
+#include <unicode/uchriter.h>
+#include "utxttest.h"
+
+static UBool gFailed = FALSE;
+static int gTestNum = 0;
+
+// Forward decl
+UText *openFragmentedUnicodeString(UText *ut, UnicodeString *s, UErrorCode *status);
+
+#define TEST_ASSERT(x) \
+{ if ((x)==FALSE) {errln("Test #%d failure in file %s at line %d\n", gTestNum, __FILE__, __LINE__);\
+ gFailed = TRUE;\
+ }}
+
+
+#define TEST_SUCCESS(status) \
+{ if (U_FAILURE(status)) {errln("Test #%d failure in file %s at line %d. Error = \"%s\"\n", \
+ gTestNum, __FILE__, __LINE__, u_errorName(status)); \
+ gFailed = TRUE;\
+ }}
+
+UTextTest::UTextTest() {
+}
+
+UTextTest::~UTextTest() {
+}
+
+
+void
+UTextTest::runIndexedTest(int32_t index, UBool exec,
+ const char* &name, char* /*par*/) {
+ switch (index) {
+ case 0: name = "TextTest";
+ if (exec) TextTest(); break;
+ case 1: name = "ErrorTest";
+ if (exec) ErrorTest(); break;
+ case 2: name = "FreezeTest";
+ if (exec) FreezeTest(); break;
+ case 3: name = "Ticket5560";
+ if (exec) Ticket5560(); break;
+ default: name = ""; break;
+ }
+}
+
+//
+// Quick and dirty random number generator.
+// (don't use library so that results are portable.
+static uint32_t m_seed = 1;
+static uint32_t m_rand()
+{
+ m_seed = m_seed * 1103515245 + 12345;
+ return (uint32_t)(m_seed/65536) % 32768;
+}
+
+
+//
+// TextTest()
+//
+// Top Level function for UText testing.
+// Specifies the strings to be tested, with the acutal testing itself
+// being carried out in another function, TestString().
+//
+void UTextTest::TextTest() {
+ int32_t i, j;
+
+ TestString("abcd\\U00010001xyz");
+ TestString("");
+
+ // Supplementary chars at start or end
+ TestString("\\U00010001");
+ TestString("abc\\U00010001");
+ TestString("\\U00010001abc");
+
+ // Test simple strings of lengths 1 to 60, looking for glitches at buffer boundaries
+ UnicodeString s;
+ for (i=1; i<60; i++) {
+ s.truncate(0);
+ for (j=0; j<i; j++) {
+ if (j+0x30 == 0x5c) {
+ // backslash. Needs to be escaped
+ s.append((UChar)0x5c);
+ }
+ s.append(UChar(j+0x30));
+ }
+ TestString(s);
+ }
+
+ // Test strings with odd-aligned supplementary chars,
+ // looking for glitches at buffer boundaries
+ for (i=1; i<60; i++) {
+ s.truncate(0);
+ s.append((UChar)0x41);
+ for (j=0; j<i; j++) {
+ s.append(UChar32(j+0x11000));
+ }
+ TestString(s);
+ }
+
+ // String of chars of randomly varying size in utf-8 representation.
+ // Exercise the mapping, and the varying sized buffer.
+ //
+ s.truncate(0);
+ UChar32 c1 = 0;
+ UChar32 c2 = 0x100;
+ UChar32 c3 = 0xa000;
+ UChar32 c4 = 0x11000;
+ for (i=0; i<1000; i++) {
+ int len8 = m_rand()%4 + 1;
+ switch (len8) {
+ case 1:
+ c1 = (c1+1)%0x80;
+ // don't put 0 into string (0 terminated strings for some tests)
+ // don't put '\', will cause unescape() to fail.
+ if (c1==0x5c || c1==0) {
+ c1++;
+ }
+ s.append(c1);
+ break;
+ case 2:
+ s.append(c2++);
+ break;
+ case 3:
+ s.append(c3++);
+ break;
+ case 4:
+ s.append(c4++);
+ break;
+ }
+ }
+ TestString(s);
+}
+
+
+//
+// TestString() Run a suite of UText tests on a string.
+// The test string is unescaped before use.
+//
+void UTextTest::TestString(const UnicodeString &s) {
+ int32_t i;
+ int32_t j;
+ UChar32 c;
+ int32_t cpCount = 0;
+ UErrorCode status = U_ZERO_ERROR;
+ UText *ut = NULL;
+ int32_t saLen;
+
+ UnicodeString sa = s.unescape();
+ saLen = sa.length();
+
+ //
+ // Build up a mapping between code points and UTF-16 code unit indexes.
+ //
+ m *cpMap = new m[sa.length() + 1];
+ j = 0;
+ for (i=0; i<sa.length(); i=sa.moveIndex32(i, 1)) {
+ c = sa.char32At(i);
+ cpMap[j].nativeIdx = i;
+ cpMap[j].cp = c;
+ j++;
+ cpCount++;
+ }
+ cpMap[j].nativeIdx = i; // position following the last char in utf-16 string.
+
+
+ // UChar * test, null terminated
+ status = U_ZERO_ERROR;
+ UChar *buf = new UChar[saLen+1];
+ sa.extract(buf, saLen+1, status);
+ TEST_SUCCESS(status);
+ ut = utext_openUChars(NULL, buf, -1, &status);
+ TEST_SUCCESS(status);
+ TestAccess(sa, ut, cpCount, cpMap);
+ utext_close(ut);
+ delete [] buf;
+
+ // UChar * test, with length
+ status = U_ZERO_ERROR;
+ buf = new UChar[saLen+1];
+ sa.extract(buf, saLen+1, status);
+ TEST_SUCCESS(status);
+ ut = utext_openUChars(NULL, buf, saLen, &status);
+ TEST_SUCCESS(status);
+ TestAccess(sa, ut, cpCount, cpMap);
+ utext_close(ut);
+ delete [] buf;
+
+
+ // UnicodeString test
+ status = U_ZERO_ERROR;
+ ut = utext_openUnicodeString(NULL, &sa, &status);
+ TEST_SUCCESS(status);
+ TestAccess(sa, ut, cpCount, cpMap);
+ TestCMR(sa, ut, cpCount, cpMap, cpMap);
+ utext_close(ut);
+
+
+ // Const UnicodeString test
+ status = U_ZERO_ERROR;
+ ut = utext_openConstUnicodeString(NULL, &sa, &status);
+ TEST_SUCCESS(status);
+ TestAccess(sa, ut, cpCount, cpMap);
+ utext_close(ut);
+
+
+ // Replaceable test. (UnicodeString inherits Replaceable)
+ status = U_ZERO_ERROR;
+ ut = utext_openReplaceable(NULL, &sa, &status);
+ TEST_SUCCESS(status);
+ TestAccess(sa, ut, cpCount, cpMap);
+ TestCMR(sa, ut, cpCount, cpMap, cpMap);
+ utext_close(ut);
+
+ // Character Iterator Tests
+ status = U_ZERO_ERROR;
+ const UChar *cbuf = sa.getBuffer();
+ CharacterIterator *ci = new UCharCharacterIterator(cbuf, saLen, status);
+ TEST_SUCCESS(status);
+ ut = utext_openCharacterIterator(NULL, ci, &status);
+ TEST_SUCCESS(status);
+ TestAccess(sa, ut, cpCount, cpMap);
+ utext_close(ut);
+ delete ci;
+
+
+ // Fragmented UnicodeString (Chunk size of one)
+ //
+ status = U_ZERO_ERROR;
+ ut = openFragmentedUnicodeString(NULL, &sa, &status);
+ TEST_SUCCESS(status);
+ TestAccess(sa, ut, cpCount, cpMap);
+ utext_close(ut);
+
+ //
+ // UTF-8 test
+ //
+
+ // Convert the test string from UnicodeString to (char *) in utf-8 format
+ int32_t u8Len = sa.extract(0, sa.length(), NULL, 0, "utf-8");
+ char *u8String = new char[u8Len + 1];
+ sa.extract(0, sa.length(), u8String, u8Len+1, "utf-8");
+
+ // Build up the map of code point indices in the utf-8 string
+ m * u8Map = new m[sa.length() + 1];
+ i = 0; // native utf-8 index
+ for (j=0; j<cpCount ; j++) { // code point number
+ u8Map[j].nativeIdx = i;
+ U8_NEXT(u8String, i, u8Len, c)
+ u8Map[j].cp = c;
+ }
+ u8Map[cpCount].nativeIdx = u8Len; // position following the last char in utf-8 string.
+
+ // Do the test itself
+ status = U_ZERO_ERROR;
+ ut = utext_openUTF8(NULL, u8String, -1, &status);
+ TEST_SUCCESS(status);
+ TestAccess(sa, ut, cpCount, u8Map);
+ utext_close(ut);
+
+
+
+ delete []cpMap;
+ delete []u8Map;
+ delete []u8String;
+}
+
+// TestCMR test Copy, Move and Replace operations.
+// us UnicodeString containing the test text.
+// ut UText containing the same test text.
+// cpCount number of code points in the test text.
+// nativeMap Mapping from code points to native indexes for the UText.
+// u16Map Mapping from code points to UTF-16 indexes, for use with the UnicodeString.
+//
+// This function runs a whole series of opertions on each incoming UText.
+// The UText is deep-cloned prior to each operation, so that the original UText remains unchanged.
+//
+void UTextTest::TestCMR(const UnicodeString &us, UText *ut, int cpCount, m *nativeMap, m *u16Map) {
+ TEST_ASSERT(utext_isWritable(ut) == TRUE);
+
+ int srcLengthType; // Loop variables for selecting the postion and length
+ int srcPosType; // of the block to operate on within the source text.
+ int destPosType;
+
+ int srcIndex = 0; // Code Point indexes of the block to operate on for
+ int srcLength = 0; // a specific test.
+
+ int destIndex = 0; // Code point index of the destination for a copy/move test.
+
+ int32_t nativeStart = 0; // Native unit indexes for a test.
+ int32_t nativeLimit = 0;
+ int32_t nativeDest = 0;
+
+ int32_t u16Start = 0; // UTF-16 indexes for a test.
+ int32_t u16Limit = 0; // used when performing the same operation in a Unicode String
+ int32_t u16Dest = 0;
+
+ // Iterate over a whole series of source index, length and a target indexes.
+ // This is done with code point indexes; these will be later translated to native
+ // indexes using the cpMap.
+ for (srcLengthType=1; srcLengthType<=3; srcLengthType++) {
+ switch (srcLengthType) {
+ case 1: srcLength = 1; break;
+ case 2: srcLength = 5; break;
+ case 3: srcLength = cpCount / 3;
+ }
+ for (srcPosType=1; srcPosType<=5; srcPosType++) {
+ switch (srcPosType) {
+ case 1: srcIndex = 0; break;
+ case 2: srcIndex = 1; break;
+ case 3: srcIndex = cpCount - srcLength; break;
+ case 4: srcIndex = cpCount - srcLength - 1; break;
+ case 5: srcIndex = cpCount / 2; break;
+ }
+ if (srcIndex < 0 || srcIndex + srcLength > cpCount) {
+ // filter out bogus test cases -
+ // those with a source range that falls of an edge of the string.
+ continue;
+ }
+
+ //
+ // Copy and move tests.
+ // iterate over a variety of destination positions.
+ //
+ for (destPosType=1; destPosType<=4; destPosType++) {
+ switch (destPosType) {
+ case 1: destIndex = 0; break;
+ case 2: destIndex = 1; break;
+ case 3: destIndex = srcIndex - 1; break;
+ case 4: destIndex = srcIndex + srcLength + 1; break;
+ case 5: destIndex = cpCount-1; break;
+ case 6: destIndex = cpCount; break;
+ }
+ if (destIndex<0 || destIndex>cpCount) {
+ // filter out bogus test cases.
+ continue;
+ }
+
+ nativeStart = nativeMap[srcIndex].nativeIdx;
+ nativeLimit = nativeMap[srcIndex+srcLength].nativeIdx;
+ nativeDest = nativeMap[destIndex].nativeIdx;
+
+ u16Start = u16Map[srcIndex].nativeIdx;
+ u16Limit = u16Map[srcIndex+srcLength].nativeIdx;
+ u16Dest = u16Map[destIndex].nativeIdx;
+
+ gFailed = FALSE;
+ TestCopyMove(us, ut, FALSE,
+ nativeStart, nativeLimit, nativeDest,
+ u16Start, u16Limit, u16Dest);
+
+ TestCopyMove(us, ut, TRUE,
+ nativeStart, nativeLimit, nativeDest,
+ u16Start, u16Limit, u16Dest);
+
+ if (gFailed) {
+ return;
+ }
+ }
+
+ //
+ // Replace tests.
+ //
+ UnicodeString fullRepString("This is an arbitrary string that will be used as replacement text");
+ for (int32_t replStrLen=0; replStrLen<20; replStrLen++) {
+ UnicodeString repStr(fullRepString, 0, replStrLen);
+ TestReplace(us, ut,
+ nativeStart, nativeLimit,
+ u16Start, u16Limit,
+ repStr);
+ if (gFailed) {
+ return;
+ }
+ }
+
+ }
+ }
+
+}
+
+//
+// TestCopyMove run a single test case for utext_copy.
+// Test cases are created in TestCMR and dispatched here for execution.
+//
+void UTextTest::TestCopyMove(const UnicodeString &us, UText *ut, UBool move,
+ int32_t nativeStart, int32_t nativeLimit, int32_t nativeDest,
+ int32_t u16Start, int32_t u16Limit, int32_t u16Dest)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UText *targetUT = NULL;
+ gTestNum++;
+ gFailed = FALSE;
+
+ //
+ // clone the UText. The test will be run in the cloned copy
+ // so that we don't alter the original.
+ //
+ targetUT = utext_clone(NULL, ut, TRUE, FALSE, &status);
+ TEST_SUCCESS(status);
+ UnicodeString targetUS(us); // And copy the reference string.
+
+ // do the test operation first in the reference
+ targetUS.copy(u16Start, u16Limit, u16Dest);
+ if (move) {
+ // delete out the source range.
+ if (u16Limit < u16Dest) {
+ targetUS.removeBetween(u16Start, u16Limit);
+ } else {
+ int32_t amtCopied = u16Limit - u16Start;
+ targetUS.removeBetween(u16Start+amtCopied, u16Limit+amtCopied);
+ }
+ }
+
+ // Do the same operation in the UText under test
+ utext_copy(targetUT, nativeStart, nativeLimit, nativeDest, move, &status);
+ if (nativeDest > nativeStart && nativeDest < nativeLimit) {
+ TEST_ASSERT(status == U_INDEX_OUTOFBOUNDS_ERROR);
+ } else {
+ TEST_SUCCESS(status);
+
+ // Compare the results of the two parallel tests
+ int32_t usi = 0; // UnicodeString postion, utf-16 index.
+ int64_t uti = 0; // UText position, native index.
+ int32_t cpi; // char32 position (code point index)
+ UChar32 usc; // code point from Unicode String
+ UChar32 utc; // code point from UText
+ utext_setNativeIndex(targetUT, 0);
+ for (cpi=0; ; cpi++) {
+ usc = targetUS.char32At(usi);
+ utc = utext_next32(targetUT);
+ if (utc < 0) {
+ break;
+ }
+ TEST_ASSERT(uti == usi);
+ TEST_ASSERT(utc == usc);
+ usi = targetUS.moveIndex32(usi, 1);
+ uti = utext_getNativeIndex(targetUT);
+ if (gFailed) {
+ goto cleanupAndReturn;
+ }
+ }
+ int64_t expectedNativeLength = utext_nativeLength(ut);
+ if (move == FALSE) {
+ expectedNativeLength += nativeLimit - nativeStart;
+ }
+ uti = utext_getNativeIndex(targetUT);
+ TEST_ASSERT(uti == expectedNativeLength);
+ }
+
+cleanupAndReturn:
+ utext_close(targetUT);
+}
+
+
+//
+// TestReplace Test a single Replace operation.
+//
+void UTextTest::TestReplace(
+ const UnicodeString &us, // reference UnicodeString in which to do the replace
+ UText *ut, // UnicodeText object under test.
+ int32_t nativeStart, // Range to be replaced, in UText native units.
+ int32_t nativeLimit,
+ int32_t u16Start, // Range to be replaced, in UTF-16 units
+ int32_t u16Limit, // for use in the reference UnicodeString.
+ const UnicodeString &repStr) // The replacement string
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UText *targetUT = NULL;
+ gTestNum++;
+ gFailed = FALSE;
+
+ //
+ // clone the target UText. The test will be run in the cloned copy
+ // so that we don't alter the original.
+ //
+ targetUT = utext_clone(NULL, ut, TRUE, FALSE, &status);
+ TEST_SUCCESS(status);
+ UnicodeString targetUS(us); // And copy the reference string.
+
+ //
+ // Do the replace operation in the Unicode String, to
+ // produce a reference result.
+ //
+ targetUS.replace(u16Start, u16Limit-u16Start, repStr);
+
+ //
+ // Do the replace on the UText under test
+ //
+ const UChar *rs = repStr.getBuffer();
+ int32_t rsLen = repStr.length();
+ int32_t actualDelta = utext_replace(targetUT, nativeStart, nativeLimit, rs, rsLen, &status);
+ int32_t expectedDelta = repStr.length() - (nativeLimit - nativeStart);
+ TEST_ASSERT(actualDelta == expectedDelta);
+
+ //
+ // Compare the results
+ //
+ int32_t usi = 0; // UnicodeString postion, utf-16 index.
+ int64_t uti = 0; // UText position, native index.
+ int32_t cpi; // char32 position (code point index)
+ UChar32 usc; // code point from Unicode String
+ UChar32 utc; // code point from UText
+ int64_t expectedNativeLength = 0;
+ utext_setNativeIndex(targetUT, 0);
+ for (cpi=0; ; cpi++) {
+ usc = targetUS.char32At(usi);
+ utc = utext_next32(targetUT);
+ if (utc < 0) {
+ break;
+ }
+ TEST_ASSERT(uti == usi);
+ TEST_ASSERT(utc == usc);
+ usi = targetUS.moveIndex32(usi, 1);
+ uti = utext_getNativeIndex(targetUT);
+ if (gFailed) {
+ goto cleanupAndReturn;
+ }
+ }
+ expectedNativeLength = utext_nativeLength(ut) + expectedDelta;
+ uti = utext_getNativeIndex(targetUT);
+ TEST_ASSERT(uti == expectedNativeLength);
+
+cleanupAndReturn:
+ utext_close(targetUT);
+}
+
+//
+// TestAccess Test the read only access functions on a UText, including cloning.
+// The text is accessed in a variety of ways, and compared with
+// the reference UnicodeString.
+//
+void UTextTest::TestAccess(const UnicodeString &us, UText *ut, int cpCount, m *cpMap) {
+ // Run the standard tests on the caller-supplied UText.
+ TestAccessNoClone(us, ut, cpCount, cpMap);
+
+ // Re-run tests on a shallow clone.
+ utext_setNativeIndex(ut, 0);
+ UErrorCode status = U_ZERO_ERROR;
+ UText *shallowClone = utext_clone(NULL, ut, FALSE /*deep*/, FALSE /*readOnly*/, &status);
+ TEST_SUCCESS(status);
+ TestAccessNoClone(us, shallowClone, cpCount, cpMap);
+
+ //
+ // Rerun again on a deep clone.
+ // Note that text providers are not required to provide deep cloning,
+ // so unsupported errors are ignored.
+ //
+ status = U_ZERO_ERROR;
+ utext_setNativeIndex(shallowClone, 0);
+ UText *deepClone = utext_clone(NULL, shallowClone, TRUE, FALSE, &status);
+ utext_close(shallowClone);
+ if (status != U_UNSUPPORTED_ERROR) {
+ TEST_SUCCESS(status);
+ TestAccessNoClone(us, deepClone, cpCount, cpMap);
+ }
+ utext_close(deepClone);
+}
+
+
+//
+// TestAccessNoClone() Test the read only access functions on a UText.
+// The text is accessed in a variety of ways, and compared with
+// the reference UnicodeString.
+//
+void UTextTest::TestAccessNoClone(const UnicodeString &us, UText *ut, int cpCount, m *cpMap) {
+ UErrorCode status = U_ZERO_ERROR;
+ gTestNum++;
+
+ //
+ // Check the length from the UText
+ //
+ int64_t expectedLen = cpMap[cpCount].nativeIdx;
+ int64_t utlen = utext_nativeLength(ut);
+ TEST_ASSERT(expectedLen == utlen);
+
+ //
+ // Iterate forwards, verify that we get the correct code points
+ // at the correct native offsets.
+ //
+ int i = 0;
+ int64_t index;
+ int64_t expectedIndex = 0;
+ int64_t foundIndex = 0;
+ UChar32 expectedC;
+ UChar32 foundC;
+ int64_t len;
+
+ for (i=0; i<cpCount; i++) {
+ expectedIndex = cpMap[i].nativeIdx;
+ foundIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(expectedIndex == foundIndex);
+ expectedC = cpMap[i].cp;
+ foundC = utext_next32(ut);
+ TEST_ASSERT(expectedC == foundC);
+ foundIndex = utext_getPreviousNativeIndex(ut);
+ TEST_ASSERT(expectedIndex == foundIndex);
+ if (gFailed) {
+ return;
+ }
+ }
+ foundC = utext_next32(ut);
+ TEST_ASSERT(foundC == U_SENTINEL);
+
+ // Repeat above, using macros
+ utext_setNativeIndex(ut, 0);
+ for (i=0; i<cpCount; i++) {
+ expectedIndex = cpMap[i].nativeIdx;
+ foundIndex = UTEXT_GETNATIVEINDEX(ut);
+ TEST_ASSERT(expectedIndex == foundIndex);
+ expectedC = cpMap[i].cp;
+ foundC = UTEXT_NEXT32(ut);
+ TEST_ASSERT(expectedC == foundC);
+ if (gFailed) {
+ return;
+ }
+ }
+ foundC = UTEXT_NEXT32(ut);
+ TEST_ASSERT(foundC == U_SENTINEL);
+
+ //
+ // Forward iteration (above) should have left index at the
+ // end of the input, which should == length().
+ //
+ len = utext_nativeLength(ut);
+ foundIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(len == foundIndex);
+
+ //
+ // Iterate backwards over entire test string
+ //
+ len = utext_getNativeIndex(ut);
+ utext_setNativeIndex(ut, len);
+ for (i=cpCount-1; i>=0; i--) {
+ expectedC = cpMap[i].cp;
+ expectedIndex = cpMap[i].nativeIdx;
+ int64_t prevIndex = utext_getPreviousNativeIndex(ut);
+ foundC = utext_previous32(ut);
+ foundIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(expectedIndex == foundIndex);
+ TEST_ASSERT(expectedC == foundC);
+ TEST_ASSERT(prevIndex == foundIndex);
+ if (gFailed) {
+ return;
+ }
+ }
+
+ //
+ // Backwards iteration, above, should have left our iterator
+ // position at zero, and continued backwards iterationshould fail.
+ //
+ foundIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(foundIndex == 0);
+ foundIndex = utext_getPreviousNativeIndex(ut);
+ TEST_ASSERT(foundIndex == 0);
+
+
+ foundC = utext_previous32(ut);
+ TEST_ASSERT(foundC == U_SENTINEL);
+ foundIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(foundIndex == 0);
+ foundIndex = utext_getPreviousNativeIndex(ut);
+ TEST_ASSERT(foundIndex == 0);
+
+
+ // And again, with the macros
+ utext_setNativeIndex(ut, len);
+ for (i=cpCount-1; i>=0; i--) {
+ expectedC = cpMap[i].cp;
+ expectedIndex = cpMap[i].nativeIdx;
+ foundC = UTEXT_PREVIOUS32(ut);
+ foundIndex = UTEXT_GETNATIVEINDEX(ut);
+ TEST_ASSERT(expectedIndex == foundIndex);
+ TEST_ASSERT(expectedC == foundC);
+ if (gFailed) {
+ return;
+ }
+ }
+
+ //
+ // Backwards iteration, above, should have left our iterator
+ // position at zero, and continued backwards iterationshould fail.
+ //
+ foundIndex = UTEXT_GETNATIVEINDEX(ut);
+ TEST_ASSERT(foundIndex == 0);
+
+ foundC = UTEXT_PREVIOUS32(ut);
+ TEST_ASSERT(foundC == U_SENTINEL);
+ foundIndex = UTEXT_GETNATIVEINDEX(ut);
+ TEST_ASSERT(foundIndex == 0);
+ if (gFailed) {
+ return;
+ }
+
+ //
+ // next32From(), prevous32From(), Iterate in a somewhat random order.
+ //
+ int cpIndex = 0;
+ for (i=0; i<cpCount; i++) {
+ cpIndex = (cpIndex + 9973) % cpCount;
+ index = cpMap[cpIndex].nativeIdx;
+ expectedC = cpMap[cpIndex].cp;
+ foundC = utext_next32From(ut, index);
+ TEST_ASSERT(expectedC == foundC);
+ if (gFailed) {
+ return;
+ }
+ }
+
+ cpIndex = 0;
+ for (i=0; i<cpCount; i++) {
+ cpIndex = (cpIndex + 9973) % cpCount;
+ index = cpMap[cpIndex+1].nativeIdx;
+ expectedC = cpMap[cpIndex].cp;
+ foundC = utext_previous32From(ut, index);
+ TEST_ASSERT(expectedC == foundC);
+ if (gFailed) {
+ return;
+ }
+ }
+
+
+ //
+ // moveIndex(int32_t delta);
+ //
+
+ // Walk through frontwards, incrementing by one
+ utext_setNativeIndex(ut, 0);
+ for (i=1; i<=cpCount; i++) {
+ utext_moveIndex32(ut, 1);
+ index = utext_getNativeIndex(ut);
+ expectedIndex = cpMap[i].nativeIdx;
+ TEST_ASSERT(expectedIndex == index);
+ index = UTEXT_GETNATIVEINDEX(ut);
+ TEST_ASSERT(expectedIndex == index);
+ }
+
+ // Walk through frontwards, incrementing by two
+ utext_setNativeIndex(ut, 0);
+ for (i=2; i<cpCount; i+=2) {
+ utext_moveIndex32(ut, 2);
+ index = utext_getNativeIndex(ut);
+ expectedIndex = cpMap[i].nativeIdx;
+ TEST_ASSERT(expectedIndex == index);
+ index = UTEXT_GETNATIVEINDEX(ut);
+ TEST_ASSERT(expectedIndex == index);
+ }
+
+ // walk through the string backwards, decrementing by one.
+ i = cpMap[cpCount].nativeIdx;
+ utext_setNativeIndex(ut, i);
+ for (i=cpCount; i>=0; i--) {
+ expectedIndex = cpMap[i].nativeIdx;
+ index = utext_getNativeIndex(ut);
+ TEST_ASSERT(expectedIndex == index);
+ index = UTEXT_GETNATIVEINDEX(ut);
+ TEST_ASSERT(expectedIndex == index);
+ utext_moveIndex32(ut, -1);
+ }
+
+
+ // walk through backwards, decrementing by three
+ i = cpMap[cpCount].nativeIdx;
+ utext_setNativeIndex(ut, i);
+ for (i=cpCount; i>=0; i-=3) {
+ expectedIndex = cpMap[i].nativeIdx;
+ index = utext_getNativeIndex(ut);
+ TEST_ASSERT(expectedIndex == index);
+ index = UTEXT_GETNATIVEINDEX(ut);
+ TEST_ASSERT(expectedIndex == index);
+ utext_moveIndex32(ut, -3);
+ }
+
+
+ //
+ // Extract
+ //
+ int bufSize = us.length() + 10;
+ UChar *buf = new UChar[bufSize];
+ status = U_ZERO_ERROR;
+ expectedLen = us.length();
+ len = utext_extract(ut, 0, utlen, buf, bufSize, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(len == expectedLen);
+ int compareResult = us.compare(buf, -1);
+ TEST_ASSERT(compareResult == 0);
+
+ status = U_ZERO_ERROR;
+ len = utext_extract(ut, 0, utlen, NULL, 0, &status);
+ if (utlen == 0) {
+ TEST_ASSERT(status == U_STRING_NOT_TERMINATED_WARNING);
+ } else {
+ TEST_ASSERT(status == U_BUFFER_OVERFLOW_ERROR);
+ }
+ TEST_ASSERT(len == expectedLen);
+
+ status = U_ZERO_ERROR;
+ u_memset(buf, 0x5555, bufSize);
+ len = utext_extract(ut, 0, utlen, buf, 1, &status);
+ if (us.length() == 0) {
+ TEST_SUCCESS(status);
+ TEST_ASSERT(buf[0] == 0);
+ } else {
+ // Buf len == 1, extracting a single 16 bit value.
+ // If the data char is supplementary, it doesn't matter whether the buffer remains unchanged,
+ // or whether the lead surrogate of the pair is extracted.
+ // It's a buffer overflow error in either case.
+ TEST_ASSERT(buf[0] == us.charAt(0) ||
+ buf[0] == 0x5555 && U_IS_SUPPLEMENTARY(us.char32At(0)));
+ TEST_ASSERT(buf[1] == 0x5555);
+ if (us.length() == 1) {
+ TEST_ASSERT(status == U_STRING_NOT_TERMINATED_WARNING);
+ } else {
+ TEST_ASSERT(status == U_BUFFER_OVERFLOW_ERROR);
+ }
+ }
+
+ delete []buf;
+}
+
+
+
+//
+// ErrorTest() Check various error and edge cases.
+//
+void UTextTest::ErrorTest()
+{
+ // Close of an unitialized UText. Shouldn't blow up.
+ {
+ UText ut;
+ memset(&ut, 0, sizeof(UText));
+ utext_close(&ut);
+ utext_close(NULL);
+ }
+
+ // Double-close of a UText. Shouldn't blow up. UText should still be usable.
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UText ut = UTEXT_INITIALIZER;
+ UnicodeString s("Hello, World");
+ UText *ut2 = utext_openUnicodeString(&ut, &s, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(ut2 == &ut);
+
+ UText *ut3 = utext_close(&ut);
+ TEST_ASSERT(ut3 == &ut);
+
+ UText *ut4 = utext_close(&ut);
+ TEST_ASSERT(ut4 == &ut);
+
+ utext_openUnicodeString(&ut, &s, &status);
+ TEST_SUCCESS(status);
+ utext_close(&ut);
+ }
+
+ // Re-use of a UText, chaining through each of the types of UText
+ // (If it doesn't blow up, and doesn't leak, it's probably working fine)
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UText ut = UTEXT_INITIALIZER;
+ UText *utp;
+ UnicodeString s1("Hello, World");
+ UChar s2[] = {(UChar)0x41, (UChar)0x42, (UChar)0};
+ const char *s3 = "\x66\x67\x68";
+
+ utp = utext_openUnicodeString(&ut, &s1, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(utp == &ut);
+
+ utp = utext_openConstUnicodeString(&ut, &s1, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(utp == &ut);
+
+ utp = utext_openUTF8(&ut, s3, -1, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(utp == &ut);
+
+ utp = utext_openUChars(&ut, s2, -1, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(utp == &ut);
+
+ utp = utext_close(&ut);
+ TEST_ASSERT(utp == &ut);
+
+ utp = utext_openUnicodeString(&ut, &s1, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(utp == &ut);
+ }
+
+ //
+ // UTF-8 with malformed sequences.
+ // These should come through as the Unicode replacement char, \ufffd
+ //
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UText *ut = NULL;
+ const char *badUTF8 = "\x41\x81\x42\xf0\x81\x81\x43";
+ UChar32 c;
+
+ ut = utext_openUTF8(NULL, badUTF8, -1, &status);
+ TEST_SUCCESS(status);
+ c = utext_char32At(ut, 1);
+ TEST_ASSERT(c == 0xfffd);
+ c = utext_char32At(ut, 3);
+ TEST_ASSERT(c == 0xfffd);
+ c = utext_char32At(ut, 5);
+ TEST_ASSERT(c == 0xfffd);
+ c = utext_char32At(ut, 6);
+ TEST_ASSERT(c == 0x43);
+
+ UChar buf[10];
+ int n = utext_extract(ut, 0, 9, buf, 10, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(n==5);
+ TEST_ASSERT(buf[1] == 0xfffd);
+ TEST_ASSERT(buf[3] == 0xfffd);
+ TEST_ASSERT(buf[2] == 0x42);
+ utext_close(ut);
+ }
+
+
+ //
+ // isLengthExpensive - does it make the exptected transitions after
+ // getting the length of a nul terminated string?
+ //
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString sa("Hello, this is a string");
+ UBool isExpensive;
+
+ UChar sb[100];
+ memset(sb, 0x20, sizeof(sb));
+ sb[99] = 0;
+
+ UText *uta = utext_openUnicodeString(NULL, &sa, &status);
+ TEST_SUCCESS(status);
+ isExpensive = utext_isLengthExpensive(uta);
+ TEST_ASSERT(isExpensive == FALSE);
+ utext_close(uta);
+
+ UText *utb = utext_openUChars(NULL, sb, -1, &status);
+ TEST_SUCCESS(status);
+ isExpensive = utext_isLengthExpensive(utb);
+ TEST_ASSERT(isExpensive == TRUE);
+ int64_t len = utext_nativeLength(utb);
+ TEST_ASSERT(len == 99);
+ isExpensive = utext_isLengthExpensive(utb);
+ TEST_ASSERT(isExpensive == FALSE);
+ utext_close(utb);
+ }
+
+ //
+ // Index to positions not on code point boundaries.
+ //
+ {
+ const char *u8str = "\xc8\x81\xe1\x82\x83\xf1\x84\x85\x86";
+ int32_t startMap[] = { 0, 0, 2, 2, 2, 5, 5, 5, 5, 9, 9};
+ int32_t nextMap[] = { 2, 2, 5, 5, 5, 9, 9, 9, 9, 9, 9};
+ int32_t prevMap[] = { 0, 0, 0, 0, 0, 2, 2, 2, 2, 5, 5};
+ UChar32 c32Map[] = {0x201, 0x201, 0x1083, 0x1083, 0x1083, 0x044146, 0x044146, 0x044146, 0x044146, -1, -1};
+ UChar32 pr32Map[] = { -1, -1, 0x201, 0x201, 0x201, 0x1083, 0x1083, 0x1083, 0x1083, 0x044146, 0x044146};
+
+ // extractLen is the size, in UChars, of what will be extracted between index and index+1.
+ // is zero when both index positions lie within the same code point.
+ int32_t exLen[] = { 0, 1, 0, 0, 1, 0, 0, 0, 2, 0, 0};
+
+
+ UErrorCode status = U_ZERO_ERROR;
+ UText *ut = utext_openUTF8(NULL, u8str, -1, &status);
+ TEST_SUCCESS(status);
+
+ // Check setIndex
+ int32_t i;
+ int32_t startMapLimit = sizeof(startMap) / sizeof(int32_t);
+ for (i=0; i<startMapLimit; i++) {
+ utext_setNativeIndex(ut, i);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == startMap[i]);
+ cpIndex = UTEXT_GETNATIVEINDEX(ut);
+ TEST_ASSERT(cpIndex == startMap[i]);
+ }
+
+ // Check char32At
+ for (i=0; i<startMapLimit; i++) {
+ UChar32 c32 = utext_char32At(ut, i);
+ TEST_ASSERT(c32 == c32Map[i]);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == startMap[i]);
+ }
+
+ // Check utext_next32From
+ for (i=0; i<startMapLimit; i++) {
+ UChar32 c32 = utext_next32From(ut, i);
+ TEST_ASSERT(c32 == c32Map[i]);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == nextMap[i]);
+ }
+
+ // check utext_previous32From
+ for (i=0; i<startMapLimit; i++) {
+ gTestNum++;
+ UChar32 c32 = utext_previous32From(ut, i);
+ TEST_ASSERT(c32 == pr32Map[i]);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == prevMap[i]);
+ }
+
+ // check Extract
+ // Extract from i to i+1, which may be zero or one code points,
+ // depending on whether the indices straddle a cp boundary.
+ for (i=0; i<startMapLimit; i++) {
+ UChar buf[3];
+ status = U_ZERO_ERROR;
+ int32_t extractedLen = utext_extract(ut, i, i+1, buf, 3, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(extractedLen == exLen[i]);
+ if (extractedLen > 0) {
+ UChar32 c32;
+ /* extractedLen-extractedLen == 0 is used to get around a compiler warning. */
+ U16_GET(buf, 0, extractedLen-extractedLen, extractedLen, c32);
+ TEST_ASSERT(c32 == c32Map[i]);
+ }
+ }
+
+ utext_close(ut);
+ }
+
+
+ { // Similar test, with utf16 instead of utf8
+ // TODO: merge the common parts of these tests.
+
+ UnicodeString u16str("\\u1000\\U00011000\\u2000\\U00022000");
+ int32_t startMap[] ={ 0, 1, 1, 3, 4, 4, 6, 6};
+ int32_t nextMap[] = { 1, 3, 3, 4, 6, 6, 6, 6};
+ int32_t prevMap[] = { 0, 0, 0, 1, 3, 3, 4, 4};
+ UChar32 c32Map[] = {0x1000, 0x11000, 0x11000, 0x2000, 0x22000, 0x22000, -1, -1};
+ UChar32 pr32Map[] = { -1, 0x1000, 0x1000, 0x11000, 0x2000, 0x2000, 0x22000, 0x22000};
+ int32_t exLen[] = { 1, 0, 2, 1, 0, 2, 0, 0,};
+
+ u16str = u16str.unescape();
+ UErrorCode status = U_ZERO_ERROR;
+ UText *ut = utext_openUnicodeString(NULL, &u16str, &status);
+ TEST_SUCCESS(status);
+
+ int32_t startMapLimit = sizeof(startMap) / sizeof(int32_t);
+ int i;
+ for (i=0; i<startMapLimit; i++) {
+ utext_setNativeIndex(ut, i);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == startMap[i]);
+ }
+
+ // Check char32At
+ for (i=0; i<startMapLimit; i++) {
+ UChar32 c32 = utext_char32At(ut, i);
+ TEST_ASSERT(c32 == c32Map[i]);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == startMap[i]);
+ }
+
+ // Check utext_next32From
+ for (i=0; i<startMapLimit; i++) {
+ UChar32 c32 = utext_next32From(ut, i);
+ TEST_ASSERT(c32 == c32Map[i]);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == nextMap[i]);
+ }
+
+ // check utext_previous32From
+ for (i=0; i<startMapLimit; i++) {
+ UChar32 c32 = utext_previous32From(ut, i);
+ TEST_ASSERT(c32 == pr32Map[i]);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == prevMap[i]);
+ }
+
+ // check Extract
+ // Extract from i to i+1, which may be zero or one code points,
+ // depending on whether the indices straddle a cp boundary.
+ for (i=0; i<startMapLimit; i++) {
+ UChar buf[3];
+ status = U_ZERO_ERROR;
+ int32_t extractedLen = utext_extract(ut, i, i+1, buf, 3, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(extractedLen == exLen[i]);
+ if (extractedLen > 0) {
+ UChar32 c32;
+ /* extractedLen-extractedLen == 0 is used to get around a compiler warning. */
+ U16_GET(buf, 0, extractedLen-extractedLen, extractedLen, c32);
+ TEST_ASSERT(c32 == c32Map[i]);
+ }
+ }
+
+ utext_close(ut);
+ }
+
+ { // Similar test, with UText over Replaceable
+ // TODO: merge the common parts of these tests.
+
+ UnicodeString u16str("\\u1000\\U00011000\\u2000\\U00022000");
+ int32_t startMap[] ={ 0, 1, 1, 3, 4, 4, 6, 6};
+ int32_t nextMap[] = { 1, 3, 3, 4, 6, 6, 6, 6};
+ int32_t prevMap[] = { 0, 0, 0, 1, 3, 3, 4, 4};
+ UChar32 c32Map[] = {0x1000, 0x11000, 0x11000, 0x2000, 0x22000, 0x22000, -1, -1};
+ UChar32 pr32Map[] = { -1, 0x1000, 0x1000, 0x11000, 0x2000, 0x2000, 0x22000, 0x22000};
+ int32_t exLen[] = { 1, 0, 2, 1, 0, 2, 0, 0,};
+
+ u16str = u16str.unescape();
+ UErrorCode status = U_ZERO_ERROR;
+ UText *ut = utext_openReplaceable(NULL, &u16str, &status);
+ TEST_SUCCESS(status);
+
+ int32_t startMapLimit = sizeof(startMap) / sizeof(int32_t);
+ int i;
+ for (i=0; i<startMapLimit; i++) {
+ utext_setNativeIndex(ut, i);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == startMap[i]);
+ }
+
+ // Check char32At
+ for (i=0; i<startMapLimit; i++) {
+ UChar32 c32 = utext_char32At(ut, i);
+ TEST_ASSERT(c32 == c32Map[i]);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == startMap[i]);
+ }
+
+ // Check utext_next32From
+ for (i=0; i<startMapLimit; i++) {
+ UChar32 c32 = utext_next32From(ut, i);
+ TEST_ASSERT(c32 == c32Map[i]);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == nextMap[i]);
+ }
+
+ // check utext_previous32From
+ for (i=0; i<startMapLimit; i++) {
+ UChar32 c32 = utext_previous32From(ut, i);
+ TEST_ASSERT(c32 == pr32Map[i]);
+ int64_t cpIndex = utext_getNativeIndex(ut);
+ TEST_ASSERT(cpIndex == prevMap[i]);
+ }
+
+ // check Extract
+ // Extract from i to i+1, which may be zero or one code points,
+ // depending on whether the indices straddle a cp boundary.
+ for (i=0; i<startMapLimit; i++) {
+ UChar buf[3];
+ status = U_ZERO_ERROR;
+ int32_t extractedLen = utext_extract(ut, i, i+1, buf, 3, &status);
+ TEST_SUCCESS(status);
+ TEST_ASSERT(extractedLen == exLen[i]);
+ if (extractedLen > 0) {
+ UChar32 c32;
+ /* extractedLen-extractedLen == 0 is used to get around a compiler warning. */
+ U16_GET(buf, 0, extractedLen-extractedLen, extractedLen, c32);
+ TEST_ASSERT(c32 == c32Map[i]);
+ }
+ }
+
+ utext_close(ut);
+ }
+}
+
+
+void UTextTest::FreezeTest() {
+ // Check isWritable() and freeze() behavior.
+ //
+
+ UnicodeString ustr("Hello, World.");
+ const char u8str[] = {char(0x31), (char)0x32, (char)0x33, 0};
+ const UChar u16str[] = {(UChar)0x31, (UChar)0x32, (UChar)0x44, 0};
+
+ UErrorCode status = U_ZERO_ERROR;
+ UText *ut = NULL;
+ UText *ut2 = NULL;
+
+ ut = utext_openUTF8(ut, u8str, -1, &status);
+ TEST_SUCCESS(status);
+ UBool writable = utext_isWritable(ut);
+ TEST_ASSERT(writable == FALSE);
+ utext_copy(ut, 1, 2, 0, TRUE, &status);
+ TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
+
+ status = U_ZERO_ERROR;
+ ut = utext_openUChars(ut, u16str, -1, &status);
+ TEST_SUCCESS(status);
+ writable = utext_isWritable(ut);
+ TEST_ASSERT(writable == FALSE);
+ utext_copy(ut, 1, 2, 0, TRUE, &status);
+ TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
+
+ status = U_ZERO_ERROR;
+ ut = utext_openUnicodeString(ut, &ustr, &status);
+ TEST_SUCCESS(status);
+ writable = utext_isWritable(ut);
+ TEST_ASSERT(writable == TRUE);
+ utext_freeze(ut);
+ writable = utext_isWritable(ut);
+ TEST_ASSERT(writable == FALSE);
+ utext_copy(ut, 1, 2, 0, TRUE, &status);
+ TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
+
+ status = U_ZERO_ERROR;
+ ut = utext_openUnicodeString(ut, &ustr, &status);
+ TEST_SUCCESS(status);
+ ut2 = utext_clone(ut2, ut, FALSE, FALSE, &status); // clone with readonly = false
+ TEST_SUCCESS(status);
+ writable = utext_isWritable(ut2);
+ TEST_ASSERT(writable == TRUE);
+ ut2 = utext_clone(ut2, ut, FALSE, TRUE, &status); // clone with readonly = true
+ TEST_SUCCESS(status);
+ writable = utext_isWritable(ut2);
+ TEST_ASSERT(writable == FALSE);
+ utext_copy(ut2, 1, 2, 0, TRUE, &status);
+ TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
+
+ status = U_ZERO_ERROR;
+ ut = utext_openConstUnicodeString(ut, (const UnicodeString *)&ustr, &status);
+ TEST_SUCCESS(status);
+ writable = utext_isWritable(ut);
+ TEST_ASSERT(writable == FALSE);
+ utext_copy(ut, 1, 2, 0, TRUE, &status);
+ TEST_ASSERT(status == U_NO_WRITE_PERMISSION);
+
+ // Deep Clone of a frozen UText should re-enable writing in the copy.
+ status = U_ZERO_ERROR;
+ ut = utext_openUnicodeString(ut, &ustr, &status);
+ TEST_SUCCESS(status);
+ utext_freeze(ut);
+ ut2 = utext_clone(ut2, ut, TRUE, FALSE, &status); // deep clone
+ TEST_SUCCESS(status);
+ writable = utext_isWritable(ut2);
+ TEST_ASSERT(writable == TRUE);
+
+
+ // Deep clone of a frozen UText, where the base type is intrinsically non-writable,
+ // should NOT enable writing in the copy.
+ status = U_ZERO_ERROR;
+ ut = utext_openUChars(ut, u16str, -1, &status);
+ TEST_SUCCESS(status);
+ utext_freeze(ut);
+ ut2 = utext_clone(ut2, ut, TRUE, FALSE, &status); // deep clone
+ TEST_SUCCESS(status);
+ writable = utext_isWritable(ut2);
+ TEST_ASSERT(writable == FALSE);
+
+ // cleanup
+ utext_close(ut);
+ utext_close(ut2);
+}
+
+
+//
+// Fragmented UText
+// A UText type that works with a chunk size of 1.
+// Intended to test for edge cases.
+// Input comes from a UnicodeString.
+//
+// ut.b the character. Put into both halves.
+//
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV
+fragTextAccess(UText *ut, int64_t index, UBool forward) {
+ const UnicodeString *us = (const UnicodeString *)ut->context;
+ UChar c;
+ int32_t length = us->length();
+ if (forward && index>=0 && index<length) {
+ c = us->charAt((int32_t)index);
+ ut->b = c | c<<16;
+ ut->chunkOffset = 0;
+ ut->chunkLength = 1;
+ ut->chunkNativeStart = index;
+ ut->chunkNativeLimit = index+1;
+ return true;
+ }
+ if (!forward && index>0 && index <=length) {
+ c = us->charAt((int32_t)index-1);
+ ut->b = c | c<<16;
+ ut->chunkOffset = 1;
+ ut->chunkLength = 1;
+ ut->chunkNativeStart = index-1;
+ ut->chunkNativeLimit = index;
+ return true;
+ }
+ ut->b = 0;
+ ut->chunkOffset = 0;
+ ut->chunkLength = 0;
+ if (index <= 0) {
+ ut->chunkNativeStart = 0;
+ ut->chunkNativeLimit = 0;
+ } else {
+ ut->chunkNativeStart = length;
+ ut->chunkNativeLimit = length;
+ }
+ return false;
+}
+
+// Function table to be used with this fragmented text provider.
+// Initialized in the open function.
+static UTextFuncs fragmentFuncs;
+
+// Clone function for fragmented text provider.
+// Didn't really want to provide this, but it's easier to provide it than to keep it
+// out of the tests.
+//
+UText *
+cloneFragmentedUnicodeString(UText *dest, const UText *src, UBool deep, UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ if (deep) {
+ *status = U_UNSUPPORTED_ERROR;
+ return NULL;
+ }
+ dest = utext_openUnicodeString(dest, (UnicodeString *)src->context, status);
+ utext_setNativeIndex(dest, utext_getNativeIndex(src));
+ return dest;
+}
+
+U_CDECL_END
+
+// Open function for the fragmented text provider.
+UText *
+openFragmentedUnicodeString(UText *ut, UnicodeString *s, UErrorCode *status) {
+ ut = utext_openUnicodeString(ut, s, status);
+ if (U_FAILURE(*status)) {
+ return ut;
+ }
+
+ // Copy of the function table from the stock UnicodeString UText,
+ // and replace the entry for the access function.
+ memcpy(&fragmentFuncs, ut->pFuncs, sizeof(fragmentFuncs));
+ fragmentFuncs.access = fragTextAccess;
+ fragmentFuncs.clone = cloneFragmentedUnicodeString;
+ ut->pFuncs = &fragmentFuncs;
+
+ ut->chunkContents = (UChar *)&ut->b;
+ ut->pFuncs->access(ut, 0, TRUE);
+ return ut;
+}
+
+// Regression test for Ticket 5560
+// Clone fails to update chunkContentPointer in the cloned copy.
+// This is only an issue for UText types that work in a local buffer,
+// (UTF-8 wrapper, for example)
+//
+// The test:
+// 1. Create an inital UText
+// 2. Deep clone it. Contents should match original.
+// 3. Reset original to something different.
+// 4. Check that clone contents did not change.
+//
+void UTextTest::Ticket5560() {
+ /* The following two strings are in UTF-8 even on EBCDIC platforms. */
+ static const char s1[] = {0x41,0x42,0x43,0x44,0x45,0x46,0}; /* "ABCDEF" */
+ static const char s2[] = {0x31,0x32,0x33,0x34,0x35,0x36,0}; /* "123456" */
+ UErrorCode status = U_ZERO_ERROR;
+
+ UText ut1 = UTEXT_INITIALIZER;
+ UText ut2 = UTEXT_INITIALIZER;
+
+ utext_openUTF8(&ut1, s1, -1, &status);
+ UChar c = utext_next32(&ut1);
+ TEST_ASSERT(c == 0x41); // c == 'A'
+
+ utext_clone(&ut2, &ut1, TRUE, FALSE, &status);
+ TEST_SUCCESS(status);
+ c = utext_next32(&ut2);
+ TEST_ASSERT(c == 0x42); // c == 'B'
+ c = utext_next32(&ut1);
+ TEST_ASSERT(c == 0x42); // c == 'B'
+
+ utext_openUTF8(&ut1, s2, -1, &status);
+ c = utext_next32(&ut1);
+ TEST_ASSERT(c == 0x31); // c == '1'
+ c = utext_next32(&ut2);
+ TEST_ASSERT(c == 0x43); // c == 'C'
+
+ utext_close(&ut1);
+ utext_close(&ut2);
+}
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/utxttest.h b/Build/source/libs/icu/icu-xetex/test/intltest/utxttest.h
new file mode 100644
index 00000000000..ca1e2f605eb
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/utxttest.h
@@ -0,0 +1,61 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2005-2007, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+/************************************************************************
+* Tests for the UText and UTextIterator text abstraction classses
+*
+************************************************************************/
+
+
+#ifndef UTXTTEST_H
+#define UTXTTEST_H
+
+#include "unicode/utypes.h"
+#include "unicode/unistr.h"
+#include "unicode/utext.h"
+
+#include "intltest.h"
+
+/**
+ * @test
+ * @summary Testing the Replaceable class
+ */
+class UTextTest : public IntlTest {
+public:
+ UTextTest();
+ virtual ~UTextTest();
+
+ void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par=NULL);
+ void TextTest();
+ void ErrorTest();
+ void FreezeTest();
+ void Ticket5560();
+
+private:
+ struct m { // Map between native indices & code points.
+ int nativeIdx;
+ UChar32 cp;
+ };
+
+ void TestString(const UnicodeString &s);
+ void TestAccess(const UnicodeString &us, UText *ut, int cpCount, m *cpMap);
+ void TestAccessNoClone(const UnicodeString &us, UText *ut, int cpCount, m *cpMap);
+ void TestCMR (const UnicodeString &us, UText *ut, int cpCount, m *nativeMap, m *utf16Map);
+ void TestCopyMove(const UnicodeString &us, UText *ut, UBool move,
+ int32_t nativeStart, int32_t nativeLimit, int32_t nativeDest,
+ int32_t u16Start, int32_t u16Limit, int32_t u16Dest);
+ void TestReplace(const UnicodeString &us, // reference UnicodeString in which to do the replace
+ UText *ut, // UnicodeText object under test.
+ int32_t nativeStart, // Range to be replaced, in UText native units.
+ int32_t nativeLimit,
+ int32_t u16Start, // Range to be replaced, in UTF-16 units
+ int32_t u16Limit, // for use in the reference UnicodeString.
+ const UnicodeString &repStr); // The replacement string
+
+
+};
+
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/uvectest.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/uvectest.cpp
new file mode 100644
index 00000000000..434876f90f2
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/uvectest.cpp
@@ -0,0 +1,200 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2004-2006, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+// Test parts of UVector and UStack
+
+#include "intltest.h"
+
+#include "uvectest.h"
+#include "uvector.h"
+#include "hash.h"
+
+#include "cstring.h"
+
+//---------------------------------------------------------------------------
+//
+// Test class boilerplate
+//
+//---------------------------------------------------------------------------
+UVectorTest::UVectorTest()
+{
+}
+
+
+UVectorTest::~UVectorTest()
+{
+}
+
+
+
+void UVectorTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite UVectorTest: ");
+ switch (index) {
+
+ case 0: name = "UVector_API";
+ if (exec) UVector_API();
+ break;
+ case 1: name = "UStack_API";
+ if (exec) UStack_API();
+ break;
+ case 2: name = "Hashtable_API";
+ if (exec) Hashtable_API();
+ break;
+ default: name = "";
+ break; //needed to end loop
+ }
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Error Checking / Reporting macros used in all of the tests.
+//
+//---------------------------------------------------------------------------
+#define TEST_CHECK_STATUS(status) \
+ if (U_FAILURE(status)) {\
+ errln("UVectorTest failure at line %d. status=%s\n", __LINE__, u_errorName(status));\
+ return;\
+ }
+
+#define TEST_ASSERT(expr) \
+ if ((expr)==FALSE) {\
+ errln("UVectorTest failure at line %d.\n", __LINE__);\
+ }
+
+static int8_t
+UVectorTest_compareInt32(UHashTok key1, UHashTok key2) {
+ if (key1.integer > key2.integer) {
+ return 1;
+ }
+ else if (key1.integer < key2.integer) {
+ return -1;
+ }
+ return 0;
+}
+
+U_CDECL_BEGIN
+static int8_t U_CALLCONV
+UVectorTest_compareCstrings(const UHashTok key1, const UHashTok key2) {
+ return !strcmp((const char *)key1.pointer, (const char *)key2.pointer);
+}
+U_CDECL_END
+
+//---------------------------------------------------------------------------
+//
+// UVector_API Check for basic functionality of UVector.
+//
+//---------------------------------------------------------------------------
+void UVectorTest::UVector_API() {
+
+ UErrorCode status = U_ZERO_ERROR;
+ UVector *a;
+
+ a = new UVector(status);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ status = U_ZERO_ERROR;
+ a = new UVector(2000, status);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ status = U_ZERO_ERROR;
+ a = new UVector(status);
+ a->sortedInsert((int32_t)10, UVectorTest_compareInt32, status);
+ a->sortedInsert((int32_t)20, UVectorTest_compareInt32, status);
+ a->sortedInsert((int32_t)30, UVectorTest_compareInt32, status);
+ a->sortedInsert((int32_t)15, UVectorTest_compareInt32, status);
+ TEST_CHECK_STATUS(status);
+ TEST_ASSERT(a->elementAti(0) == 10);
+ TEST_ASSERT(a->elementAti(1) == 15);
+ TEST_ASSERT(a->elementAti(2) == 20);
+ TEST_ASSERT(a->elementAti(3) == 30);
+ TEST_ASSERT(a->indexOf((int32_t)3) == -1);
+ TEST_ASSERT(a->indexOf((int32_t)15) == 1);
+ TEST_ASSERT(a->indexOf((int32_t)15, 2) == -1);
+ TEST_ASSERT(a->contains((int32_t)15));
+ TEST_ASSERT(!a->contains((int32_t)5));
+ delete a;
+}
+
+void UVectorTest::UStack_API() {
+ UErrorCode status = U_ZERO_ERROR;
+ UStack *a;
+
+ a = new UStack(status);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ status = U_ZERO_ERROR;
+ a = new UStack(2000, status);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ status = U_ZERO_ERROR;
+ a = new UStack(NULL, NULL, 2000, status);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ status = U_ZERO_ERROR;
+ a = new UStack(NULL, UVectorTest_compareCstrings, status);
+ TEST_ASSERT(a->empty());
+ a->push((void*)"abc", status);
+ TEST_ASSERT(!a->empty());
+ a->push((void*)"bcde", status);
+ a->push((void*)"cde", status);
+ TEST_CHECK_STATUS(status);
+ TEST_ASSERT(strcmp("cde", (const char *)a->peek()) == 0);
+ TEST_ASSERT(a->search((void*)"cde") == 1);
+ TEST_ASSERT(a->search((void*)"bcde") == 2);
+ TEST_ASSERT(a->search((void*)"abc") == 3);
+ TEST_ASSERT(strcmp("abc", (const char *)a->firstElement()) == 0);
+ TEST_ASSERT(strcmp("cde", (const char *)a->lastElement()) == 0);
+ TEST_ASSERT(strcmp("cde", (const char *)a->pop()) == 0);
+ TEST_ASSERT(strcmp("bcde", (const char *)a->pop()) == 0);
+ TEST_ASSERT(strcmp("abc", (const char *)a->pop()) == 0);
+ delete a;
+}
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV neverTRUE(const UHashTok /*key1*/, const UHashTok /*key2*/) {
+ return FALSE;
+}
+
+U_CDECL_END
+
+void UVectorTest::Hashtable_API() {
+ UErrorCode status = U_ZERO_ERROR;
+ Hashtable *a = new Hashtable(status);
+ TEST_ASSERT((a->puti("a", 1, status) == 0));
+ TEST_ASSERT((a->find("a") != NULL));
+ TEST_ASSERT((a->find("b") == NULL));
+ TEST_ASSERT((a->puti("b", 2, status) == 0));
+ TEST_ASSERT((a->find("b") != NULL));
+ TEST_ASSERT((a->removei("a") == 1));
+ TEST_ASSERT((a->find("a") == NULL));
+
+ /* verify that setValueCompartor works */
+ Hashtable b(status);
+ TEST_ASSERT((!a->equals(b)));
+ TEST_ASSERT((b.puti("b", 2, status) == 0));
+ TEST_ASSERT((!a->equals(b))); // Without a value comparator, this will be FALSE by default.
+ b.setValueCompartor(uhash_compareLong);
+ TEST_ASSERT((!a->equals(b)));
+ a->setValueCompartor(uhash_compareLong);
+ TEST_ASSERT((a->equals(b)));
+ TEST_ASSERT((a->equals(*a))); // This better be reflexive.
+
+ /* verify that setKeyCompartor works */
+ TEST_ASSERT((a->puti("a", 1, status) == 0));
+ TEST_ASSERT((a->find("a") != NULL));
+ a->setKeyCompartor(neverTRUE);
+ TEST_ASSERT((a->find("a") == NULL));
+
+ delete a;
+}
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/uvectest.h b/Build/source/libs/icu/icu-xetex/test/intltest/uvectest.h
new file mode 100644
index 00000000000..84a3e24fdb6
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/uvectest.h
@@ -0,0 +1,34 @@
+/*
+******************************************************************************
+* Copyright (C) 2004, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+******************************************************************************
+*/
+
+// file: uvectest.h
+
+
+#ifndef UVECTEST_H
+#define UVECTEST_H
+
+#include "unicode/utypes.h"
+
+#include "intltest.h"
+
+
+class UVectorTest: public IntlTest {
+public:
+
+ UVectorTest();
+ virtual ~UVectorTest();
+
+ virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // The following are test functions that are visible from the intltest test framework.
+ void UVector_API();
+ void UStack_API();
+ void Hashtable_API();
+
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/v32test.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/v32test.cpp
new file mode 100644
index 00000000000..c668a38ce64
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/v32test.cpp
@@ -0,0 +1,495 @@
+/********************************************************************
+ * COPYRIGHT:
+ * Copyright (c) 2002-2003, International Business Machines Corporation and
+ * others. All Rights Reserved.
+ ********************************************************************/
+
+//
+// regextst.cpp
+//
+// ICU Regular Expressions test, part of intltest.
+//
+
+#include "intltest.h"
+
+#include "v32test.h"
+#include "uvectr32.h"
+#include "uvector.h"
+#include "util.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+
+//---------------------------------------------------------------------------
+//
+// Test class boilerplate
+//
+//---------------------------------------------------------------------------
+UVector32Test::UVector32Test()
+{
+}
+
+
+UVector32Test::~UVector32Test()
+{
+}
+
+
+
+void UVector32Test::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
+{
+ if (exec) logln("TestSuite UVector32Test: ");
+ switch (index) {
+
+ case 0: name = "UVector32_API";
+ if (exec) UVector32_API();
+ break;
+ default: name = "";
+ break; //needed to end loop
+ }
+}
+
+
+//---------------------------------------------------------------------------
+//
+// Error Checking / Reporting macros used in all of the tests.
+//
+//---------------------------------------------------------------------------
+#define TEST_CHECK_STATUS(status) \
+ if (U_FAILURE(status)) {\
+ errln("UVector32Test failure at line %d. status=%s\n", __LINE__, u_errorName(status));\
+ return;\
+ }
+
+#define TEST_ASSERT(expr) \
+ if ((expr)==FALSE) {\
+ errln("RegexTest failure at line %d.\n", __LINE__);\
+ }
+
+//---------------------------------------------------------------------------
+//
+// UVector32_API Check for basic functionality of UVector32.
+//
+//---------------------------------------------------------------------------
+void UVector32Test::UVector32_API() {
+
+ UErrorCode status = U_ZERO_ERROR;
+ UVector32 *a;
+ UVector32 *b;
+
+ a = new UVector32(status);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ status = U_ZERO_ERROR;
+ a = new UVector32(2000, status);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ //
+ // assign()
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ b = new UVector32(status);
+ b->assign(*a, status);
+ TEST_ASSERT(b->size() == 3);
+ TEST_ASSERT(b->elementAti(1) == 20);
+ TEST_CHECK_STATUS(status);
+ delete a;
+ delete b;
+
+ //
+ // operator == and != and equals()
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ b = new UVector32(status);
+ TEST_ASSERT(*b != *a);
+ TEST_ASSERT(!(*b == *a));
+ TEST_ASSERT(!b->equals(*a));
+ b->assign(*a, status);
+ TEST_ASSERT(*b == *a);
+ TEST_ASSERT(!(*b != *a));
+ TEST_ASSERT(b->equals(*a));
+ b->addElement(666, status);
+ TEST_ASSERT(*b != *a);
+ TEST_ASSERT(!(*b == *a));
+ TEST_ASSERT(!b->equals(*a));
+ TEST_CHECK_STATUS(status);
+ delete b;
+ delete a;
+
+ //
+ // addElement(). Covered by above tests.
+ //
+
+ //
+ // setElementAt()
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ a->setElementAt(666, 1);
+ TEST_ASSERT(a->elementAti(0) == 10);
+ TEST_ASSERT(a->elementAti(1) == 666);
+ TEST_ASSERT(a->size() == 3);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ //
+ // insertElementAt()
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ a->insertElementAt(666, 1, status);
+ TEST_ASSERT(a->elementAti(0) == 10);
+ TEST_ASSERT(a->elementAti(1) == 666);
+ TEST_ASSERT(a->elementAti(2) == 20);
+ TEST_ASSERT(a->elementAti(3) == 30);
+ TEST_ASSERT(a->size() == 4);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ //
+ // elementAti() covered by above tests
+ //
+
+ //
+ // lastElementi
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ TEST_ASSERT(a->lastElementi() == 30);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+
+ //
+ // indexOf
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ TEST_ASSERT(a->indexOf(30, 0) == 2);
+ TEST_ASSERT(a->indexOf(40, 0) == -1);
+ TEST_ASSERT(a->indexOf(10, 0) == 0);
+ TEST_ASSERT(a->indexOf(10, 1) == -1);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+
+ //
+ // contains
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ TEST_ASSERT(a->contains(10) == TRUE);
+ TEST_ASSERT(a->contains(11) == FALSE);
+ TEST_ASSERT(a->contains(20) == TRUE);
+ TEST_ASSERT(a->contains(-10) == FALSE);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+
+ //
+ // containsAll
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ b = new UVector32(status);
+ TEST_ASSERT(a->containsAll(*b) == TRUE);
+ b->addElement(2, status);
+ TEST_ASSERT(a->containsAll(*b) == FALSE);
+ b->setElementAt(10, 0);
+ TEST_ASSERT(a->containsAll(*b) == TRUE);
+ TEST_ASSERT(b->containsAll(*a) == FALSE);
+ b->addElement(30, status);
+ b->addElement(20, status);
+ TEST_ASSERT(a->containsAll(*b) == TRUE);
+ TEST_ASSERT(b->containsAll(*a) == TRUE);
+ b->addElement(2, status);
+ TEST_ASSERT(a->containsAll(*b) == FALSE);
+ TEST_ASSERT(b->containsAll(*a) == TRUE);
+ TEST_CHECK_STATUS(status);
+ delete a;
+ delete b;
+
+ //
+ // removeAll
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ b = new UVector32(status);
+ a->removeAll(*b);
+ TEST_ASSERT(a->size() == 3);
+ b->addElement(20, status);
+ a->removeAll(*b);
+ TEST_ASSERT(a->size() == 2);
+ TEST_ASSERT(a->contains(10)==TRUE);
+ TEST_ASSERT(a->contains(30)==TRUE);
+ b->addElement(10, status);
+ a->removeAll(*b);
+ TEST_ASSERT(a->size() == 1);
+ TEST_ASSERT(a->contains(30) == TRUE);
+ TEST_CHECK_STATUS(status);
+ delete a;
+ delete b;
+
+ //
+ // retainAll
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ b = new UVector32(status);
+ b->addElement(10, status);
+ b->addElement(20, status);
+ b->addElement(30, status);
+ b->addElement(15, status);
+ a->retainAll(*b);
+ TEST_ASSERT(a->size() == 3);
+ b->removeElementAt(1);
+ a->retainAll(*b);
+ TEST_ASSERT(a->contains(20) == FALSE);
+ TEST_ASSERT(a->size() == 2);
+ b->removeAllElements();
+ TEST_ASSERT(b->size() == 0);
+ a->retainAll(*b);
+ TEST_ASSERT(a->size() == 0);
+ TEST_CHECK_STATUS(status);
+ delete a;
+ delete b;
+
+ //
+ // removeElementAt Tested above.
+ //
+
+ //
+ // removeAllElments Tested above
+ //
+
+ //
+ // size() tested above
+ //
+
+ //
+ // isEmpty
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ TEST_ASSERT(a->isEmpty() == TRUE);
+ a->addElement(10, status);
+ TEST_ASSERT(a->isEmpty() == FALSE);
+ a->addElement(20, status);
+ a->removeElementAt(0);
+ TEST_ASSERT(a->isEmpty() == FALSE);
+ a->removeElementAt(0);
+ TEST_ASSERT(a->isEmpty() == TRUE);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+
+ //
+ // ensureCapacity, expandCapacity
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ TEST_ASSERT(a->isEmpty() == TRUE);
+ a->addElement(10, status);
+ TEST_ASSERT(a->ensureCapacity(5000, status)== TRUE);
+ TEST_ASSERT(a->expandCapacity(20000, status) == TRUE);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ //
+ // setSize
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ a->setSize(100);
+ TEST_ASSERT(a->size() == 100);
+ TEST_ASSERT(a->elementAti(0) == 10);
+ TEST_ASSERT(a->elementAti(1) == 20);
+ TEST_ASSERT(a->elementAti(2) == 30);
+ TEST_ASSERT(a->elementAti(3) == 0);
+ a->setElementAt(666, 99);
+ a->setElementAt(777, 100);
+ TEST_ASSERT(a->elementAti(99) == 666);
+ TEST_ASSERT(a->elementAti(100) == 0);
+ a->setSize(2);
+ TEST_ASSERT(a->elementAti(1) == 20);
+ TEST_ASSERT(a->elementAti(2) == 0);
+ TEST_ASSERT(a->size() == 2);
+ a->setSize(0);
+ TEST_ASSERT(a->empty() == TRUE);
+ TEST_ASSERT(a->size() == 0);
+
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ //
+ // containsNone
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ b = new UVector32(status);
+ TEST_ASSERT(a->containsNone(*b) == TRUE);
+ b->addElement(5, status);
+ TEST_ASSERT(a->containsNone(*b) == TRUE);
+ b->addElement(30, status);
+ TEST_ASSERT(a->containsNone(*b) == FALSE);
+
+ TEST_CHECK_STATUS(status);
+ delete a;
+ delete b;
+
+ //
+ // sortedInsert
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->sortedInsert(30, status);
+ a->sortedInsert(20, status);
+ a->sortedInsert(10, status);
+ TEST_ASSERT(a->elementAti(0) == 10);
+ TEST_ASSERT(a->elementAti(1) == 20);
+ TEST_ASSERT(a->elementAti(2) == 30);
+
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ //
+ // getBuffer
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ int32_t *buf = a->getBuffer();
+ TEST_ASSERT(buf[0] == 10);
+ TEST_ASSERT(buf[1] == 20);
+ a->setSize(20000);
+ int32_t *resizedBuf;
+ resizedBuf = a->getBuffer();
+ TEST_ASSERT(buf != resizedBuf);
+ TEST_ASSERT(resizedBuf[0] == 10);
+ TEST_ASSERT(resizedBuf[1] == 20);
+
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+
+ //
+ // empty
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ TEST_ASSERT(a->empty() == TRUE);
+ a->addElement(10, status);
+ TEST_ASSERT(a->empty() == FALSE);
+ a->addElement(20, status);
+ a->removeElementAt(0);
+ TEST_ASSERT(a->empty() == FALSE);
+ a->removeElementAt(0);
+ TEST_ASSERT(a->empty() == TRUE);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+
+ //
+ // peeki
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ TEST_ASSERT(a->peeki() == 10);
+ a->addElement(20, status);
+ TEST_ASSERT(a->peeki() == 20);
+ a->addElement(30, status);
+ TEST_ASSERT(a->peeki() == 30);
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+
+ //
+ // popi
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->addElement(10, status);
+ a->addElement(20, status);
+ a->addElement(30, status);
+ TEST_ASSERT(a->popi() == 30);
+ TEST_ASSERT(a->popi() == 20);
+ TEST_ASSERT(a->popi() == 10);
+ TEST_ASSERT(a->popi() == 0);
+ TEST_ASSERT(a->isEmpty());
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+ //
+ // push
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ TEST_ASSERT(a->push(10, status) == 10);
+ TEST_ASSERT(a->push(20, status) == 20);
+ TEST_ASSERT(a->push(30, status) == 30);
+ TEST_ASSERT(a->size() == 3);
+ TEST_ASSERT(a->popi() == 30);
+ TEST_ASSERT(a->popi() == 20);
+ TEST_ASSERT(a->popi() == 10);
+ TEST_ASSERT(a->isEmpty());
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+
+ //
+ // reserveBlock
+ //
+ status = U_ZERO_ERROR;
+ a = new UVector32(status);
+ a->ensureCapacity(1000, status);
+
+ // TODO:
+
+ TEST_CHECK_STATUS(status);
+ delete a;
+
+}
+
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/v32test.h b/Build/source/libs/icu/icu-xetex/test/intltest/v32test.h
new file mode 100644
index 00000000000..f364aeb1bcd
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/v32test.h
@@ -0,0 +1,32 @@
+/*
+******************************************************************************
+* Copyright (C) 2003, International Business Machines Corporation and *
+* others. All Rights Reserved. *
+******************************************************************************
+*/
+
+// file: v32test.h
+
+
+#ifndef V32TEST_H
+#define V32TEST_H
+
+#include "unicode/utypes.h"
+
+#include "intltest.h"
+
+
+class UVector32Test: public IntlTest {
+public:
+
+ UVector32Test();
+ virtual ~UVector32Test();
+
+ virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par = NULL );
+
+ // The following are test functions that are visible from the intltest test framework.
+ virtual void UVector32_API();
+
+};
+
+#endif
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/wbnf.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/wbnf.cpp
new file mode 100644
index 00000000000..7d08de7081b
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/wbnf.cpp
@@ -0,0 +1,1771 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 2005-2007, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ ******************************************************************************
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "wbnf.h"
+
+// Most of this code is meant to test the test code. It's a self test.
+// Normally this isn't run.
+#define TEST_WBNF_TEST 0
+
+///////////////////////////////////////////////////////////
+//
+// Constants and the most basic helper classes
+//
+
+static const char DIGIT_CHAR[] = "0123456789";
+static const char WHITE_SPACE[] = {'\t', ' ', '\r', '\n', 0};
+static const char ALPHABET[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static const char SPECIAL[] = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
+
+static inline UBool isInList(const char c /*in*/, const char list[] /*in*/){
+ const char * p = list;
+ for (;*p != 0 && *p != c; p++);
+ return *p?TRUE:FALSE;
+}
+static inline UBool isDigit(char c) {return isInList(c, DIGIT_CHAR);}
+static inline UBool isWhiteSpace(char c) {return isInList(c, WHITE_SPACE);}
+static inline UBool isAlphabet(char c) {return isInList(c, ALPHABET);}
+static inline UBool isSpecialAsciiChar(char c) {return isInList(c,SPECIAL);}
+
+
+
+///////////////////////////////////////////////////////////
+//
+// Helper classes
+//
+
+class Buffer_byte{
+// Utility class, can be treated as an auto expanded array. no boundary check.
+
+ typedef char byte;
+ byte * start;
+ byte * current;
+ int buffer_size; // size unit is byte
+public:
+ inline int content_size(){return current - start;} // size unit is byte
+
+private:
+ inline void expand(int add_size = 100){ // size unit is byte
+ int new_size = buffer_size + add_size;
+
+ int cs_snap = content_size();
+ start = (byte *) realloc(start, new_size); // may change the value of start
+ current = start + cs_snap;
+
+ memset(current, 0, add_size);
+ buffer_size = new_size;
+ }
+
+ inline void expand_to(int size){
+ int r = size - buffer_size;
+ if (r > 0) {
+ expand(r); // simply expand, no block alignment
+ }
+ }
+ Buffer_byte(const Buffer_byte &);
+ Buffer_byte & operator = (const Buffer_byte &);
+public:
+ Buffer_byte():start(NULL),current(start),buffer_size(0){
+ expand();
+ }
+ ~Buffer_byte(){
+ free(start);
+ }
+
+ inline void reset(){
+ start != NULL ? memset(start, 0, buffer_size) : 0;
+ current = start;
+ }
+
+ // Using memory copy method to append a C array to buffer,
+ inline void append(const void * c, int size){ // size unit is byte
+ expand_to(content_size() + size) ;
+ memcpy(current, c, size);
+ current = current + size;
+ }
+
+ byte * buffer(){
+ return start;
+ }
+};
+
+/*
+ The class(es) try to work as bulid-in array, so it overloads these two operators
+ operator type *();
+ type & operator[];
+ The first is used to auto type convert, the latter is used to select member.
+
+ A small trick is the class does not overload the address-of operator. This
+ behavior is different from bulid-in array, but it give us the opportunity
+ to get the address of the class itself.
+*/
+//template<typename type>
+// class BUFFER{
+// typedef BUFFER name;
+#define BUFFER(type, name)\
+ class name {\
+ private:\
+ Buffer_byte buf;\
+ public:\
+ name & reset() {buf.reset(); return *this;}\
+ name & append(type c) {buf.append(&c, sizeof(type)); return *this;}\
+ name & append_array(const type * p, int size) {buf.append(p, sizeof(type)*size); return *this;}\
+ type & operator [] (int i) { return ((type *) buf.buffer())[i];}\
+ operator type *(){return (type *) buf.buffer();} \
+ int content_size(){return buf.content_size() / sizeof(type);}\
+ }
+
+
+class Pick{
+/* The Pick is the basic language generator element*/
+public:
+ // generate a string accroding the syntax
+ // Return a null-terminated c-string. The buffer is owned by callee.
+ virtual const char* next() = 0;
+ virtual ~Pick(){};
+};
+
+//typedef BUFFER<char> Buffer_char;
+//typedef BUFFER<int> Buffer_int;
+//typedef BUFFER<Pick *> Buffer_pPick;
+BUFFER(char, Buffer_char);
+BUFFER(int, Buffer_int);
+BUFFER(Pick *, Buffer_pPick);
+
+class SymbolTable{
+/* Helper class.
+* It's a mapping table between 'variable name' and its 'active Pick object'
+*/
+private:
+ Buffer_char name_buffer; // var names storage space
+
+ Buffer_int names; // points to name (offset in name_buffer)
+ Buffer_pPick refs; // points to Pick
+
+ int get_index(const char *const var_name){
+ int len = names.content_size();
+ for (int i=0; i< len; i++){
+ if (strcmp(var_name, name_buffer + names[i]) == 0){
+ return i;
+ }
+ }
+ return -1;
+ }
+
+public:
+ enum RESULT {EMPTY, NO_VAR, NO_REF, HAS_REF};
+
+ RESULT find(const char *const var_name /*[in] c-string*/, Pick * * ref = NULL /*[out] Pick* */){
+ if (!var_name) return EMPTY; // NULL name
+
+ int i = get_index(var_name);
+ if (i == -1){
+ return NO_VAR; // new name
+ }
+ if (!refs[i]){ // exist name, no ref
+ return NO_REF;
+ } else {
+ if (ref) {
+ *ref = refs[i];
+ }
+ return HAS_REF; // exist name, has ref
+ }
+ }
+
+ void put(const char *const var_name, Pick *const var_ref = NULL){
+ int i = get_index(var_name);
+ switch(find(var_name)){
+ case EMPTY: // NULL name
+ break;
+ case NO_VAR: // new name
+ int offset;
+ offset = name_buffer.content_size();
+ name_buffer.append_array(var_name, strlen(var_name) + 1);
+ names.append(offset);
+ refs.append(var_ref);
+ break;
+ case NO_REF: // exist name, no ref
+ refs[i] = var_ref; // link definition with variable
+ break;
+ case HAS_REF: // exist name, has ref
+ if (var_ref){
+ refs[i] = var_ref;
+ }
+ break;
+ default:
+ ; // ASSERT(FALSE);
+ }
+ return;
+ }
+
+ UBool is_complete(){
+ int n = names.content_size();
+ for (int i=0; i<n; ++i){
+ if (refs[i] == NULL){
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ void reset(){
+ names.reset();
+ name_buffer.reset();
+
+ // release memory here
+ int s = refs.content_size();
+ for (int i=0; i < s; i++){
+ delete refs[i]; // TOFIX: point alias/recursion problem
+ }
+ refs.reset();
+ }
+
+ ~SymbolTable(){
+ reset();
+ }
+};
+
+
+/*
+// Document of class Escaper
+//
+// ATTENTION:
+// From http://icu-project.org/userguide/Collate_Customization.html.
+// We get the precedence of escape/quote operations
+//
+// (highest) 1. backslash \
+// 2. two single quotes ''
+// 3. quoting ' '
+//
+// ICU Collation should accept following as the same string.
+//
+// 1) 'ab'c _
+// 2) a\bc \
+// 3) a'b'\c |- They are equal.
+// 4) abc _/
+//
+// From "two single quotes", we have following deductions
+// D1. empty quoting is illgal. (obviously)
+// D2. no contact operation between two quotings
+// '.''.' is not .. it is .'.
+// D3. "two single quotes" cannot contact two quoting simultaneously
+// '..''''.' is not ..'. it is ..''.
+// NOTICE:
+// "two single quotes" can contact before one quoting
+// '''.' is '.
+// "two single quotes" can literally contact after one quoting
+// But, from syntax, it's one quoting including a "two single quotes"
+// '.''' is .'
+// D4. "two single quotes" cannot solely be included in quoting
+// '''' is not ' it is ''
+// NOTICE: These are legal
+// '.''.' is .'.
+// '.''' is .'
+//
+// dicision
+// /\
+// /__\
+// output buffer input buffer
+//
+// To make our dicision (within an atom operation) without caring input and output buffer,
+// following calling pattern (within an atom operation) shall be avoided
+//
+// P1 open_quoting() then close_quoting() (direct violation) D1
+// P2 close_quoting() then open_quoting() (direct violation) D2
+// P3 empty open_quoting() (indirect violation) D1, D4
+// P4 empty close_quoting() (indirect violation) D2, D3
+// P5 open_quoting() then two single quotes (indirect violation) D4
+// P6 close_quoting() then two single quotes (indirect violation) D3
+//
+// two single quotes escaping will not open_ or close_ quoting()
+// The choice will not lose some quoing forms.
+//
+// For open_quoting(),
+// we may get this form quoting ''' P5
+// It may raise a bug ''''x
+// If we expect
+// '''.' let the next char open the quoting
+// '.''.' the quoting is already opened by preceding char
+//
+// For close_quoting()
+// we will get this form quoting '.''' P6
+// It may raise a bug '.''''.'
+// If we expect
+// '.'''\. let the next char close the quoting
+// '.''''.' the expectation is wrong! using '.'\''.' instead
+//
+// It's a hard work to re-adjust generation opportunity for various escaping form.
+// We just simply ignore it.
+*/
+class Escaper{
+public:
+ enum CHOICE {YES, NO, RAND};
+ enum ESCAPE_FORM {BSLASH_ONLY, QUOTE_ONLY, QUOTE_AND_BSLAH, RAND_ESC};
+private:
+ class Bool{ // A wrapper class for CHOICE, to auto adapter UBool class
+ private:
+ const CHOICE tag;
+ public:
+ Bool(CHOICE flag=RAND):tag(flag){}
+ operator UBool() { // conversion operator
+ return tag == RAND ? rand()%2 : tag == YES;
+ //if (tag == RAND){
+ // return rand()%2 == 1;
+ //} else {
+ // return tag == YES ? TRUE : FALSE;
+ //}
+ }
+ };
+public:
+ Escaper(CHOICE escapeLiteral = RAND,
+ CHOICE twoQuotesEscape = RAND,
+ ESCAPE_FORM escapeForm = RAND_ESC):
+ escape_form(escapeForm),
+ escape_literal(escapeLiteral),
+ two_quotes_escape(twoQuotesEscape),
+ is_quoting(FALSE){}
+private:
+ Buffer_char str;
+ ESCAPE_FORM escape_form;
+ Bool escape_literal;
+ Bool two_quotes_escape;
+ UBool quote_escape;
+ UBool bslash_escape;
+ UBool is_quoting;
+
+ void set_options(){
+ ESCAPE_FORM t = escape_form == RAND_ESC ? (ESCAPE_FORM) (rand()%3) : escape_form;
+ switch (t){
+ case BSLASH_ONLY :
+ bslash_escape = TRUE; quote_escape = FALSE; break;
+ case QUOTE_ONLY:
+ bslash_escape = FALSE;quote_escape = TRUE; break;
+ case QUOTE_AND_BSLAH:
+ bslash_escape = TRUE; quote_escape = TRUE; break;
+ default:
+ ;// error
+ }
+ }
+
+ void reset(){
+ str.reset();
+ is_quoting = FALSE;
+ }
+
+ inline void open_quoting(){
+ if(is_quoting){
+ // do nothing
+ } else {
+ str.append('\'');
+ is_quoting = TRUE;
+ }
+ }
+ inline void close_quoting(){
+ if(is_quoting){
+ str.append('\'');
+ is_quoting = FALSE;
+ } else {
+ // do nothing
+ }
+ }
+
+ // str [in] null-terminated c-string
+ void append(const char * strToAppend){
+ for(;*strToAppend != 0; strToAppend++){
+ append(*strToAppend);
+ }
+ }
+
+ inline void append(const char c){
+ set_options();
+
+ if (c == '\\'){
+ quote_escape ? open_quoting() : close_quoting();
+ //bslash_escape always true here
+ str.append('\\');
+ str.append('\\');
+ } else if (c == '\''){
+ if (two_quotes_escape){ // quoted using two single quotes
+ // See documents in anonymous.design
+ str.append('\'');
+ str.append('\'');
+ } else{
+ quote_escape ? open_quoting() : close_quoting();
+ //bslash_escape always true here
+ str.append('\\');
+ str.append('\'');
+ }
+ } else if (isSpecialAsciiChar(c) || isWhiteSpace(c)){
+ quote_escape ? open_quoting() : close_quoting();
+ if (bslash_escape) str.append('\\');
+ str.append(c);
+ } else { //if (isAlphabet(c) || isDigit(c) || TRUE){ // treat others as literal
+ if (escape_literal){
+ quote_escape ? open_quoting() : close_quoting();
+ if (bslash_escape) str.append('\\');
+ str.append(c);
+ } else {
+ close_quoting();
+ str.append(c);
+ }
+ }
+ }
+
+public:
+ // Return a null-terminate c-string. The buffer is owned by callee.
+ char * operator()(const char * literal /*c-string*/){
+ str.reset();
+ for(;*literal != 0; literal++){
+ append(*literal);
+ }
+ close_quoting(); // P4 exception, to close whole quoting
+ return str;
+ }
+};
+
+class WeightedRand{
+// Return a random number in [0, size)
+// Every number has different chance (aka weight) to be selected.
+private:
+ Buffer_int weights;
+ double total;
+ WeightedRand(const WeightedRand &);
+ WeightedRand & operator = (const WeightedRand &);
+public:
+ WeightedRand(Buffer_int * weight_list = NULL, int size = 0){
+ if ( weight_list == NULL){
+ for (int i=0; i<size; ++i) weights.append(DEFAULT_WEIGHT);
+ } else {
+ int s = weight_list->content_size();
+ if (s < size){
+ weights.append_array( (*weight_list),s);
+ for (int i=s; i<size; ++i) weights.append(DEFAULT_WEIGHT);
+ } else { // s >= size
+ weights.append_array( (*weight_list),size);
+ }
+ }
+ total = 0;
+ int c = weights.content_size();
+ for (int i=0; i<c; ++i){
+ total += weights[i];
+ }
+ }
+
+ void append(int weight){
+ weights.append(weight);
+ total += weight;
+ }
+
+ // Give a random number with the consideration of weight.
+ // Every random number is associated with a weight.
+ // It identifies the chance to be selected,
+ // larger weight has more chance to be selected.
+ //
+ //
+ // ______________________ every slot has equal chance
+ //
+ // [____][_][___][______] each item has different slots, hence different chance
+ //
+ //
+ // The algorithms to generate the number is illustrated by preceding figure.
+ // First, a slot is selected by rand(). Then we translate the slot to corresponding item.
+ //
+ int next(){
+ // get a random in [0,1]
+ double reference_mark = (double)rand() / (double)RAND_MAX;
+
+ // get the slot's index, 0 <= mark <= total;
+ double mark = total * reference_mark;
+
+ // translate the slot to corresponding item
+ int i=0;
+ for (;;){
+ mark -= weights[i]; // 0 <= mark <= total
+ if (mark <= 0)
+ break;
+ i++;
+ }
+ return i;
+ }
+};
+
+///////////////////////////////////////////////////////////
+//
+// The parser result nodes
+//
+
+class Literal : public Pick {
+public:
+ virtual const char* next(){
+ return str;
+ }
+ Literal(const char * s /*c-string*/){
+ str.append_array(s, strlen(s) + 1);
+ }
+private:
+ Buffer_char str; //null-terminated c-string
+};
+
+class Variable : public Pick {
+public:
+ Variable(SymbolTable * symbols, const char * varName, Pick * varRef = NULL){
+ this->var_name.append_array(varName, strlen(varName) + 1);
+ if ((symbol_table = symbols)){
+ symbol_table->put(varName, varRef);
+ }
+ }
+
+ operator const char *(){
+ return var_name;
+ }
+
+ virtual const char* next(){
+ if (symbol_table){
+ Pick * var_ref = NULL;
+ symbol_table->find(var_name, &var_ref);
+ if (var_ref) {
+ return var_ref->next();
+ }
+ }
+ return ""; // dumb string
+ }
+private:
+ Buffer_char var_name;
+ SymbolTable * symbol_table;
+};
+
+class Quote : public Pick{
+public:
+ Quote(Pick & base):item(base),e(Escaper::NO, Escaper::NO, Escaper::BSLASH_ONLY){
+ }
+ virtual const char* next(){
+ return e(item.next());
+ }
+private:
+ Pick & item;
+ Buffer_char str;
+ Escaper e;
+};
+
+
+class Morph : public Pick{
+/*
+The difference between morph and an arbitrary random string is that
+a morph changes slowly. When we build collation rules, for example,
+it is a much better test if the strings we use are all in the same
+'neighborhood'; they share many common characters.
+*/
+public:
+ Morph(Pick & base):item(base){}
+
+ virtual const char* next(){
+ current.reset();
+ const char * s = item.next();
+ current.append_array(s, strlen(s) + 1);
+ if (last.content_size() == 0) {
+ str.reset();
+ last.reset();
+ str.append_array(current, current.content_size());
+ last.append_array(current, current.content_size());
+ } else {
+ morph();
+ }
+ return str;
+ }
+private:
+ Pick & item;
+ Buffer_char str;
+ Buffer_char last;
+ Buffer_char current;
+
+ char * p_last;
+ char * p_curr;
+
+ void copy_curr(){
+ if (*p_curr) {
+ str.append(*p_curr);
+ p_curr++;
+ }
+ }
+
+ void copy_last(){
+ if (*p_last) {
+ str.append(*p_last);
+ p_last++;
+ }
+ }
+
+ // copy 0, 1, or 2 character(s) to str
+ void copy(){
+ static WeightedRand wr(& Buffer_int().append(DEFAULT_WEIGHT * 10), 5);
+
+ switch (wr.next()){
+ case 0: // copy last -- has 10 times chance than others
+ copy_last();
+ break;
+ case 1: // copy both
+ copy_curr();
+ copy_last();
+ break;
+ case 2: // copy both
+ copy_last();
+ copy_curr();
+ break;
+ case 3:
+ copy_curr();
+ break;
+ case 4: // copy nothing
+ break;
+ default:
+ // ASSERT(FALSE);
+ ;
+ }
+ }
+
+ void morph(void){
+ int min = strlen(last);
+ int max = strlen(current);
+ if (min > max){
+ int temp = min;
+ min = max;
+ max = temp;
+ }
+
+ int len = min + rand()%(max - min + 1); // min + [0, diff]
+ p_curr = current;
+ p_last = last;
+ str.reset();
+
+ for (; str.content_size()<len && *p_curr && *p_last;){
+ copy(); // copy 0, 1, or 2 character(s) to str
+ }
+
+ if (str.content_size() == len) {
+ str.append(0);
+ final();
+ return;
+ }
+
+ if (str.content_size() > len) { // if the last copy copied two characters
+ str[len]=0;
+ final();
+ return;
+ }
+
+ // str.content_size() < len
+ if (*p_last) {
+ for (; str.content_size() < len; copy_last());
+ } else if (*p_curr){
+ for (; str.content_size() < len; copy_curr());
+ }
+
+ int last_len = last.content_size();
+ for (;str.content_size() < len;){
+ str.append(last[rand()%last_len]);
+ }
+ str.append(0);
+ final();
+ }
+
+ void final(){
+ last.reset();
+ last.append_array(current, current.content_size());
+ }
+};
+
+class Sequence : public Pick {
+public:
+ virtual const char* next(){
+ str.reset();
+ int s = items.content_size();
+ for(int i=0; i < s; i++){
+ const char * t = items[i]->next();
+ str.append_array(t, strlen(t));
+ }
+ str.append(0); // terminal null
+ return str;
+ }
+
+ void append (Pick * node){
+ items.append(node);
+ }
+
+ virtual ~Sequence(){
+ int s = items.content_size();
+ for(int i=0; i < s; i++){
+ //How can assure the item is got from heap?
+ //Let's assume it.
+ delete items[i]; // TOFIX: point alias/recursion problem
+ items[i] = NULL;
+ }
+ }
+private:
+ Buffer_pPick items;
+ Buffer_char str; //null-terminated c-string
+};
+
+class Repeat : public Pick {
+private:
+ Pick * item;
+ Buffer_char str;
+ WeightedRand wr;
+ int min;
+ int max;
+ int select_a_count(){
+ return min + wr.next();
+ }
+public:
+ virtual const char* next(){
+ str.reset();
+ int c = select_a_count();
+ for(int i=0; i< c; i++){
+ const char * t = item->next();
+ str.append_array(t, strlen(t));
+ }
+ str.append(0);
+ return str;
+ }
+
+ Repeat(Pick * base, int minCount =0, int maxCount = 1, Buffer_int * weights = NULL):
+ wr(weights, maxCount-minCount +1) {
+ this->item = base;
+ this->min = minCount;
+ this->max = maxCount;
+ }
+ virtual ~Repeat(){
+ delete item; // TOFIX: point alias/recursion problem
+ item = NULL;
+ }
+};
+
+
+class Alternation : public Pick {
+public:
+ virtual const char* next(){
+ str.reset();
+ int i = wr.next();
+ const char * t = items[i]->next();
+ str.append_array(t, strlen(t) + 1);
+ return str;
+ }
+ virtual ~Alternation(){
+ int s = items.content_size();
+ for(int i=0; i < s; i++){
+ delete items[i]; // TOFIX: point alias/recursion problem
+ items[i] = NULL;
+ }
+ }
+
+ Alternation & append (Pick * node, int weight = DEFAULT_WEIGHT){
+ items.append(node);
+ wr.append(weight);
+ return *this;
+ }
+private:
+ Buffer_pPick items;
+ Buffer_char str; // null-terminated c-string
+ WeightedRand wr;
+};
+
+///////////////////////////////////////////////////////////
+//
+// The parser
+//
+
+enum TokenType {STRING, VAR, NUMBER, STREAM_END, ERROR, QUESTION, STAR, PLUS, LBRACE, RBRACE, LPAR, RPAR, SEMI, EQ, COMMA, BAR, AT, WAVE, PERCENT};
+
+class Scanner{
+friend int DumpScanner(Scanner & s, UBool dumb);
+private:
+ const char * source;
+ const char * working;
+ const char * history; // for debug
+ enum StateType {START, IN_NUM, IN_VAR_FIRST, IN_VAR, IN_QUOTE, IN_QUOTE_BSLASH, IN_BSLASH, IN_STRING, DONE};
+ StateType state;
+ void terminated(TokenType t){
+ working--; // return the peeked character
+ tokenType = t;
+ token.append(0); // close buffer
+ state = DONE;
+ }
+public:
+ // the buffer of "source" is owned by caller
+ Scanner(const char *src/*[in] c-string*/ = NULL):source(src){
+ working = src;
+ history = working;
+ state = DONE;
+ tokenType = ERROR;
+ }
+
+ //void setSource(const char *const src /*[in] c-string*/){
+ // *(&const_cast<const char *>(source)) = src;
+ //}
+
+ Buffer_char token;
+ TokenType tokenType;
+
+ TokenType getNextToken(){
+ token.reset();
+ state = START;
+ history = working; // for debug
+ while (state != DONE){
+ char c = *working++;
+ if (c == 0 && state != START){//avoid buffer overflow. for IN_QUOE, IN_ESCAPE
+ terminated(ERROR);
+ break; // while
+ }
+ switch(state){
+ case START:
+ tokenType = ERROR;
+ switch(c){
+ case '?' : tokenType = QUESTION; break;
+ case '*' : tokenType = STAR; break;
+ case '+' : tokenType = PLUS; break;
+ case '{' : tokenType = LBRACE; break;
+ case '}' : tokenType = RBRACE; break;
+ case '(' : tokenType = LPAR; break;
+ case ')' : tokenType = RPAR; break;
+ case ';' : tokenType = SEMI; break;
+ case '=' : tokenType = EQ; break;
+ case ',' : tokenType = COMMA; break;
+ case '|' : tokenType = BAR; break;
+ case '@' : tokenType = AT; break;
+ case '~' : tokenType = WAVE; break;
+ case '%' : tokenType = PERCENT; break;
+ case 0 : tokenType = STREAM_END; working-- /*avoid buffer overflow*/; break;
+ }
+ if (tokenType != ERROR){
+ token.append(c);
+ token.append(0);
+ state = DONE;
+ break; // START
+ }
+ switch(c){
+ case '$' : state = IN_VAR_FIRST; token.append(c); break;
+ case '\'' : state = IN_QUOTE; break;
+ case '\\' : state = IN_BSLASH; break;
+ default:
+ if (isWhiteSpace(c)){ // state = START; //do nothing
+ } else if (isDigit(c)){ state = IN_NUM; token.append(c);
+ } else if (isAlphabet(c)){ state = IN_STRING; token.append(c);
+ } else {terminated(ERROR);}
+ }
+ break;//START
+ case IN_NUM:
+ if (isDigit(c)){
+ token.append(c);
+ } else {
+ terminated(NUMBER);
+ }
+ break;//IN_NUM
+ case IN_VAR_FIRST:
+ if (isAlphabet(c)){
+ token.append(c);
+ state = IN_VAR;
+ } else {
+ terminated(ERROR);
+ }
+ break; // IN_VAR_FISRT
+ case IN_VAR:
+ if (isAlphabet(c) || isDigit(c)){
+ token.append(c);
+ } else {
+ terminated(VAR);
+ }
+ break;//IN_VAR
+ case IN_STRING:
+ // About the scanner's behavior for STRING, AT, and ESCAPE:
+ // All of them can be contacted with each other.
+ // This means the scanner will eat up as much as possible strings
+ // (STRING, AT, and ESCAPE) at one time, with no regard of their
+ // combining sequence.
+ //
+ if (c == '\''){
+ state = IN_QUOTE; // the first time we see single quote
+ } else if (c =='\\'){ // back slash character
+ state = IN_BSLASH;
+ } else if (isAlphabet(c) || isDigit(c)){
+ token.append(c);
+ } else{
+ terminated(STRING);
+ }
+ break;//IN_STRING
+ case IN_QUOTE:
+ if (c == '\''){ // the second time we see single quote
+ state = IN_STRING; // see document in IN_STRING
+ } else if ( c== '\\') { // backslah escape in quote
+ state = IN_QUOTE_BSLASH;
+ } else {
+ token.append(c); // eat up everything, includes back slash
+ }
+ break;//IN_QUOTE
+ case IN_QUOTE_BSLASH:
+ case IN_BSLASH:
+ switch (c){
+ case 'n' : token.append('\n'); break;
+ case 'r' : token.append('\r'); break;
+ case 't' : token.append('\t'); break;
+ case '\'' : token.append('\''); break;
+ case '\\' : token.append('\\'); break;
+ default: token.append(c); // unknown escaping, treat it as literal
+ }
+ if (state == IN_BSLASH){
+ state = IN_STRING; // see document in IN_STRING
+ } else { // state == IN_QUOTE_BSLASH
+ state = IN_QUOTE;
+ }
+ break;//IN_BSLASH
+ case DONE: /* should never happen */
+ default:
+ working--;
+ tokenType = ERROR;
+ state = DONE;
+ break;
+ }//switch(state)
+ }//while (state != DONE)
+
+ return tokenType;
+ }
+};//class Scanner
+
+class Parser{
+friend UBool TestParser();
+friend class TestParserT;
+friend class LanguageGenerator_impl;
+private:
+ Scanner s;
+ TokenType & token;
+ int min_max; // for the evil infinite
+
+ UBool match(TokenType expected){
+ if (token == expected) {
+ token = s.getNextToken();
+ return TRUE;
+ } else {
+ //s.dumpCurrentPoint();
+ return FALSE;
+ }
+ }
+
+ UBool weight(int & value){
+ if (token == NUMBER){
+ int temp = atoi(s.token);
+ match(NUMBER);
+ if (match(PERCENT)){
+ value = temp;
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+ UBool repeat (Pick* &node /*in,out*/){
+ if (node == NULL) return FALSE;
+
+ int count = -2;
+ int min = -2;
+ int max = -2;
+ UBool question = FALSE;
+ switch (token){
+ case QUESTION:
+ match(QUESTION);
+ min = 0;
+ max = 1;
+ count = 2;
+ question = TRUE;
+ break;
+ case STAR:
+ match(STAR);
+ min = 0;
+ max = -1;
+ count = -1;
+ break;
+ case PLUS:
+ match(PLUS);
+ min = 1;
+ max = -1;
+ count = -1;
+ break;
+ case LBRACE:
+ match(LBRACE);
+ if (token != NUMBER){
+ return FALSE;
+ }else {
+ min = atoi(s.token);
+ match(NUMBER);
+ if (token == RBRACE){
+ match(RBRACE);
+ max = min;
+ count = 1;
+ } else if (token == COMMA) {
+ match(COMMA);
+ if (token == RBRACE){
+ match(RBRACE);
+ max = -1;
+ count = -1;
+ } else if (token == NUMBER) {
+ max = atoi(s.token);
+ match(NUMBER);
+ count = max - min + 1;
+ if (!match(RBRACE)) {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+ }
+ break;
+ default:
+ return FALSE;
+ }
+
+ if (count == -2 || min == -2 || max == -2){
+ //ASSERT(FALSE);
+ return FALSE;
+ }
+
+ // eat up following weights
+ Buffer_int weights;
+ int w;
+ while (weight(w)){
+ weights.append(w);
+ }
+
+ // for the evil infinite
+ min_max = min_max > min ? min_max : min;
+ min_max = min_max > max ? min_max : max;
+ if (min_max > PSEUDO_INFINIT){
+ return FALSE; // PSEUDO_INFINIT is less than the real maximum
+ }
+ if (max == -1){ // the evil infinite
+ max = PSEUDO_INFINIT;
+ }
+ // for the strange question mark
+ if (question && weights.content_size() > 0){
+ Buffer_int w2;
+ w2.append(DEFAULT_WEIGHT - weights[0]).append(weights[0]);
+ node = new Repeat(node,min,max,&w2);
+ return TRUE;
+ }
+ node = new Repeat(node,min,max,&weights);
+ return TRUE;
+ }
+
+ UBool core(Pick* &node /*out*/){
+ if (node != NULL) return FALSE; //assert node == NULL
+
+ switch(token){
+ case LPAR:
+ match(LPAR);
+ if(defination(node) && match(RPAR)){
+ return TRUE;
+ }
+ return FALSE;
+ case VAR:
+ node = new Variable(&symbols, s.token);
+ match(VAR);
+ return TRUE;
+ case STRING:
+ node = new Literal(s.token);
+ match(STRING);
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ }
+ UBool modified(Pick* &node /*out*/){
+ if (node != NULL) return FALSE; //assert node == NULL
+
+ if (!core(node)) {
+ return FALSE;
+ }
+
+ for (;;){
+ switch(token){
+ case WAVE:
+ match(WAVE);
+ node = new Morph(*node);
+ break;
+ case AT:
+ match(AT);
+ node = new Quote(*node);
+ break;
+ case QUESTION:
+ case STAR:
+ case PLUS:
+ case LBRACE:
+ if (!repeat(node)) return FALSE;
+ break;
+ case SEMI: // rule definiation closed
+ case RPAR: // within parenthesis (core closed)
+ case BAR: // in alternation
+ case NUMBER: // in alternation, with weight
+ case LPAR: // in sequence
+ case VAR: // in sequence
+ case STRING: // in sequence
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ }
+ }
+
+
+ UBool sequence_list(Pick* &node /*in,out*/){
+ if (node == NULL) return FALSE; // assert node != NULL
+
+ Sequence* seq = new Sequence();
+ Pick * n = node;
+
+ while (token == VAR || token == STRING || token == LPAR){
+ seq->append(n);
+ n = NULL;
+ if (modified(n)){
+ // go on
+ } else {
+ goto FAIL;
+ }
+ }
+
+ if (token == SEMI || token == RPAR || token == BAR){
+ seq->append(n);
+ node = seq;
+ return TRUE;
+ }
+FAIL:
+ delete seq;
+ return FALSE;
+
+ }
+
+ UBool sequence(Pick* &node /*out*/){
+ if (node != NULL) return FALSE; //assert node == NULL
+
+ if (!modified(node)) {
+ return FALSE;
+ }
+
+ if (token == VAR || token == STRING || token == LPAR){
+ return sequence_list(node);
+ } else {
+ return TRUE; // just a modified
+ }
+ }
+
+ UBool alternation_list(Pick* &node /*in,out*/){
+ if (node == NULL) return FALSE; // assert node != NULL
+
+ Alternation * alt = new Alternation();
+ Pick * n = node;
+ int w = DEFAULT_WEIGHT;
+
+ while (token == NUMBER || token == BAR){
+ if(token == NUMBER) {
+ if (weight(w)){
+ if (token == BAR){
+ // the middle item, go on
+ } else {
+ // the last item or encounter error
+ break; //while
+ }
+ } else {
+ goto FAIL;
+ }
+ } // else token == BAR
+ match(BAR);
+ alt->append(n,w);
+
+ n = NULL;
+ w = DEFAULT_WEIGHT;
+ if (sequence(n)){
+ // go on
+ } else {
+ goto FAIL;
+ }
+ }
+
+ if (token == SEMI || token == RPAR) {
+ alt->append(n,w);
+ node = alt;
+ return TRUE;
+ }
+FAIL:
+ delete alt;
+ return FALSE;
+ }
+
+ UBool alternation(Pick* &node /*out*/){
+ if (node != NULL) return FALSE; //assert node == NULL
+
+ // 'sequence' has higher precedence than 'alternation'
+ if (!sequence(node)){
+ return FALSE;
+ }
+
+ if (token == BAR || token == NUMBER){ // find a real alternation1, create it.
+ return alternation_list(node);
+ } else {
+ return TRUE; // just a sequence_old
+ }
+ }
+
+
+ UBool defination(Pick* &node /*out*/){
+ if (node != NULL) return FALSE; //assert node == NULL
+ return alternation(node);
+ }
+
+ UBool rule(){
+ if (token == VAR){
+ Buffer_char name;
+ name.append_array(s.token, strlen(s.token) + 1);
+ match(VAR);
+
+ if (match(EQ)){
+ Pick * t = NULL;
+ if(defination(t)){
+ symbols.put(name, t);
+ return match(SEMI);
+ }
+ }
+ }
+ return FALSE;
+ }
+public:
+ UBool rules(){
+ symbols.reset();
+ token = s.getNextToken();
+ while (rule()){
+ }
+ if (token == STREAM_END){
+ return TRUE;
+ } else {
+ //s.dumpCurrentPoint();
+ return FALSE;
+ }
+ }
+
+public:
+ SymbolTable symbols;
+
+ Parser(const char *const source):s(source), token(s.tokenType){
+ min_max = -2;
+ }
+ UBool parse(){
+ return rules();
+ }
+
+}; // class Parser
+
+
+///////////////////////////////////////////////////////////
+//
+//
+//
+
+int DumpScanner(Scanner & s, UBool dump = TRUE){
+ int len = strlen(s.source);
+ int error_start_offset = s.history - s.source;
+ if (dump){
+ printf("\n=================== DumpScanner ================\n");
+ fwrite(s.source, len, 1, stdout);
+ printf("\n-----parsed-------------------------------------\n");
+ fwrite(s.source, s.history - s.source, 1, stdout);
+ printf("\n-----current------------------------------------\n");
+ fwrite(s.history, s.working - s.history, 1, stdout);
+ printf("\n-----unparsed-----------------------------------\n");
+ fwrite(s.working, (s.source + len - s.working), 1, stdout);
+ printf("\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
+ }
+ return error_start_offset;
+}
+
+class LanguageGenerator_impl{
+public:
+ LanguageGenerator_impl(const char *const bnf_definition, const char *const top_node)
+ :par(bnf_definition), top_node_name(top_node){
+ srand((unsigned)time( NULL ));
+ }
+
+ LanguageGenerator::PARSE_RESULT parseBNF(UBool debug = TRUE){
+ if (par.parse()){
+ if (par.symbols.find(top_node_name, &top_node_ref) == SymbolTable::HAS_REF) {
+ if (par.symbols.is_complete()) {
+ return LanguageGenerator::OK;
+ } else {
+ if (debug) printf("The bnf definition is incomplete.\n");
+ return LanguageGenerator::INCOMPLETE;
+ }
+ } else {
+ if (debug) printf("No top node is found.\n");
+ return LanguageGenerator::NO_TOP_NODE;
+ }
+ } else {
+ if(debug) {
+ printf("The bnf definition is wrong\n");
+ DumpScanner(par.s, TRUE);
+ }
+ return LanguageGenerator::BNF_DEF_WRONG;
+ }
+ }
+ const char * next(){
+ return top_node_ref->next();
+ }
+
+private:
+ Parser par;
+ const char *const top_node_name;
+ Pick * top_node_ref;
+};
+
+LanguageGenerator::LanguageGenerator():lang_gen(NULL){
+}
+
+LanguageGenerator::~LanguageGenerator(){
+ delete lang_gen;
+}
+
+LanguageGenerator::PARSE_RESULT LanguageGenerator::parseBNF(const char *const bnf_definition /*in*/, const char *const top_node/*in*/, UBool debug){
+ if (lang_gen){
+ delete lang_gen;
+ }
+ lang_gen = new LanguageGenerator_impl(bnf_definition, top_node);
+ PARSE_RESULT r = lang_gen->parseBNF(debug);
+ if (r != OK){
+ delete lang_gen;
+ lang_gen = NULL;
+ return r;
+ } else {
+ return r;
+ }
+}
+const char *LanguageGenerator::next(){ // Return a null-terminated c-string. The buffer is owned by callee.
+ if (lang_gen){
+ return lang_gen->next();
+ }else {
+ return "";
+ }
+}
+
+///////////////////////////////////////////////////////////
+//
+// The test code for WBNF
+//
+
+#define CALL(fun) \
+ if (fun()){ \
+ printf("Pass: " #fun "\n");\
+ } else { \
+ printf("FAILED: !!! " #fun " !!!\n"); \
+ }
+
+#define DUMP_R(fun, var, times) \
+ {printf("\n========= " #fun " =============\n"); \
+ for (int i=0; i<times; i++) { \
+ const char * t = var.next();\
+ fwrite(t,strlen(t),1,stdout); \
+ printf("\n"); \
+ } \
+ printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");}
+
+
+
+#if TEST_WBNF_TEST
+static UBool TestQuote(){
+ const char *const str = "This ' A !,z| qq [] .new\tline";
+ //const char *const str_r = "This \\' A '!,'z'|' qq '[]' '.'new\tline";
+ ////
+ //// :( we must quote our string to following C syntax
+ //// cannot type the literal here, it makes our code rather human unreadable
+ //// very very unconformable!
+ ////
+ ///*
+ //*/
+
+ //const char *const s1 = "ab'c";
+ //const char (* s1_r1) [] = { "ab''c", // ab''c
+ // "ab\\'c", // ab\'c
+ // };//
+ ///*
+ // . '.' \.
+ // .. \.\. '.'\. '.'\. '..' // '.''.' wrong
+ //*/
+
+ //const char *const s2 = "a..'.b"; // a..'.b
+ //const char (*s2_r) [] = { "a'..''.'b" // a'..''.'b
+ // ,"a'..\\'.'b" // a'..\'.'b
+ // ,"a'..'\\''.'b" // a'..'\''.'b
+ // };//
+
+ //const char *const s3 = "a..\\.b"; // a..\.b
+ //const char (*s3_r) [] = { "a'..\\\\.'b" // a'..\\.'b
+ // ,"a'..'\\\\'.'b" // a'..'\\'.'b
+ // };//
+
+ // // no catact operation, no choice, must be compact
+
+ srand((unsigned)time( NULL ));
+
+ //Escaper l(Escaper::NO, Escaper::NO, Escaper::RAND_ESC);
+ Pick *p = new Literal(str);
+ Quote q(*p);
+
+ DUMP_R(TestQuote, (*p), 1);
+ DUMP_R(TestQuote, q, 20);
+ return FALSE;
+}
+static UBool TestLiteral(){
+ const char * s = "test string99.";
+ Literal n(s);
+ const char * r = n.next();
+ return strcmp(s,r) == 0;
+}
+
+static UBool TestSequence(){
+ Sequence seq;
+ seq.append(new Literal("abc "));
+ seq.append(new Literal(", s"));
+
+ return strcmp(seq.next(), "abc , s") == 0;
+}
+static UBool TestAlternation(){
+ srand((unsigned)time( NULL ));
+ Alternation alt;
+ alt.append(new Literal("aaa_10%"),10);
+ alt.append(new Literal("bbb_0%"),0);
+ alt.append(new Literal("ccc_10%"),10);
+ alt.append(new Literal("ddddddd_50%"),50);
+
+ DUMP_R(TestAlternation, alt, 50);
+
+ return FALSE;
+}
+
+static UBool TestBuffer(){
+ Buffer_int t;
+ t.append(1).append(0).append(5);
+ int s = t.content_size();
+ for (int i=0; i<s; ++i){
+ printf("%d\n", t[i]);
+ }
+ return FALSE;
+}
+
+static UBool TestWeightedRand(){
+ srand((unsigned)time( NULL ));
+ Buffer_int t;
+ t.append(1).append(0).append(5);
+ WeightedRand wr(&Buffer_int().append(10).append(0).append(50),4);
+// WeightedRand wr(&t,3);
+ for (int i=0; i< 50; ++i){
+ printf("%d\n", wr.next());
+ }
+ return FALSE;
+}
+
+static UBool TestRepeat(){
+ srand((unsigned)time( NULL ));
+ Repeat rep(new Literal("aaa1-5 "), 1, 5);
+ DUMP_R(TestRepeat, rep, 50);
+
+ Repeat r2(new Literal("b{1,3}1%0%5% "), 1, 3, &Buffer_int().append(1).append(0).append(5));
+ DUMP_R(TestRepeat, r2, 50);
+
+ Repeat r3(new Literal("aaa5-5 "), 5, 5);
+ DUMP_R(TestRepeat, r3, 50);
+
+ return FALSE;
+}
+
+static UBool TestVariable(){
+ SymbolTable tab;
+ Pick * value = new Literal("string1");
+ Variable var1(&tab, "x", value);
+
+ Variable var2(&tab, "y");
+// tab.put(var2, value); // TOFIX: point alias/recursion problem
+ Pick * value2 = new Literal("string2");
+ tab.put(var2, value2);
+
+ Pick * value3 = new Literal("string3");
+ Variable var3(&tab, "z");
+ tab.put("z", value3);
+
+ UBool pass;
+ pass = strcmp(var1.next(), value->next()) == 0;
+ pass = pass && strcmp(var2.next(), value2->next()) == 0;
+ pass = pass && strcmp(var3.next(), value3->next()) == 0;
+ return pass;
+}
+
+static UBool TestSymbolTable(){
+ Literal * n1 = new Literal("string1");
+ Literal * n2 = new Literal("string2");
+ SymbolTable t;
+ t.put("abc", n1);
+ t.put("$aaa", n2);
+// t.put("alias", n1); // TOFIX: point alias/recursion problem
+ t.put("bbb");
+
+ UBool pass;
+ pass = t.find(NULL) == SymbolTable::EMPTY;
+ pass = pass && t.find("ccc") == SymbolTable::NO_VAR;
+ pass = pass && t.find("bbb") == SymbolTable::NO_REF;
+ pass = pass && t.find("abc") == SymbolTable::HAS_REF;
+ pass = pass && t.find("$aaa") == SymbolTable::HAS_REF;
+
+ t.reset();
+ pass = pass && t.find("abc") == SymbolTable::NO_VAR;
+ return pass;
+}
+
+
+static UBool TestScanner(void){
+ //const char str1[] = "$root = $command{0,5} $reset $mostRules{1,20};";
+ //const char str1_r[][20] = {"$root", "=", "$command", "{", "0", ",", "5", "}",
+ // "$reset", "$mostRules", "{", "1", ",", "20", "}", ";"};
+
+ const char str2[] = "$p2 =(\\\\ $s $string $s)? 25%;";
+ const char str2_r[][20] = {"$p2", "=", "(", "\\", "$s", "$string", "$s", ")", "?", "25", "%", ";"};
+
+ const char *str = str2;
+ const char (*str_r)[20] = str2_r;
+ int tokenNum = sizeof(str2_r)/sizeof(char[20]);
+
+ Scanner t(str);
+ UBool pass = TRUE;
+ t.getNextToken();
+ int i = 0;
+ while (pass){
+ if (t.tokenType == STREAM_END){
+ pass = pass? i == tokenNum : FALSE;
+ break;//while
+ } else if (t.tokenType == ERROR){
+ pass = FALSE;
+ break;//while
+ } else {
+ pass = strcmp( &(t.token[0]), str_r[i++]) == 0;
+ t.getNextToken();
+ }
+ }
+
+ //const char ts[] = "$commandList = '['"
+ //" ( alternate ' ' $alternateOptions"
+ //" | backwards ' 2'"
+ //" | normalization ' ' $onoff "
+ //" | caseLevel ' ' $onoff "
+ //" | hiraganaQ ' ' $onoff"
+ //" | caseFirst ' ' $caseFirstOptions"
+ //" | strength ' ' $strengthOptions"
+ //" ) ']';" ;
+
+ //Scanner t2(ts);
+ //pass = TRUE;
+ //do {
+ // t2.getNextToken();
+ // if (t2.tokenType == ERROR){
+ // DumpScanner(t2);
+ // return FALSE;
+ // }
+ //}while (t.tokenType != STREAM_END);
+
+ return pass;
+}
+
+class TestParserT {
+public:
+UBool operator () (const char *const str, const int exp_error_offset = -1, const UBool dump = TRUE){
+ Parser par(str);
+ if (par.rules()){
+ if ( exp_error_offset == -1){
+ return TRUE;
+ }else {
+ DumpScanner(par.s,dump);
+ return FALSE;
+ }
+ }else {
+ return DumpScanner(par.s, dump) == exp_error_offset;
+ }
+}
+};
+
+UBool TestParser(){
+ TestParserT test;
+
+ UBool pass = TRUE;
+ pass = pass && test ("$s = ' ' ? 50%;");
+ pass = pass && test("$x = ($var {1,2}) 3%;"); // legal
+ pass = pass && test("$x = $var {1,2} 3% | b 4%;"); // legal
+ pass = pass && test("$x = $var {1,2} 3%;"); // legal
+ pass = pass && test("$m = $c ? 2% 4% | $r 5% | $n 25%;"); // legal
+ pass = pass && test("$a = b ? 2% | c 5%;"); // legal
+ pass = pass && test("$x = A B 5% C 10% | D;", 8, FALSE); // illegal 5%
+ pass = pass && test("$x = aa 45% | bb 5% cc;", 19, FALSE);// illegal cc
+ pass = pass && test("$x = (b 5%) (c 6%);"); // legal
+ pass = pass && test("$x = (b 5%) c 6%;", 13, FALSE); // illegal 6%
+ pass = pass && test("$x = b 5% (c 6%);", 9, FALSE); // illegal (c 6%)
+ pass = pass && test("$x = b 5% c 6%;", 9, FALSE); // illegal c 6%
+ pass = pass && test("$x = b 5%;"); // legal
+ pass = pass && test("$x = aa 45% | bb 5% cc;", 19, FALSE);// illegal cc
+ pass = pass && test("$x = a | b | c 4% | d 5%;"); // legal
+ pass = pass && test("$s = ' ' ? 50% abc;"); // legal
+ pass = pass && test("$s = a | c d | e f;"); // legal
+ pass = pass && test( "$z = q 0% | p 1% | r 100%;"); // legal How to check parsed tree??
+
+ pass = pass && test("$s = ' ' ? 50%;");
+ pass = pass && test("$relationList = '<' | '<<' | ';' | '<<<' | ',' | '=';");
+ pass = pass && test("$p1 = ($string $s '|' $s)? 25%;");
+ pass = pass && test("$p2 = (\\\\ $s $string $s)? 25%;");
+ pass = pass && test("$rel2 = $p1 $string $s $p2;");
+ pass = pass && test("$relation = $relationList $s ($rel1 | $rel2) $crlf;");
+ pass = pass && test("$command = $commandList $crlf;");
+ pass = pass && test("$reset = '&' $s ($beforeList $s)? 10% ($positionList 100% | $string 10%) $crlf;");
+ pass = pass && test("$mostRules = $command 1% | $reset 5% | $relation 25%;");
+ pass = pass && test("$root = $command{0,5} $reset $mostRules{1,20};");
+
+ const char collationBNF[] =
+ "$s = ' '? 50%;"
+ "$crlf = '\r\n';"
+
+ "$alternateOptions = non'-'ignorable | shifted;"
+ "$onoff = on | off;"
+ "$caseFirstOptions = off | upper | lower;"
+ "$strengthOptions = '1' | '2' | '3' | '4' | 'I';"
+ "$commandList = '['"
+ " ( alternate ' ' $alternateOptions"
+ " | backwards ' 2'"
+ " | normalization ' ' $onoff "
+ " | caseLevel ' ' $onoff "
+ " | hiraganaQ ' ' $onoff"
+ " | caseFirst ' ' $caseFirstOptions"
+ " | strength ' ' $strengthOptions"
+ " ) ']';"
+ "$command = $commandList $crlf;"
+
+ "$ignorableTypes = (tertiary | secondary | primary) ' ' ignorable;"
+ "$allTypes = variable | regular | implicit | trailing | $ignorableTypes;"
+ "$positionList = '[' (first | last) ' ' $allTypes ']';"
+
+ "$beforeList = '[before ' ('1' | '2' | '3') ']';"
+
+ "$relationList = ("
+ " '<'"
+ " | '<<'"
+ " | ';'"
+ " | '<<<'"
+ " | ','"
+ " | '='"
+ ");"
+ "$string = $magic;"
+ "$rel1 = '[variable top]' $s;"
+ "$p1 = ($string $s '|' $s)? 25%;"
+ "$p2 = (\\\\ $s $string $s)? 25%;"
+ "$rel2 = $p1 $string $s $p2;"
+ "$relation = $relationList $s ($rel1 | $rel2) $crlf;"
+
+ "$reset = '&' $s ($beforeList $s)? 10% ($positionList 1% | $string 10%) $crlf;"
+ "$mostRules = $command 1% | $reset 5% | $relation 25%;"
+ "$root = $command{0,5} $reset $mostRules{1,20};"
+ ;
+
+ pass = pass && test(collationBNF);
+
+
+ return pass;
+}
+
+static UBool TestMorph(){
+ srand((unsigned)time( NULL ));
+
+ Alternation * alt = new Alternation();
+
+ (*alt)
+ .append(new Literal("a")).append(new Literal("b")).append(new Literal("c"))
+ .append(new Literal("d")).append(new Literal("e")).append(new Literal("f"))
+ .append(new Literal("g")).append(new Literal("h")).append(new Literal("i"))
+ .append(new Literal("j")).append(new Literal("k")).append(new Literal("l"))
+ .append(new Literal("m")).append(new Literal("n")).append(new Literal("o"))
+ ;
+
+ Repeat * rep = new Repeat( alt ,5,5 );
+ Morph m( *rep);
+
+// DUMP_R(TestMorph,(*rep),20);
+ DUMP_R(TestMorph,m,100);
+
+ return FALSE;
+}
+
+#endif
+
+static UBool TestLanguageGenerator(){
+ //LanguageGenerator g;
+ //const char *const s = "$s = p 0% | q 1%;";
+ //g.parseBNF(s, "$s");
+ UBool pass;
+ //= strcmp("q", g.next()) == 0;
+
+ const char *const def =
+ //"$a = $b;"
+ //"$b = $c;"
+ //"$c = $t;"
+ //"$t = abc $z{1,2};"
+ //"$k = a | b | c | d | e | f | g ;"
+ //"$z = q 0% | p 1% | r 1%;"
+ "$x = a ? 0%;"
+ ; // end of string
+// const char * s = "abczz";
+//
+//
+ LanguageGenerator g;
+ pass = g.parseBNF(def, "$x",TRUE);
+//// LanguageGenerator g(collationBNF, "$root", "$magic", new MagicNode());
+//
+ if (pass != LanguageGenerator::OK) return FALSE;
+
+ DUMP_R(TestLanguageGenerator, g, 20);
+ return pass;
+
+ ////UBool pass = strcmp(s,r) == 0;
+
+ //if (pass){
+ // printf("TestRandomLanguageGenerator passed.\n");
+ //} else {
+ // printf("TestRandomLanguageGenerator FAILED!!!\n");
+ //}
+ //return pass;
+}
+
+void TestWbnf(void){
+ srand((unsigned)time( NULL ));
+
+ //CALL(TestLiteral);
+ //CALL(TestSequence);
+ //CALL(TestSymbolTable);
+ //CALL(TestVariable);
+
+ //TestRepeat();
+ //TestAlternation();
+ //TestMorph();
+
+ //TestQuote();
+ //TestBuffer();
+ //TestWeightedRand();
+
+ //CALL(TestScanner);
+ //CALL(TestParser);
+ CALL(TestLanguageGenerator);
+}
+
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/wbnf.h b/Build/source/libs/icu/icu-xetex/test/intltest/wbnf.h
new file mode 100644
index 00000000000..7b76f8f2daa
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/wbnf.h
@@ -0,0 +1,157 @@
+/*
+ ******************************************************************************
+ * Copyright (C) 2005, International Business Machines Corporation and *
+ * others. All Rights Reserved. *
+ ******************************************************************************
+ */
+/*
+ WBNF, Weighted BNF, is an extend BNF. The most difference between WBNF
+ and standard BNF is the WBNF accepts weight for its alternation items.
+ The weight specifies the opportunity it will be selected.
+
+ The purpose of WBNF is to help generate a random string from a given grammar
+ which can be described with standard BNF. The introduction of 'weight'
+ is to guide the generator to give the specific parts different chances to be
+ generated.
+
+ Usually, the user gives LanguageGenerator the grammar description in WBNF,
+ then LanguageGenerator will generate a random string on every next() call.
+ The return code of parseBNF() can help user to determine the error,
+ either in the grammar description or in the WBNF parser itself.
+
+
+ The grammar of WBNF itself can be described in standard BNF,
+
+ escaping = _single character with a leading back slash, either inside or outside quoting_
+ quoting = _quoted with a pair of single quotation marks_
+ string = string alphabet | string digit | string quoting | string escaping |
+ alphabet | quoting | escaping
+ alphabet =
+ digit =
+ integer = integer digit | digit
+ weight = integer %
+ weight-list = weight-list weight | weight
+ var = var alphabet | var digit | $ alphabet
+
+ var-defs = var-defs var-def | var-def
+ var-def = var '=' definition;
+
+ alternation = alternation '|' alt-item | alt-item
+ alt-item = sequence | sequence weight
+
+ sequence = sequence modified | modified
+
+ modified = core | morph | quote | repeat
+ morph = modified ~
+ quote = modified @
+ repeat = modified quantifier | modified quantifier weight-list
+ quantifier = ? | * | + | { integer , integer} | {integer, } | {integer}
+
+ core = var | string | '(' definition ')'
+
+ definition = core | modified | sequence | alternation
+ definition = alternation
+
+ Remarks:
+ o Following characters are literals in preceding definition
+ but are syntax symbols in WBNF
+
+ % $ ~ @ ? * + { } ,
+
+ o Following character are syntax symbols in preceding definition
+ (sapce) contact operation, or separators to increase readability
+ = definition
+ | selection operation
+ ( ) precedence select
+ ' ' override special-character to plain character
+
+ o the definition of 'escaping' and 'quoting' are preceding definition text
+ o infinite is actually a predefine value PSEUDO_INFINIT defined in this file
+ o if weight is not presented in "alt-item' and 'repeat',
+ a default weight DEFAULT_WEIGHT defined in this file is used
+
+ o * == {0, }
+ + == {1, }
+ ? == {0, 1}
+
+ o the weight-list for repeat assigns the weights for repeat itmes one by one
+
+ demo{1,3} 30% 40% 100% == (demo)30% | (demodemo)40% | (demodemodemo)100%
+
+ To find more explain of the weight-list, please see the LIMITATION of the grammar
+
+ o but the weight-list for question mark has different meaning
+
+ demo ? 30% != demo{0,1} 30% 100%
+ demo ? 30% == demo{0,1} 70% 30%
+
+ the 70% is calculated from (DEFAULT_WEIGHT - weight)
+
+
+ Known LIMITATION of the grammar
+ For 'repeat', the parser will eat up as much as possible weights at one time,
+ discard superfluous weights if it is too much,
+ fill insufficient weights with default weight if it is too less.
+ This behavior means following definitions are equal
+
+ demo{1,3} 30% 40% 100%
+ demo{1,3} 30% 40% 100% 50%
+ demo{1,3} 30% 40%
+
+ This behavior will cause a little confusion when defining an alternation
+
+ demo{1,3} 30% 40% 100% 50% | show 20%
+
+ is interpreted as
+
+ (demo{1,3} 30% 40% 100%) 100% | show 20%
+
+ not
+
+ (demo{1,3} 30% 40% 100%) 50% | show 20%
+
+ to get an expected definition, please use parentheses.
+
+ Known LIMITATION of current implement
+ Due to the well known point alias problem, current Parser will be effectively
+ crashed if the definition looks like
+
+ $a = demo;
+ $b = $a;
+ $c = $a;
+ or
+ $a = demo;
+ $b = $a $a;
+ or
+ $a = demo;
+ $b = $b $a;
+
+ The crash will occur at delete operation in destructor or other memory release code.
+ Several plans are on hard to fix the problem. Use a smart point with reference count,
+ or use a central memory management solution. But now, it works well with collation
+ monkey test, which is the only user for WBNF.
+*/
+
+#ifndef _WBNF
+#define _WBNF
+
+#include "unicode/utypes.h"
+
+const int DEFAULT_WEIGHT = 100;
+const int PSEUDO_INFINIT = 200;
+
+class LanguageGenerator_impl;
+
+class LanguageGenerator{
+ LanguageGenerator_impl * lang_gen;
+public:
+ enum PARSE_RESULT {OK, BNF_DEF_WRONG, INCOMPLETE, NO_TOP_NODE};
+ LanguageGenerator();
+ ~LanguageGenerator();
+ PARSE_RESULT parseBNF(const char *const bnf_definition /*in*/, const char *const top_node/*in*/, UBool debug=FALSE);
+ const char *next(); /* Return a null-terminated c-string. The buffer is owned by callee. */
+};
+
+void TestWbnf(void);
+
+#endif /* _WBNF */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/windttst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/windttst.cpp
new file mode 100644
index 00000000000..3869f34acfc
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/windttst.cpp
@@ -0,0 +1,197 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINDTTST.CPP
+*
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+#include "unicode/ustring.h"
+#include "unicode/testlog.h"
+#include "unicode/utmscale.h"
+
+#include "windtfmt.h"
+#include "winutil.h"
+#include "windttst.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+#include "locmap.h"
+#include "wintz.h"
+
+# define WIN32_LEAN_AND_MEAN
+# define VC_EXTRALEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+# include <windows.h>
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+
+static const char *getCalendarType(int32_t type)
+{
+ switch (type)
+ {
+ case 1:
+ case 2:
+ return "@calendar=gregorian";
+
+ case 3:
+ return "@calendar=japanese";
+
+ case 6:
+ return "@calendar=islamic";
+
+ case 7:
+ return "@calendar=buddhist";
+
+ case 8:
+ return "@calendar=hebrew";
+
+ default:
+ return "";
+ }
+}
+
+void Win32DateTimeTest::testLocales(TestLog *log)
+{
+ SYSTEMTIME winNow;
+ UDate icuNow = 0;
+ SYSTEMTIME st;
+ FILETIME ft;
+ UnicodeString zoneID;
+ const TimeZone *tz = TimeZone::createDefault();
+ TIME_ZONE_INFORMATION tzi;
+
+ uprv_memset(&tzi, 0, sizeof(tzi));
+ tz->getID(zoneID);
+ if (! uprv_getWindowsTimeZoneInfo(&tzi, zoneID.getBuffer(), zoneID.length())) {
+ UBool found = FALSE;
+ int32_t ec = TimeZone::countEquivalentIDs(zoneID);
+
+ for (int z = 0; z < ec; z += 1) {
+ UnicodeString equiv = TimeZone::getEquivalentID(zoneID, z);
+
+ if (found = uprv_getWindowsTimeZoneInfo(&tzi, equiv.getBuffer(), equiv.length())) {
+ break;
+ }
+ }
+
+ if (! found) {
+ GetTimeZoneInformation(&tzi);
+ }
+ }
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+ SystemTimeToTzSpecificLocalTime(&tzi, &st, &winNow);
+
+ int64_t wftNow = ((int64_t) ft.dwHighDateTime << 32) + ft.dwLowDateTime;
+ UErrorCode status = U_ZERO_ERROR;
+
+ int64_t udtsNow = utmscale_fromInt64(wftNow, UDTS_WINDOWS_FILE_TIME, &status);
+
+ icuNow = (UDate) utmscale_toInt64(udtsNow, UDTS_ICU4C_TIME, &status);
+
+ int32_t lcidCount = 0;
+ Win32Utilities::LCIDRecord *lcidRecords = Win32Utilities::getLocales(lcidCount);
+
+ for(int i = 0; i < lcidCount; i += 1) {
+ UErrorCode status = U_ZERO_ERROR;
+ WCHAR longDateFormat[81], longTimeFormat[81], wdBuffer[256], wtBuffer[256];
+ int32_t calType = 0;
+
+ // NULL localeID means ICU didn't recognize this locale
+ if (lcidRecords[i].localeID == NULL) {
+ continue;
+ }
+
+ GetLocaleInfoW(lcidRecords[i].lcid, LOCALE_SLONGDATE, longDateFormat, 81);
+ GetLocaleInfoW(lcidRecords[i].lcid, LOCALE_STIMEFORMAT, longTimeFormat, 81);
+ GetLocaleInfoW(lcidRecords[i].lcid, LOCALE_RETURN_NUMBER|LOCALE_ICALENDARTYPE, (LPWSTR) calType, sizeof(int32_t));
+
+ char localeID[64];
+
+ uprv_strcpy(localeID, lcidRecords[i].localeID);
+ uprv_strcat(localeID, getCalendarType(calType));
+
+ UnicodeString ubBuffer, udBuffer, utBuffer;
+ Locale ulocale(localeID);
+ int32_t wdLength, wtLength;
+
+ wdLength = GetDateFormatW(lcidRecords[i].lcid, DATE_LONGDATE, &winNow, NULL, wdBuffer, ARRAY_SIZE(wdBuffer));
+ wtLength = GetTimeFormatW(lcidRecords[i].lcid, 0, &winNow, NULL, wtBuffer, ARRAY_SIZE(wtBuffer));
+
+ if (uprv_strchr(localeID, '@') > 0) {
+ uprv_strcat(localeID, ";");
+ } else {
+ uprv_strcat(localeID, "@");
+ }
+
+ uprv_strcat(localeID, "compat=host");
+
+ Locale wlocale(localeID);
+ DateFormat *wbf = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, wlocale);
+ DateFormat *wdf = DateFormat::createDateInstance(DateFormat::kFull, wlocale);
+ DateFormat *wtf = DateFormat::createTimeInstance(DateFormat::kFull, wlocale);
+
+ wbf->format(icuNow, ubBuffer);
+ wdf->format(icuNow, udBuffer);
+ wtf->format(icuNow, utBuffer);
+
+ if (ubBuffer.indexOf(wdBuffer, wdLength - 1, 0) < 0) {
+ UnicodeString baseName(wlocale.getBaseName());
+ UnicodeString expected(wdBuffer);
+
+ log->errln("DateTime format error for locale " + baseName + ": expected date \"" + expected +
+ "\" got \"" + ubBuffer + "\"");
+ }
+
+ if (ubBuffer.indexOf(wtBuffer, wtLength - 1, 0) < 0) {
+ UnicodeString baseName(wlocale.getBaseName());
+ UnicodeString expected(wtBuffer);
+
+ log->errln("DateTime format error for locale " + baseName + ": expected time \"" + expected +
+ "\" got \"" + ubBuffer + "\"");
+ }
+
+ if (udBuffer.compare(wdBuffer) != 0) {
+ UnicodeString baseName(wlocale.getBaseName());
+ UnicodeString expected(wdBuffer);
+
+ log->errln("Date format error for locale " + baseName + ": expected \"" + expected +
+ "\" got \"" + udBuffer + "\"");
+ }
+
+ if (utBuffer.compare(wtBuffer) != 0) {
+ UnicodeString baseName(wlocale.getBaseName());
+ UnicodeString expected(wtBuffer);
+
+ log->errln("Time format error for locale " + baseName + ": expected \"" + expected +
+ "\" got \"" + utBuffer + "\"");
+ }
+ delete wbf;
+ delete wdf;
+ delete wtf;
+ }
+
+ Win32Utilities::freeLocales(lcidRecords);
+ delete tz;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif /* #ifdef U_WINDOWS */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/windttst.h b/Build/source/libs/icu/icu-xetex/test/intltest/windttst.h
new file mode 100644
index 00000000000..b9b3e637488
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/windttst.h
@@ -0,0 +1,41 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINDTTST.H
+*
+********************************************************************************
+*/
+
+#ifndef __WINDTTST
+#define __WINDTTST
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * \file
+ * \brief C++ API: Format dates using Windows API.
+ */
+
+class TestLog;
+
+class Win32DateTimeTest
+{
+public:
+ static void testLocales(TestLog *log);
+
+private:
+ Win32DateTimeTest();
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // #ifdef U_WINDOWS
+
+#endif // __WINDTTST
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/winnmtst.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/winnmtst.cpp
new file mode 100644
index 00000000000..dfbf200bff0
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/winnmtst.cpp
@@ -0,0 +1,323 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINNMTST.CPP
+*
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/format.h"
+#include "unicode/numfmt.h"
+#include "unicode/locid.h"
+#include "unicode/ustring.h"
+#include "unicode/testlog.h"
+#include "unicode/utmscale.h"
+
+#include "winnmfmt.h"
+#include "winutil.h"
+#include "winnmtst.h"
+
+#include "cmemory.h"
+#include "cstring.h"
+#include "locmap.h"
+#include "wintz.h"
+#include "uassert.h"
+
+# define WIN32_LEAN_AND_MEAN
+# define VC_EXTRALEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+# include <windows.h>
+# include <stdio.h>
+# include <time.h>
+# include <float.h>
+# include <locale.h>
+
+#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
+#define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
+#define DELETE_ARRAY(array) uprv_free((void *) (array))
+
+#define STACK_BUFFER_SIZE 32
+
+#define LOOP_COUNT 1000
+
+static UBool initialized = FALSE;
+
+/**
+ * Return a random int64_t where U_INT64_MIN <= ran <= U_INT64_MAX.
+ */
+static uint64_t randomInt64(void)
+{
+ int64_t ran = 0;
+ int32_t i;
+
+ if (!initialized) {
+ srand((unsigned)time(NULL));
+ initialized = TRUE;
+ }
+
+ /* Assume rand has at least 12 bits of precision */
+ for (i = 0; i < sizeof(ran); i += 1) {
+ ((char*)&ran)[i] = (char)((rand() & 0x0FF0) >> 4);
+ }
+
+ return ran;
+}
+
+/**
+ * Return a random double where U_DOUBLE_MIN <= ran <= U_DOUBLE_MAX.
+ */
+static double randomDouble(void)
+{
+ double ran = 0;
+
+ if (!initialized) {
+ srand((unsigned)time(NULL));
+ initialized = TRUE;
+ }
+#if 0
+ int32_t i;
+ do {
+ /* Assume rand has at least 12 bits of precision */
+ for (i = 0; i < sizeof(ran); i += 1) {
+ ((char*)&ran)[i] = (char)((rand() & 0x0FF0) >> 4);
+ }
+ } while (_isnan(ran));
+#else
+ int64_t numerator = randomInt64();
+ int64_t denomenator;
+ do {
+ denomenator = randomInt64();
+ }
+ while (denomenator == 0);
+
+ ran = (double)numerator / (double)denomenator;
+#endif
+
+ return ran;
+}
+
+/**
+ * Return a random int32_t where U_INT32_MIN <= ran <= U_INT32_MAX.
+ */
+static uint32_t randomInt32(void)
+{
+ int32_t ran = 0;
+ int32_t i;
+
+ if (!initialized) {
+ srand((unsigned)time(NULL));
+ initialized = TRUE;
+ }
+
+ /* Assume rand has at least 12 bits of precision */
+ for (i = 0; i < sizeof(ran); i += 1) {
+ ((char*)&ran)[i] = (char)((rand() & 0x0FF0) >> 4);
+ }
+
+ return ran;
+}
+
+static UnicodeString &getWindowsFormat(int32_t lcid, UBool currency, UnicodeString &appendTo, const wchar_t *fmt, ...)
+{
+ wchar_t nStackBuffer[STACK_BUFFER_SIZE];
+ wchar_t *nBuffer = nStackBuffer;
+ va_list args;
+ int result;
+
+ nBuffer[0] = 0x0000;
+
+ /* Due to the arguments causing a result to be <= 23 characters (+2 for NULL and minus),
+ we don't need to reallocate the buffer. */
+ va_start(args, fmt);
+ result = _vsnwprintf(nBuffer, STACK_BUFFER_SIZE, fmt, args);
+ va_end(args);
+
+ /* Just to make sure of the above statement, we add this assert */
+ U_ASSERT(result >=0);
+ // The following code is not used because _vscwprintf isn't available on MinGW at the moment.
+ /*if (result < 0) {
+ int newLength;
+
+ va_start(args, fmt);
+ newLength = _vscwprintf(fmt, args);
+ va_end(args);
+
+ nBuffer = NEW_ARRAY(UChar, newLength + 1);
+
+ va_start(args, fmt);
+ result = _vsnwprintf(nBuffer, newLength + 1, fmt, args);
+ va_end(args);
+ }*/
+
+
+ // vswprintf is sensitive to the locale set by setlocale. For some locales
+ // it doesn't use "." as the decimal separator, which is what GetNumberFormatW
+ // and GetCurrencyFormatW both expect to see.
+ //
+ // To fix this, we scan over the string and replace the first non-digits, except
+ // for a leading "-", with a "."
+ //
+ // Note: (nBuffer[0] == L'-') will evaluate to 1 if there is a leading '-' in the
+ // number, and 0 otherwise.
+ for (wchar_t *p = &nBuffer[nBuffer[0] == L'-']; *p != L'\0'; p += 1) {
+ if (*p < L'0' || *p > L'9') {
+ *p = L'.';
+ break;
+ }
+ }
+
+ wchar_t stackBuffer[STACK_BUFFER_SIZE];
+ wchar_t *buffer = stackBuffer;
+
+ buffer[0] = 0x0000;
+
+ if (currency) {
+ result = GetCurrencyFormatW(lcid, 0, nBuffer, NULL, buffer, STACK_BUFFER_SIZE);
+
+ if (result == 0) {
+ DWORD lastError = GetLastError();
+
+ if (lastError == ERROR_INSUFFICIENT_BUFFER) {
+ int newLength = GetCurrencyFormatW(lcid, 0, nBuffer, NULL, NULL, 0);
+
+ buffer = NEW_ARRAY(UChar, newLength);
+ buffer[0] = 0x0000;
+ GetCurrencyFormatW(lcid, 0, nBuffer, NULL, buffer, newLength);
+ }
+ }
+ } else {
+ result = GetNumberFormatW(lcid, 0, nBuffer, NULL, buffer, STACK_BUFFER_SIZE);
+
+ if (result == 0) {
+ DWORD lastError = GetLastError();
+
+ if (lastError == ERROR_INSUFFICIENT_BUFFER) {
+ int newLength = GetNumberFormatW(lcid, 0, nBuffer, NULL, NULL, 0);
+
+ buffer = NEW_ARRAY(UChar, newLength);
+ buffer[0] = 0x0000;
+ GetNumberFormatW(lcid, 0, nBuffer, NULL, buffer, newLength);
+ }
+ }
+ }
+
+ appendTo.append(buffer, (int32_t) wcslen(buffer));
+
+ if (buffer != stackBuffer) {
+ DELETE_ARRAY(buffer);
+ }
+
+ /*if (nBuffer != nStackBuffer) {
+ DELETE_ARRAY(nBuffer);
+ }*/
+
+ return appendTo;
+}
+
+static void testLocale(const char *localeID, int32_t lcid, NumberFormat *wnf, UBool currency, TestLog *log)
+{
+ for (int n = 0; n < LOOP_COUNT; n += 1) {
+ UnicodeString u3Buffer, u6Buffer, udBuffer;
+ UnicodeString w3Buffer, w6Buffer, wdBuffer;
+ double d = randomDouble();
+ int32_t i32 = randomInt32();
+ int64_t i64 = randomInt64();
+
+ getWindowsFormat(lcid, currency, wdBuffer, L"%.16f", d);
+
+ getWindowsFormat(lcid, currency, w3Buffer, L"%I32d", i32);
+
+ getWindowsFormat(lcid, currency, w6Buffer, L"%I64d", i64);
+
+ wnf->format(d, udBuffer);
+ if (udBuffer.compare(wdBuffer) != 0) {
+ UnicodeString locale(localeID);
+
+ log->errln("Double format error for locale " + locale +
+ ": got " + udBuffer + " expected " + wdBuffer);
+ }
+
+ wnf->format(i32, u3Buffer);
+ if (u3Buffer.compare(w3Buffer) != 0) {
+ UnicodeString locale(localeID);
+
+ log->errln("int32_t format error for locale " + locale +
+ ": got " + u3Buffer + " expected " + w3Buffer);
+ }
+
+ wnf->format(i64, u6Buffer);
+ if (u6Buffer.compare(w6Buffer) != 0) {
+ UnicodeString locale(localeID);
+
+ log->errln("int64_t format error for locale " + locale +
+ ": got " + u6Buffer + " expected " + w6Buffer);
+ }
+ }
+}
+
+void Win32NumberTest::testLocales(TestLog *log)
+{
+ int32_t lcidCount = 0;
+ Win32Utilities::LCIDRecord *lcidRecords = Win32Utilities::getLocales(lcidCount);
+
+ for(int i = 0; i < lcidCount; i += 1) {
+ UErrorCode status = U_ZERO_ERROR;
+ char localeID[128];
+
+ // NULL localeID means ICU didn't recognize the lcid
+ if (lcidRecords[i].localeID == NULL) {
+ continue;
+ }
+
+ strcpy(localeID, lcidRecords[i].localeID);
+
+ if (strchr(localeID, '@') > 0) {
+ strcat(localeID, ";");
+ } else {
+ strcat(localeID, "@");
+ }
+
+ strcat(localeID, "compat=host");
+
+ Locale ulocale(localeID);
+ NumberFormat *wnf = NumberFormat::createInstance(ulocale, status);
+ NumberFormat *wcf = NumberFormat::createCurrencyInstance(ulocale, status);
+
+ testLocale(lcidRecords[i].localeID, lcidRecords[i].lcid, wnf, FALSE, log);
+ testLocale(lcidRecords[i].localeID, lcidRecords[i].lcid, wcf, TRUE, log);
+
+#if 0
+ char *old_locale = strdup(setlocale(LC_ALL, NULL));
+
+ setlocale(LC_ALL, "German");
+
+ testLocale(lcidRecords[i].localeID, lcidRecords[i].lcid, wnf, FALSE, log);
+ testLocale(lcidRecords[i].localeID, lcidRecords[i].lcid, wcf, TRUE, log);
+
+ setlocale(LC_ALL, old_locale);
+
+ free(old_locale);
+#endif
+
+ delete wcf;
+ delete wnf;
+ }
+
+ Win32Utilities::freeLocales(lcidRecords);
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif /* #ifdef U_WINDOWS */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/winnmtst.h b/Build/source/libs/icu/icu-xetex/test/intltest/winnmtst.h
new file mode 100644
index 00000000000..411969ad9ef
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/winnmtst.h
@@ -0,0 +1,41 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINNMTST.H
+*
+********************************************************************************
+*/
+
+#ifndef __WINNMTST
+#define __WINNMTST
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * \file
+ * \brief C++ API: Format dates using Windows API.
+ */
+
+class TestLog;
+
+class Win32NumberTest
+{
+public:
+ static void testLocales(TestLog *log);
+
+private:
+ Win32NumberTest();
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // #ifdef U_WINDOWS
+
+#endif // __WINNMTST
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/winutil.cpp b/Build/source/libs/icu/icu-xetex/test/intltest/winutil.cpp
new file mode 100644
index 00000000000..1963221ea4e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/winutil.cpp
@@ -0,0 +1,81 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINUTIL.CPP
+*
+********************************************************************************
+*/
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "winutil.h"
+#include "locmap.h"
+
+# define WIN32_LEAN_AND_MEAN
+# define VC_EXTRALEAN
+# define NOUSER
+# define NOSERVICE
+# define NOIME
+# define NOMCX
+# include <windows.h>
+# include <stdio.h>
+
+static Win32Utilities::LCIDRecord *lcidRecords = NULL;
+static int32_t lcidCount = 0;
+static int32_t lcidMax = 0;
+
+BOOL CALLBACK EnumLocalesProc(LPSTR lpLocaleString)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ if (lcidCount >= lcidMax) {
+ Win32Utilities::LCIDRecord *newRecords = new Win32Utilities::LCIDRecord[lcidMax + 32];
+
+ for (int i = 0; i < lcidMax; i += 1) {
+ newRecords[i] = lcidRecords[i];
+ }
+
+ delete[] lcidRecords;
+ lcidRecords = newRecords;
+ lcidMax += 32;
+ }
+
+ sscanf(lpLocaleString, "%8x", &lcidRecords[lcidCount].lcid);
+
+ lcidRecords[lcidCount].localeID = uprv_convertToPosix(lcidRecords[lcidCount].lcid, &status);
+
+ lcidCount += 1;
+
+ return TRUE;
+}
+
+Win32Utilities::LCIDRecord *Win32Utilities::getLocales(int32_t &localeCount)
+{
+ LCIDRecord *result;
+
+ EnumSystemLocalesA(EnumLocalesProc, LCID_INSTALLED);
+
+ localeCount = lcidCount;
+ result = lcidRecords;
+
+ lcidCount = lcidMax = 0;
+ lcidRecords = NULL;
+
+ return result;
+}
+
+void Win32Utilities::freeLocales(LCIDRecord *records)
+{
+ delete[] records;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif /* #ifdef U_WINDOWS */
diff --git a/Build/source/libs/icu/icu-xetex/test/intltest/winutil.h b/Build/source/libs/icu/icu-xetex/test/intltest/winutil.h
new file mode 100644
index 00000000000..03a0044ac6e
--- /dev/null
+++ b/Build/source/libs/icu/icu-xetex/test/intltest/winutil.h
@@ -0,0 +1,46 @@
+/*
+********************************************************************************
+* Copyright (C) 2005-2006, International Business Machines
+* Corporation and others. All Rights Reserved.
+********************************************************************************
+*
+* File WINUTIL.H
+*
+********************************************************************************
+*/
+
+#ifndef __WINUTIL
+#define __WINUTIL
+
+#include "unicode/utypes.h"
+
+#ifdef U_WINDOWS
+
+#if !UCONFIG_NO_FORMATTING
+
+/**
+ * \file
+ * \brief C++ API: Format dates using Windows API.
+ */
+
+class Win32Utilities
+{
+public:
+ struct LCIDRecord
+ {
+ int32_t lcid;
+ const char *localeID;
+ };
+
+ static LCIDRecord *getLocales(int32_t &localeCount);
+ static void freeLocales(LCIDRecord *records);
+
+private:
+ Win32Utilities();
+};
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
+
+#endif // #ifdef U_WINDOWS
+
+#endif // __WINUTIL