1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 2005-2014, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
11 * created on: 2005jun15
12 * created by: Raymond Yang
15 #include "unicode/utypes.h"
22 #include "unicode/ucnv.h"
23 #include "unicode/ustring.h"
24 #include "unicode/uidna.h"
25 #include "unicode/utf16.h"
28 static const UChar C_TAG
[] = {0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0}; // =====
29 static const UChar C_NAMEZONE
[] = {0x6E, 0x61, 0x6D, 0x65, 0x7A, 0x6F, 0x6E, 0x65, 0}; // namezone
30 static const UChar C_NAMEBASE
[] = {0x6E, 0x61, 0x6D, 0x65, 0x62, 0x61, 0x73, 0x65, 0}; // namebase
32 static const UChar C_TYPE
[] = {0x74, 0x79, 0x70, 0x65, 0}; // type
33 static const UChar C_TOASCII
[] = {0x74, 0x6F, 0x61, 0x73, 0x63, 0x69, 0x69, 0}; // toascii
34 static const UChar C_TOUNICODE
[] = {0x74, 0x6F, 0x75, 0x6E, 0x69, 0x63, 0x6F, 0x64, 0x65, 0}; // tounicode
36 static const UChar C_PASSFAIL
[] = {0x70, 0x61, 0x73, 0x73, 0x66, 0x61, 0x69, 0x6C, 0}; // passfail
37 static const UChar C_PASS
[] = {0x70, 0x61, 0x73, 0x73, 0}; // pass
38 static const UChar C_FAIL
[] = {0x66, 0x61, 0x69, 0x6C, 0}; // fail
40 static const UChar C_DESC
[] = {0x64, 0x65, 0x73, 0x63, 0}; // desc
41 static const UChar C_USESTD3ASCIIRULES
[] = {0x55, 0x73, 0x65, 0x53, 0x54, 0x44,
42 0x33, 0x41, 0x53, 0x43, 0x49, 0x49, 0x52, 0x75, 0x6C, 0x65, 0x73, 0}; // UseSTD3ASCIIRules
44 IdnaConfTest::IdnaConfTest(){
49 type
= option
= passfail
= -1;
50 namebase
.setToBogus();
51 namezone
.setToBogus();
53 IdnaConfTest::~IdnaConfTest(){
58 /* this function is modified from RBBITest::ReadAndConvertFile()
61 UBool
IdnaConfTest::ReadAndConvertFile(){
66 // read the test data file to memory
68 UErrorCode status
= U_ZERO_ERROR
;
70 const char *path
= IntlTest::getSourceTestData(status
);
71 if (U_FAILURE(status
)) {
72 errln("%s", u_errorName(status
));
76 const char* name
= "idna_conf.txt"; // test data file
77 int t
= static_cast<int>(strlen(path
) + strlen(name
) + 1);
78 char* absolute_name
= new char[t
];
79 strcpy(absolute_name
, path
);
80 strcat(absolute_name
, name
);
81 f
= fopen(absolute_name
, "rb");
82 delete [] absolute_name
;
85 dataerrln("fopen error on %s", name
);
89 fseek( f
, 0, SEEK_END
);
90 if ((source_len
= ftell(f
)) <= 0){
91 errln("Error reading test data file.");
96 source
= new char[source_len
];
97 fseek(f
, 0, SEEK_SET
);
98 if (fread(source
, 1, source_len
, f
) != source_len
) {
99 errln("Error reading test data file.");
106 // convert the UTF-8 encoded stream to UTF-16 stream
107 UConverter
* conv
= ucnv_open("utf-8", &status
);
108 int dest_len
= ucnv_toUChars(conv
,
112 static_cast<int32_t>(source_len
),
114 if (status
== U_BUFFER_OVERFLOW_ERROR
) {
115 // Buffer Overflow is expected from the preflight operation.
116 status
= U_ZERO_ERROR
;
118 dest
= new UChar
[ dest_len
+ 1];
119 ucnv_toUChars(conv
, dest
, dest_len
+ 1, source
, static_cast<int32_t>(source_len
), &status
);
120 // Do not know the "if possible" behavior of ucnv_toUChars()
127 return TRUE
; // The buffer will owned by caller.
129 errln("UConverter error: %s", u_errorName(status
));
135 int IdnaConfTest::isNewlineMark(){
136 static const UChar LF
= 0x0a;
137 static const UChar CR
= 0x0d;
138 UChar c
= base
[curOffset
];
140 if ( c
== CR
&& curOffset
+ 1 < len
&& base
[curOffset
+ 1] == LF
){
145 if ( c
== CR
|| c
== LF
) {
152 /* Read a logical line.
154 * All lines ending in a backslash (\) and immediately followed by a newline
155 * character are joined with the next line in the source file forming logical
156 * lines from the physical lines.
159 UBool
IdnaConfTest::ReadOneLine(UnicodeString
& buf
){
160 if ( !(curOffset
< len
) ) return FALSE
; // stream end
162 static const UChar BACKSLASH
= 0x5c;
165 while (curOffset
< len
){
166 if ((t
= isNewlineMark())) { // end of line
170 UChar c
= base
[curOffset
];
171 if (c
== BACKSLASH
&& curOffset
< len
-1){ // escaped new line mark
172 if ((t
= isNewlineMark())){
173 curOffset
+= 1 + t
; // BACKSLAH and NewlineMark
184 //===============================================================
187 /* Explain <xxxxx> tag to a native value
189 * Since <xxxxx> is always larger than the native value,
190 * the operation will replace the tag directly in the buffer,
191 * and, of course, will shift tail elements.
193 void IdnaConfTest::ExplainCodePointTag(UnicodeString
& buf
){
194 buf
.append((UChar
)0); // add a terminal NULL
195 UChar
* bufBase
= buf
.getBuffer(buf
.length());
198 if ( *p
!= 0x3C){ // <
203 for ( ;*p
!= 0x3E; p
++){ // >
204 if (0x30 <= *p
&& *p
<= 0x39){ // 0-9
205 cp
= (cp
* 16) + (*p
- 0x30);
206 } else if (0x61 <= *p
&& *p
<= 0x66){ // a-f
207 cp
= (cp
* 16) + (*p
- 0x61) + 10;
208 } else if (0x41 <= *p
&& *p
<= 0x46) {// A-F
209 cp
= (cp
* 16) + (*p
- 0x41) + 10;
211 // no else. hope everything is good.
217 *bufBase
++ = U16_LEAD(cp
);
218 *bufBase
++ = U16_TRAIL(cp
);
222 *bufBase
= 0; // close our buffer
226 void IdnaConfTest::Call(){
227 if (type
== -1 || option
== -1 || passfail
== -1 || namebase
.isBogus() || namezone
.isBogus()){
228 errln("Incomplete record");
230 UErrorCode status
= U_ZERO_ERROR
;
231 UChar result
[200] = {0,}; // simple life
232 const UChar
*p
= namebase
.getTerminatedBuffer();
233 const int p_len
= namebase
.length();
235 if (type
== 0 && option
== 0){
236 uidna_IDNToASCII(p
, p_len
, result
, 200, UIDNA_USE_STD3_RULES
, NULL
, &status
);
237 } else if (type
== 0 && option
== 1){
238 uidna_IDNToASCII(p
, p_len
, result
, 200, UIDNA_ALLOW_UNASSIGNED
, NULL
, &status
);
239 } else if (type
== 1 && option
== 0){
240 uidna_IDNToUnicode(p
, p_len
, result
, 200, UIDNA_USE_STD3_RULES
, NULL
, &status
);
241 } else if (type
== 1 && option
== 1){
242 uidna_IDNToUnicode(p
, p_len
, result
, 200, UIDNA_ALLOW_UNASSIGNED
, NULL
, &status
);
245 if (U_FAILURE(status
)){
246 id
.append(" should pass, but failed. - ");
247 id
.append(u_errorName(status
));
248 errcheckln(status
, id
);
250 if (namezone
.compare(result
, -1) == 0){
252 logln(UnicodeString("namebase: ") + prettify(namebase
) + UnicodeString(" result: ") + prettify(result
));
254 id
.append(" no error, but result is not as expected.");
258 } else if (passfail
== 1){
259 if (U_FAILURE(status
)){
261 // TODO: Uncomment this when U_IDNA_ZERO_LENGTH_LABEL_ERROR is added to u_errorName
262 //logln("Got the expected error: " + UnicodeString(u_errorName(status)));
264 if (namebase
.compare(result
, -1) == 0){
265 // garbage in -> garbage out
266 logln(UnicodeString("ICU will not recognize malformed ACE-Prefixes or incorrect ACE-Prefixes. ") + UnicodeString("namebase: ") + prettify(namebase
) + UnicodeString(" result: ") + prettify(result
));
268 id
.append(" should fail, but not failed. ");
269 id
.append(u_errorName(status
));
275 type
= option
= passfail
= -1;
276 namebase
.setToBogus();
277 namezone
.setToBogus();
282 void IdnaConfTest::Test(void){
283 if (!ReadAndConvertFile())return;
289 // skip everything before the first "=====" and "=====" itself
291 if (!ReadOneLine(s
)) {
292 errln("End of file prematurely found");
296 while (s
.compare(C_TAG
, -1) != 0); //"====="
298 while(ReadOneLine(s
)){
302 if (s
.compare(C_TAG
, -1) == 0){ //"====="
306 int p
= s
.indexOf((UChar
)0x3A); // :
307 key
.setTo(s
,0,p
).trim();
308 value
.setTo(s
,p
+1).trim();
309 if (key
.compare(C_TYPE
, -1) == 0){
310 if (value
.compare(C_TOASCII
, -1) == 0) {
312 } else if (value
.compare(C_TOUNICODE
, -1) == 0){
315 } else if (key
.compare(C_PASSFAIL
, -1) == 0){
316 if (value
.compare(C_PASS
, -1) == 0){
318 } else if (value
.compare(C_FAIL
, -1) == 0){
321 } else if (key
.compare(C_DESC
, -1) == 0){
322 if (value
.indexOf(C_USESTD3ASCIIRULES
, u_strlen(C_USESTD3ASCIIRULES
), 0) == -1){
323 option
= 1; // not found
327 id
.setTo(value
, 0, value
.indexOf((UChar
)0x20)); // space
328 } else if (key
.compare(C_NAMEZONE
, -1) == 0){
329 ExplainCodePointTag(value
);
330 namezone
.setTo(value
);
331 } else if (key
.compare(C_NAMEBASE
, -1) == 0){
332 ExplainCodePointTag(value
);
333 namebase
.setTo(value
);
335 // just skip other lines
339 Call(); // for last record
342 void IdnaConfTest::Test(void)
348 void IdnaConfTest::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/){
351 default: name
= ""; break;