1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* ***** BEGIN LICENSE BLOCK ***** 3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * http://www.mozilla.org/MPL/ 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 * 15 * The Original Code is Mozilla Communicator client code, released 16 * March 31, 1998. 17 * 18 * The Initial Developer of the Original Code is 19 * Netscape Communications Corporation. 20 * Portions created by the Initial Developer are Copyright (C) 1998 21 * the Initial Developer. All Rights Reserved. 22 * 23 * Contributor(s): 24 * 25 * Alternatively, the contents of this file may be used under the terms of 26 * either the GNU General Public License Version 2 or later (the "GPL"), or 27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 28 * in which case the provisions of the GPL or the LGPL are applicable instead 29 * of those above. If you wish to allow use of your version of this file only 30 * under the terms of either the GPL or the LGPL, and not to allow others to 31 * use your version of this file under the terms of the MPL, indicate your 32 * decision by deleting the provisions above and replace them with the notice 33 * and other provisions required by the GPL or the LGPL. If you do not delete 34 * the provisions above, a recipient may use your version of this file under 35 * the terms of any one of the MPL, the GPL or the LGPL. 36 * 37 * ***** END LICENSE BLOCK ***** */ 38 /** 39 File Name: 15.5.4.11-2.js 40 ECMA Section: 15.5.4.11 String.prototype.toLowerCase() 41 Description: 42 43 Returns a string equal in length to the length of the result of converting 44 this object to a string. The result is a string value, not a String object. 45 46 Every character of the result is equal to the corresponding character of the 47 string, unless that character has a Unicode 2.0 uppercase equivalent, in which 48 case the uppercase equivalent is used instead. (The canonical Unicode 2.0 case 49 mapping shall be used, which does not depend on implementation or locale.) 50 51 Note that the toLowerCase function is intentionally generic; it does not require 52 that its this value be a String object. Therefore it can be transferred to other 53 kinds of objects for use as a method. 54 55 Author: christine (at) netscape.com 56 Date: 12 november 1997 57 */ 58 /* 59 Safari Changes: This test differs from the mozilla tests in two significant 60 ways. 61 First, the lower case range for Georgian letters in this file is the 62 correct range according to the Unicode 5.0 standard, as opposed to the 63 Georgian caseless range that mozilla uses. 64 Secondly this test uses an array for expected results with two entries, 65 instead of a single expected result. This allows us to accept Unicode 4.0 or 66 Unicode 5.0 results as correct, as opposed to the mozilla test, which assumes 67 Unicode 5.0. This allows Safari to pass this test on OS' with different 68 Unicode standards implemented (e.g. Tiger and XP) 69 */ 70 var SECTION = "15.5.4.11-2"; 71 var VERSION = "ECMA_1"; 72 startTest(); 73 var TITLE = "String.prototype.toLowerCase()"; 74 75 writeHeaderToLog( SECTION + " "+ TITLE); 76 77 var testcases = getTestCases(); 78 test(); 79 80 function getTestCases() { 81 var array = new Array(); 82 var item = 0; 83 84 // Georgian 85 // Range: U+10A0 to U+10FF 86 for ( var i = 0x10A0; i <= 0x10FF; i++ ) { 87 var U = new Array(new Unicode( i, 4 ), new Unicode( i, 5 )); 88 89 /* 90 array[item++] = new TestCase( SECTION, 91 "var s = new String( String.fromCharCode("+i+") ); s.toLowerCase()", 92 String.fromCharCode(U.lower), 93 eval("var s = new String( String.fromCharCode("+i+") ); s.toLowerCase()") ); 94 */ 95 array[item++] = new TestCaseDualExpected( SECTION, 96 "var s = new String( String.fromCharCode("+i+") ); s.toLowerCase().charCodeAt(0)", 97 U, 98 eval("var s = new String( String.fromCharCode(i) ); s.toLowerCase().charCodeAt(0)") ); 99 } 100 101 return array; 102 } 103 104 /* 105 * TestCase constructor 106 * 107 */ 108 109 function TestCaseDualExpected( n, d, e, a ) { 110 this.name = n; 111 this.description = d; 112 this.expect = e; 113 this.actual = a; 114 this.passed = true; 115 this.reason = ""; 116 this.bugnumber = BUGNUMBER; 117 118 this.passed = getTestCaseResultDualExpected( this.expect, this.actual ); 119 if ( DEBUG ) { 120 writeLineToLog( "added " + this.description ); 121 } 122 } 123 124 // Added so that either Unicode 4.0 or 5.0 results will be considered correct. 125 function writeTestCaseResultDualExpected( expect, actual, string ) { 126 var passed = getTestCaseResultDualExpected( expect, actual ); 127 writeFormattedResult( expect[1].lower, actual, string, passed ); 128 return passed; 129 } 130 /* 131 * Added so that either Unicode 4.0 or 5.0 results will be considered correct. 132 * Compare expected result to the actual result and figure out whether 133 * the test case passed. 134 */ 135 function getTestCaseResultDualExpected( expect, actual ) { 136 expectedU4 = expect[0].lower; 137 expectedU5 = expect[1].lower; 138 // because ( NaN == NaN ) always returns false, need to do 139 // a special compare to see if we got the right result. 140 if ( actual != actual ) { 141 if ( typeof actual == "object" ) { 142 actual = "NaN object"; 143 } else { 144 actual = "NaN number"; 145 } 146 } 147 148 if ( expectedU4 != expectedU4 ) { 149 if ( typeof expectedU4 == "object" ) { 150 expectedU4 = "NaN object"; 151 } else { 152 expectedU4 = "NaN number"; 153 } 154 } 155 if ( expectedU5 != expectedU5 ) { 156 if ( typeof expectedU5 == "object" ) { 157 expectedU5 = "NaN object"; 158 } else { 159 expectedU5 = "NaN number"; 160 } 161 } 162 163 var passed = ( expectedU4 == actual || expectedU5 == actual ) ? true : false; 164 165 // if both objects are numbers 166 // need to replace w/ IEEE standard for rounding 167 if ( !passed && 168 typeof(actual) == "number" && 169 (typeof(expectedU4) == "number" || 170 typeof(expectedU5) == "number")) { 171 if (( Math.abs(actual-expectedU4) < 0.0000001 ) || ( Math.abs(actual-expectedU5) < 0.0000001 )) { 172 passed = true; 173 } 174 } 175 176 // verify type is the same 177 if ( typeof(expectedU4) != typeof(actual) && typeof(expectedU5) != typeof(actual) ) { 178 passed = false; 179 } 180 181 return passed; 182 } 183 184 function test() { 185 for ( tc=0; tc < testcases.length; tc++ ) { 186 testcases[tc].passed = writeTestCaseResultDualExpected( 187 testcases[tc].expect, 188 testcases[tc].actual, 189 testcases[tc].description +" = "+ testcases[tc].actual ); 190 191 testcases[tc].reason += ( testcases[tc].passed ) ? "" : "wrong value "; 192 } 193 stopTest(); 194 return ( testcases ); 195 } 196 197 function MyObject( value ) { 198 this.value = value; 199 this.substring = String.prototype.substring; 200 this.toString = new Function ( "return this.value+''" ); 201 } 202 203 function Unicode( c, version ) { 204 u = GetUnicodeValues( c, version ); 205 this.upper = u[0]; 206 this.lower = u[1] 207 return this; 208 } 209 210 function GetUnicodeValues( c, version ) { 211 u = new Array(); 212 213 u[0] = c; 214 u[1] = c; 215 216 // upper case Basic Latin 217 218 if ( c >= 0x0041 && c <= 0x005A) { 219 u[0] = c; 220 u[1] = c + 32; 221 return u; 222 } 223 224 // lower case Basic Latin 225 if ( c >= 0x0061 && c <= 0x007a ) { 226 u[0] = c - 32; 227 u[1] = c; 228 return u; 229 } 230 231 // upper case Latin-1 Supplement 232 if ( c == 0x00B5 ) { 233 u[0] = c; 234 u[1] = 0x039C; 235 return u; 236 } 237 if ( (c >= 0x00C0 && c <= 0x00D6) || (c >= 0x00D8 && c<=0x00DE) ) { 238 u[0] = c; 239 u[1] = c + 32; 240 return u; 241 } 242 243 // lower case Latin-1 Supplement 244 if ( (c >= 0x00E0 && c <= 0x00F6) || (c >= 0x00F8 && c <= 0x00FE) ) { 245 u[0] = c - 32; 246 u[1] = c; 247 return u; 248 } 249 if ( c == 0x00FF ) { 250 u[0] = 0x0178; 251 u[1] = c; 252 return u; 253 } 254 // Latin Extended A 255 if ( (c >= 0x0100 && c < 0x0138) || (c > 0x0149 && c < 0x0178) ) { 256 // special case for capital I 257 if ( c == 0x0130 ) { 258 u[0] = c; 259 u[1] = 0x0069; 260 return u; 261 } 262 if ( c == 0x0131 ) { 263 u[0] = 0x0049; 264 u[1] = c; 265 return u; 266 } 267 268 if ( c % 2 == 0 ) { 269 // if it's even, it's a capital and the lower case is c +1 270 u[0] = c; 271 u[1] = c+1; 272 } else { 273 // if it's odd, it's a lower case and upper case is c-1 274 u[0] = c-1; 275 u[1] = c; 276 } 277 return u; 278 } 279 if ( c == 0x0178 ) { 280 u[0] = c; 281 u[1] = 0x00FF; 282 return u; 283 } 284 285 if ( (c >= 0x0139 && c < 0x0149) || (c > 0x0178 && c < 0x017F) ) { 286 if ( c % 2 == 1 ) { 287 // if it's odd, it's a capital and the lower case is c +1 288 u[0] = c; 289 u[1] = c+1; 290 } else { 291 // if it's even, it's a lower case and upper case is c-1 292 u[0] = c-1; 293 u[1] = c; 294 } 295 return u; 296 } 297 if ( c == 0x017F ) { 298 u[0] = 0x0053; 299 u[1] = c; 300 } 301 302 // Latin Extended B 303 // need to improve this set 304 305 if ( c >= 0x0200 && c <= 0x0217 ) { 306 if ( c % 2 == 0 ) { 307 u[0] = c; 308 u[1] = c+1; 309 } else { 310 u[0] = c-1; 311 u[1] = c; 312 } 313 return u; 314 } 315 316 // Latin Extended Additional 317 // Range: U+1E00 to U+1EFF 318 // http://www.unicode.org/Unicode.charts/glyphless/U1E00.html 319 320 // Spacing Modifier Leters 321 // Range: U+02B0 to U+02FF 322 323 // Combining Diacritical Marks 324 // Range: U+0300 to U+036F 325 326 // skip Greek for now 327 // Greek 328 // Range: U+0370 to U+03FF 329 330 // Cyrillic 331 // Range: U+0400 to U+04FF 332 333 if ( c >= 0x0400 && c <= 0x040F) { 334 u[0] = c; 335 u[1] = c + 80; 336 return u; 337 } 338 339 340 if ( c >= 0x0410 && c <= 0x042F ) { 341 u[0] = c; 342 u[1] = c + 32; 343 return u; 344 } 345 346 if ( c >= 0x0430 && c<= 0x044F ) { 347 u[0] = c - 32; 348 u[1] = c; 349 return u; 350 351 } 352 if ( c >= 0x0450 && c<= 0x045F ) { 353 u[0] = c -80; 354 u[1] = c; 355 return u; 356 } 357 358 if ( c >= 0x0460 && c <= 0x047F ) { 359 if ( c % 2 == 0 ) { 360 u[0] = c; 361 u[1] = c +1; 362 } else { 363 u[0] = c - 1; 364 u[1] = c; 365 } 366 return u; 367 } 368 369 // Armenian 370 // Range: U+0530 to U+058F 371 if ( c >= 0x0531 && c <= 0x0556 ) { 372 u[0] = c; 373 u[1] = c + 48; 374 return u; 375 } 376 if ( c >= 0x0561 && c < 0x0587 ) { 377 u[0] = c - 48; 378 u[1] = c; 379 return u; 380 } 381 382 // Hebrew 383 // Range: U+0590 to U+05FF 384 385 386 // Arabic 387 // Range: U+0600 to U+06FF 388 389 // Devanagari 390 // Range: U+0900 to U+097F 391 392 393 // Bengali 394 // Range: U+0980 to U+09FF 395 396 397 // Gurmukhi 398 // Range: U+0A00 to U+0A7F 399 400 401 // Gujarati 402 // Range: U+0A80 to U+0AFF 403 404 405 // Oriya 406 // Range: U+0B00 to U+0B7F 407 // no capital / lower case 408 409 410 // Tamil 411 // Range: U+0B80 to U+0BFF 412 // no capital / lower case 413 414 415 // Telugu 416 // Range: U+0C00 to U+0C7F 417 // no capital / lower case 418 419 420 // Kannada 421 // Range: U+0C80 to U+0CFF 422 // no capital / lower case 423 424 425 // Malayalam 426 // Range: U+0D00 to U+0D7F 427 428 // Thai 429 // Range: U+0E00 to U+0E7F 430 431 432 // Lao 433 // Range: U+0E80 to U+0EFF 434 435 436 // Tibetan 437 // Range: U+0F00 to U+0FBF 438 439 // Georgian 440 // Range: U+10A0 to U+10F0 441 if ( version == 5 ) { 442 if ( c >= 0x10A0 && c <= 0x10C5 ) { 443 u[0] = c; 444 u[1] = c + 7264; //48; 445 return u; 446 } 447 if ( c >= 0x2D00 && c <= 0x2D25 ) { 448 u[0] = c; 449 u[1] = c; 450 return u; 451 } 452 } 453 454 // Hangul Jamo 455 // Range: U+1100 to U+11FF 456 457 // Greek Extended 458 // Range: U+1F00 to U+1FFF 459 // skip for now 460 461 462 // General Punctuation 463 // Range: U+2000 to U+206F 464 465 // Superscripts and Subscripts 466 // Range: U+2070 to U+209F 467 468 // Currency Symbols 469 // Range: U+20A0 to U+20CF 470 471 472 // Combining Diacritical Marks for Symbols 473 // Range: U+20D0 to U+20FF 474 // skip for now 475 476 477 // Number Forms 478 // Range: U+2150 to U+218F 479 // skip for now 480 481 482 // Arrows 483 // Range: U+2190 to U+21FF 484 485 // Mathematical Operators 486 // Range: U+2200 to U+22FF 487 488 // Miscellaneous Technical 489 // Range: U+2300 to U+23FF 490 491 // Control Pictures 492 // Range: U+2400 to U+243F 493 494 // Optical Character Recognition 495 // Range: U+2440 to U+245F 496 497 // Enclosed Alphanumerics 498 // Range: U+2460 to U+24FF 499 500 // Box Drawing 501 // Range: U+2500 to U+257F 502 503 // Block Elements 504 // Range: U+2580 to U+259F 505 506 // Geometric Shapes 507 // Range: U+25A0 to U+25FF 508 509 // Miscellaneous Symbols 510 // Range: U+2600 to U+26FF 511 512 // Dingbats 513 // Range: U+2700 to U+27BF 514 515 // CJK Symbols and Punctuation 516 // Range: U+3000 to U+303F 517 518 // Hiragana 519 // Range: U+3040 to U+309F 520 521 // Katakana 522 // Range: U+30A0 to U+30FF 523 524 // Bopomofo 525 // Range: U+3100 to U+312F 526 527 // Hangul Compatibility Jamo 528 // Range: U+3130 to U+318F 529 530 // Kanbun 531 // Range: U+3190 to U+319F 532 533 534 // Enclosed CJK Letters and Months 535 // Range: U+3200 to U+32FF 536 537 // CJK Compatibility 538 // Range: U+3300 to U+33FF 539 540 // Hangul Syllables 541 // Range: U+AC00 to U+D7A3 542 543 // High Surrogates 544 // Range: U+D800 to U+DB7F 545 546 // Private Use High Surrogates 547 // Range: U+DB80 to U+DBFF 548 549 // Low Surrogates 550 // Range: U+DC00 to U+DFFF 551 552 // Private Use Area 553 // Range: U+E000 to U+F8FF 554 555 // CJK Compatibility Ideographs 556 // Range: U+F900 to U+FAFF 557 558 // Alphabetic Presentation Forms 559 // Range: U+FB00 to U+FB4F 560 561 // Arabic Presentation Forms-A 562 // Range: U+FB50 to U+FDFF 563 564 // Combining Half Marks 565 // Range: U+FE20 to U+FE2F 566 567 // CJK Compatibility Forms 568 // Range: U+FE30 to U+FE4F 569 570 // Small Form Variants 571 // Range: U+FE50 to U+FE6F 572 573 // Arabic Presentation Forms-B 574 // Range: U+FE70 to U+FEFF 575 576 // Halfwidth and Fullwidth Forms 577 // Range: U+FF00 to U+FFEF 578 579 if ( c >= 0xFF21 && c <= 0xFF3A ) { 580 u[0] = c; 581 u[1] = c + 32; 582 return u; 583 } 584 585 if ( c >= 0xFF41 && c <= 0xFF5A ) { 586 u[0] = c - 32; 587 u[1] = c; 588 return u; 589 } 590 591 // Specials 592 // Range: U+FFF0 to U+FFFF 593 594 return u; 595 } 596 597 function DecimalToHexString( n ) { 598 n = Number( n ); 599 var h = "0x"; 600 601 for ( var i = 3; i >= 0; i-- ) { 602 if ( n >= Math.pow(16, i) ){ 603 var t = Math.floor( n / Math.pow(16, i)); 604 n -= t * Math.pow(16, i); 605 if ( t >= 10 ) { 606 if ( t == 10 ) { 607 h += "A"; 608 } 609 if ( t == 11 ) { 610 h += "B"; 611 } 612 if ( t == 12 ) { 613 h += "C"; 614 } 615 if ( t == 13 ) { 616 h += "D"; 617 } 618 if ( t == 14 ) { 619 h += "E"; 620 } 621 if ( t == 15 ) { 622 h += "F"; 623 } 624 } else { 625 h += String( t ); 626 } 627 } else { 628 h += "0"; 629 } 630 } 631 632 return h; 633 }