michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: /** michael@0: File Name: 15.1.2.2-1.js michael@0: ECMA Section: 15.1.2.2 Function properties of the global object michael@0: parseInt( string, radix ) michael@0: michael@0: Description: michael@0: michael@0: The parseInt function produces an integer value dictated by intepretation michael@0: of the contents of the string argument according to the specified radix. michael@0: michael@0: When the parseInt function is called, the following steps are taken: michael@0: michael@0: 1. Call ToString(string). michael@0: 2. Compute a substring of Result(1) consisting of the leftmost character michael@0: that is not a StrWhiteSpaceChar and all characters to the right of michael@0: that character. (In other words, remove leading whitespace.) michael@0: 3. Let sign be 1. michael@0: 4. If Result(2) is not empty and the first character of Result(2) is a michael@0: minus sign -, let sign be -1. michael@0: 5. If Result(2) is not empty and the first character of Result(2) is a michael@0: plus sign + or a minus sign -, then Result(5) is the substring of michael@0: Result(2) produced by removing the first character; otherwise, Result(5) michael@0: is Result(2). michael@0: 6. If the radix argument is not supplied, go to step 12. michael@0: 7. Call ToInt32(radix). michael@0: 8. If Result(7) is zero, go to step 12; otherwise, if Result(7) < 2 or michael@0: Result(7) > 36, return NaN. michael@0: 9. Let R be Result(7). michael@0: 10. If R = 16 and the length of Result(5) is at least 2 and the first two michael@0: characters of Result(5) are either "0x" or "0X", let S be the substring michael@0: of Result(5) consisting of all but the first two characters; otherwise, michael@0: let S be Result(5). michael@0: 11. Go to step 22. michael@0: 12. If Result(5) is empty or the first character of Result(5) is not 0, michael@0: go to step 20. michael@0: 13. If the length of Result(5) is at least 2 and the second character of michael@0: Result(5) is x or X, go to step 17. michael@0: 14. Let R be 8. michael@0: 15. Let S be Result(5). michael@0: 16. Go to step 22. michael@0: 17. Let R be 16. michael@0: 18. Let S be the substring of Result(5) consisting of all but the first michael@0: two characters. michael@0: 19. Go to step 22. michael@0: 20. Let R be 10. michael@0: 21. Let S be Result(5). michael@0: 22. If S contains any character that is not a radix-R digit, then let Z be michael@0: the substring of S consisting of all characters to the left of the michael@0: leftmost such character; otherwise, let Z be S. michael@0: 23. If Z is empty, return NaN. michael@0: 24. Compute the mathematical integer value that is represented by Z in michael@0: radix-R notation. (But if R is 10 and Z contains more than 20 michael@0: significant digits, every digit after the 20th may be replaced by a 0 michael@0: digit, at the option of the implementation; and if R is not 2, 4, 8, michael@0: 10, 16, or 32, then Result(24) may be an implementation-dependent michael@0: approximation to the mathematical integer value that is represented michael@0: by Z in radix-R notation.) michael@0: 25. Compute the number value for Result(24). michael@0: 26. Return sign Result(25). michael@0: michael@0: Note that parseInt may interpret only a leading portion of the string as michael@0: an integer value; it ignores any characters that cannot be interpreted as michael@0: part of the notation of an integer, and no indication is given that any michael@0: such characters were ignored. michael@0: michael@0: Author: christine@netscape.com michael@0: Date: 28 october 1997 michael@0: michael@0: */ michael@0: var SECTION = "15.1.2.2-1"; michael@0: var VERSION = "ECMA_1"; michael@0: var TITLE = "parseInt(string, radix)"; michael@0: var BUGNUMBER = "none"; michael@0: michael@0: startTest(); michael@0: michael@0: writeHeaderToLog( SECTION + " "+ TITLE); michael@0: michael@0: var HEX_STRING = "0x0"; michael@0: var HEX_VALUE = 0; michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt.length", michael@0: 2, michael@0: parseInt.length ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt.length = 0; parseInt.length", michael@0: 2, michael@0: eval("parseInt.length = 0; parseInt.length") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "var PROPS=''; for ( var p in parseInt ) { PROPS += p; }; PROPS", "", michael@0: eval("var PROPS=''; for ( var p in parseInt ) { PROPS += p; }; PROPS") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "delete parseInt.length", michael@0: false, michael@0: delete parseInt.length ); michael@0: michael@0: new TestCase( SECTION, michael@0: "delete parseInt.length; parseInt.length", michael@0: 2, michael@0: eval("delete parseInt.length; parseInt.length") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt.length = null; parseInt.length", michael@0: 2, michael@0: eval("parseInt.length = null; parseInt.length") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt()", michael@0: NaN, michael@0: parseInt() ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt('')", michael@0: NaN, michael@0: parseInt("") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt('','')", michael@0: NaN, michael@0: parseInt("","") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt(\" 0xabcdef ", michael@0: 11259375, michael@0: parseInt( " 0xabcdef " )); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt(\" 0XABCDEF ", michael@0: 11259375, michael@0: parseInt( " 0XABCDEF " ) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( 0xabcdef )", michael@0: 11259375, michael@0: parseInt( "0xabcdef") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( 0XABCDEF )", michael@0: 11259375, michael@0: parseInt( "0XABCDEF") ); michael@0: michael@0: for ( HEX_STRING = "0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"')", HEX_VALUE, parseInt(HEX_STRING) ); michael@0: HEX_VALUE += Math.pow(16,POWER)*15; michael@0: } michael@0: for ( HEX_STRING = "0X0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"')", HEX_VALUE, parseInt(HEX_STRING) ); michael@0: HEX_VALUE += Math.pow(16,POWER)*15; michael@0: } michael@0: for ( HEX_STRING = "0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"', 16)", HEX_VALUE, parseInt(HEX_STRING,16) ); michael@0: HEX_VALUE += Math.pow(16,POWER)*15; michael@0: } michael@0: for ( HEX_STRING = "0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"', 16)", HEX_VALUE, parseInt(HEX_STRING,16) ); michael@0: HEX_VALUE += Math.pow(16,POWER)*15; michael@0: } michael@0: for ( HEX_STRING = "0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"', null)", HEX_VALUE, parseInt(HEX_STRING,null) ); michael@0: HEX_VALUE += Math.pow(16,POWER)*15; michael@0: } michael@0: for ( HEX_STRING = "0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"', void 0)", HEX_VALUE, parseInt(HEX_STRING, void 0) ); michael@0: HEX_VALUE += Math.pow(16,POWER)*15; michael@0: } michael@0: michael@0: // a few tests with spaces michael@0: michael@0: for ( var space = " ", HEX_STRING = "0x0", HEX_VALUE = 0, POWER = 0; michael@0: POWER < 15; michael@0: POWER++, HEX_STRING = HEX_STRING +"f", space += " ") michael@0: { michael@0: new TestCase( SECTION, "parseInt('"+space+HEX_STRING+space+"', void 0)", HEX_VALUE, parseInt(space+HEX_STRING+space, void 0) ); michael@0: HEX_VALUE += Math.pow(16,POWER)*15; michael@0: } michael@0: michael@0: new TestCase(SECTION, "parseInt(BOM + '123', 10)", 123, parseInt("\uFEFF" + "123", 10)); michael@0: michael@0: // a few tests with negative numbers michael@0: for ( HEX_STRING = "-0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"')", HEX_VALUE, parseInt(HEX_STRING) ); michael@0: HEX_VALUE -= Math.pow(16,POWER)*15; michael@0: } michael@0: michael@0: // we should stop parsing when we get to a value that is not a numeric literal for the type we expect michael@0: michael@0: for ( HEX_STRING = "0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"g', 16)", HEX_VALUE, parseInt(HEX_STRING+"g",16) ); michael@0: HEX_VALUE += Math.pow(16,POWER)*15; michael@0: } michael@0: for ( HEX_STRING = "0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"G', 16)", HEX_VALUE, parseInt(HEX_STRING+"G",16) ); michael@0: HEX_VALUE += Math.pow(16,POWER)*15; michael@0: } michael@0: michael@0: for ( HEX_STRING = "-0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"')", HEX_VALUE, parseInt(HEX_STRING) ); michael@0: HEX_VALUE -= Math.pow(16,POWER)*15; michael@0: } michael@0: for ( HEX_STRING = "-0X0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"')", HEX_VALUE, parseInt(HEX_STRING) ); michael@0: HEX_VALUE -= Math.pow(16,POWER)*15; michael@0: } michael@0: for ( HEX_STRING = "-0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"', 16)", HEX_VALUE, parseInt(HEX_STRING,16) ); michael@0: HEX_VALUE -= Math.pow(16,POWER)*15; michael@0: } michael@0: for ( HEX_STRING = "-0x0", HEX_VALUE = 0, POWER = 0; POWER < 15; POWER++, HEX_STRING = HEX_STRING +"f" ) { michael@0: new TestCase( SECTION, "parseInt('"+HEX_STRING+"', 16)", HEX_VALUE, parseInt(HEX_STRING,16) ); michael@0: HEX_VALUE -= Math.pow(16,POWER)*15; michael@0: } michael@0: michael@0: // Numbers that start with 0 and do not provide a radix should use 10 as radix michael@0: // per ES5, not octal (as it was in ES3). michael@0: michael@0: var OCT_STRING = "0"; michael@0: var OCT_VALUE = 0; michael@0: michael@0: for ( OCT_STRING = "0", OCT_VALUE = 0, POWER = 0; POWER < 15; POWER++, OCT_STRING = OCT_STRING +"7" ) { michael@0: new TestCase( SECTION, "parseInt('"+OCT_STRING+"')", OCT_VALUE, parseInt(OCT_STRING) ); michael@0: OCT_VALUE += Math.pow(10,POWER)*7; michael@0: } michael@0: michael@0: for ( OCT_STRING = "-0", OCT_VALUE = 0, POWER = 0; POWER < 15; POWER++, OCT_STRING = OCT_STRING +"7" ) { michael@0: new TestCase( SECTION, "parseInt('"+OCT_STRING+"')", OCT_VALUE, parseInt(OCT_STRING) ); michael@0: OCT_VALUE -= Math.pow(10,POWER)*7; michael@0: } michael@0: michael@0: // should get octal-based results if we provid the radix of 8 (or 010) michael@0: michael@0: for ( OCT_STRING = "0", OCT_VALUE = 0, POWER = 0; POWER < 15; POWER++, OCT_STRING = OCT_STRING +"7" ) { michael@0: new TestCase( SECTION, "parseInt('"+OCT_STRING+"', 8)", OCT_VALUE, parseInt(OCT_STRING,8) ); michael@0: OCT_VALUE += Math.pow(8,POWER)*7; michael@0: } michael@0: for ( OCT_STRING = "-0", OCT_VALUE = 0, POWER = 0; POWER < 15; POWER++, OCT_STRING = OCT_STRING +"7" ) { michael@0: new TestCase( SECTION, "parseInt('"+OCT_STRING+"', 010)", OCT_VALUE, parseInt(OCT_STRING,010) ); michael@0: OCT_VALUE -= Math.pow(8,POWER)*7; michael@0: } michael@0: michael@0: // we shall stop parsing digits when we get one that isn't a numeric literal of the type we think michael@0: // it should be. michael@0: for ( OCT_STRING = "0", OCT_VALUE = 0, POWER = 0; POWER < 15; POWER++, OCT_STRING = OCT_STRING +"7" ) { michael@0: new TestCase( SECTION, "parseInt('"+OCT_STRING+"8', 8)", OCT_VALUE, parseInt(OCT_STRING+"8",8) ); michael@0: OCT_VALUE += Math.pow(8,POWER)*7; michael@0: } michael@0: for ( OCT_STRING = "-0", OCT_VALUE = 0, POWER = 0; POWER < 15; POWER++, OCT_STRING = OCT_STRING +"7" ) { michael@0: new TestCase( SECTION, "parseInt('"+OCT_STRING+"8', 010)", OCT_VALUE, parseInt(OCT_STRING+"8",010) ); michael@0: OCT_VALUE -= Math.pow(8,POWER)*7; michael@0: } michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '0x' )", michael@0: NaN, michael@0: parseInt("0x") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '0X' )", michael@0: NaN, michael@0: parseInt("0X") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '11111111112222222222' )", michael@0: 11111111112222222222, michael@0: parseInt("11111111112222222222") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '111111111122222222223' )", michael@0: 111111111122222222220, michael@0: parseInt("111111111122222222223") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '11111111112222222222',10 )", michael@0: 11111111112222222222, michael@0: parseInt("11111111112222222222",10) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '111111111122222222223',10 )", michael@0: 111111111122222222220, michael@0: parseInt("111111111122222222223",10) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', -1 )", michael@0: Number.NaN, michael@0: parseInt("01234567890",-1) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 0 )", michael@0: 1234567890, michael@0: parseInt("01234567890", 0) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 1 )", michael@0: Number.NaN, michael@0: parseInt("01234567890",1) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 2 )", michael@0: 1, michael@0: parseInt("01234567890",2) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 3 )", michael@0: 5, michael@0: parseInt("01234567890",3) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 4 )", michael@0: 27, michael@0: parseInt("01234567890",4) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 5 )", michael@0: 194, michael@0: parseInt("01234567890",5) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 6 )", michael@0: 1865, michael@0: parseInt("01234567890",6) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 7 )", michael@0: 22875, michael@0: parseInt("01234567890",7) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 8 )", michael@0: 342391, michael@0: parseInt("01234567890",8) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 9 )", michael@0: 6053444, michael@0: parseInt("01234567890",9) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '01234567890', 10 )", michael@0: 1234567890, michael@0: parseInt("01234567890",10) ); michael@0: michael@0: // need more test cases with hex radix michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '1234567890', '0xa')", michael@0: 1234567890, michael@0: parseInt("1234567890","0xa") ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '012345', 11 )", michael@0: 17715, michael@0: parseInt("012345",11) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '012345', 35 )", michael@0: 1590195, michael@0: parseInt("012345",35) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '012345', 36 )", michael@0: 1776965, michael@0: parseInt("012345",36) ); michael@0: michael@0: new TestCase( SECTION, michael@0: "parseInt( '012345', 37 )", michael@0: Number.NaN, michael@0: parseInt("012345",37) ); michael@0: michael@0: test();