|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 * |
|
8 * Date: 15 July 2002 |
|
9 * SUMMARY: Testing functions with double-byte names |
|
10 * See http://bugzilla.mozilla.org/show_bug.cgi?id=58274 |
|
11 * |
|
12 * Here is a sample of the problem: |
|
13 * |
|
14 * js> function f\u02B1 () {} |
|
15 * |
|
16 * js> f\u02B1.toSource(); |
|
17 * function f¦() {} |
|
18 * |
|
19 * js> f\u02B1.toSource().toSource(); |
|
20 * (new String("function f\xB1() {}")) |
|
21 * |
|
22 * |
|
23 * See how the high-byte information (the 02) has been lost? |
|
24 * The same thing was happening with the toString() method: |
|
25 * |
|
26 * js> f\u02B1.toString(); |
|
27 * |
|
28 * function f¦() { |
|
29 * } |
|
30 * |
|
31 * js> f\u02B1.toString().toSource(); |
|
32 * (new String("\nfunction f\xB1() {\n}\n")) |
|
33 * |
|
34 */ |
|
35 //----------------------------------------------------------------------------- |
|
36 var UBound = 0; |
|
37 var BUGNUMBER = 58274; |
|
38 var summary = 'Testing functions with double-byte names'; |
|
39 var ERR = 'UNEXPECTED ERROR! \n'; |
|
40 var ERR_MALFORMED_NAME = ERR + 'Could not find function name in: \n\n'; |
|
41 var status = ''; |
|
42 var statusitems = []; |
|
43 var actual = ''; |
|
44 var actualvalues = []; |
|
45 var expect= ''; |
|
46 var expectedvalues = []; |
|
47 var sEval; |
|
48 var sName; |
|
49 |
|
50 |
|
51 sEval = "function f\u02B2() {return 42;}"; |
|
52 eval(sEval); |
|
53 sName = getFunctionName(f\u02B2); |
|
54 |
|
55 // Test function call - |
|
56 status = inSection(1); |
|
57 actual = f\u02B2(); |
|
58 expect = 42; |
|
59 addThis(); |
|
60 |
|
61 // Test both characters of function name - |
|
62 status = inSection(2); |
|
63 actual = sName[0]; |
|
64 expect = sEval[9]; |
|
65 addThis(); |
|
66 |
|
67 status = inSection(3); |
|
68 actual = sName[1]; |
|
69 expect = sEval[10]; |
|
70 addThis(); |
|
71 |
|
72 |
|
73 |
|
74 sEval = "function f\u02B2\u0AAA () {return 84;}"; |
|
75 eval(sEval); |
|
76 sName = getFunctionName(f\u02B2\u0AAA); |
|
77 |
|
78 // Test function call - |
|
79 status = inSection(4); |
|
80 actual = f\u02B2\u0AAA(); |
|
81 expect = 84; |
|
82 addThis(); |
|
83 |
|
84 // Test all three characters of function name - |
|
85 status = inSection(5); |
|
86 actual = sName[0]; |
|
87 expect = sEval[9]; |
|
88 addThis(); |
|
89 |
|
90 status = inSection(6); |
|
91 actual = sName[1]; |
|
92 expect = sEval[10]; |
|
93 addThis(); |
|
94 |
|
95 status = inSection(7); |
|
96 actual = sName[2]; |
|
97 expect = sEval[11]; |
|
98 addThis(); |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 //----------------------------------------------------------------------------- |
|
104 test(); |
|
105 //----------------------------------------------------------------------------- |
|
106 |
|
107 |
|
108 |
|
109 /* |
|
110 * Goal: test that f.toString() contains the proper function name. |
|
111 * |
|
112 * Note, however, f.toString() is implementation-independent. For example, |
|
113 * it may begin with '\nfunction' instead of 'function'. Therefore we use |
|
114 * a regexp to make sure we extract the name properly. |
|
115 * |
|
116 * Here we assume that f has been defined by means of a function statement, |
|
117 * and not a function expression (where it wouldn't have to have a name). |
|
118 * |
|
119 * Rhino uses a Unicode representation for f.toString(); whereas |
|
120 * SpiderMonkey uses an ASCII representation, putting escape sequences |
|
121 * for non-ASCII characters. For example, if a function is called f\u02B1, |
|
122 * then in Rhino the toString() method will present a 2-character Unicode |
|
123 * string for its name, whereas SpiderMonkey will present a 7-character |
|
124 * ASCII string for its name: the string literal 'f\u02B1'. |
|
125 * |
|
126 * So we force the lexer to condense the string before using it. |
|
127 * This will give uniform results in Rhino and SpiderMonkey. |
|
128 */ |
|
129 function getFunctionName(f) |
|
130 { |
|
131 var s = condenseStr(f.toString()); |
|
132 var re = /\s*function\s+(\S+)\s*\(/; |
|
133 var arr = s.match(re); |
|
134 |
|
135 if (!(arr && arr[1])) |
|
136 return ERR_MALFORMED_NAME + s; |
|
137 return arr[1]; |
|
138 } |
|
139 |
|
140 |
|
141 /* |
|
142 * This function is the opposite of functions like escape(), which take |
|
143 * Unicode characters and return escape sequences for them. Here, we force |
|
144 * the lexer to turn escape sequences back into single characters. |
|
145 * |
|
146 * Note we can't simply do |eval(str)|, since in practice |str| will be an |
|
147 * identifier somewhere in the program (e.g. a function name); thus |eval(str)| |
|
148 * would return the object that the identifier represents: not what we want. |
|
149 * |
|
150 * So we surround |str| lexicographically with quotes to force the lexer to |
|
151 * evaluate it as a string. Have to strip out any linefeeds first, however - |
|
152 */ |
|
153 function condenseStr(str) |
|
154 { |
|
155 /* |
|
156 * You won't be able to do the next step if |str| has |
|
157 * any carriage returns or linefeeds in it. For example: |
|
158 * |
|
159 * js> eval("'" + '\nHello' + "'"); |
|
160 * 1: SyntaxError: unterminated string literal: |
|
161 * 1: ' |
|
162 * 1: ^ |
|
163 * |
|
164 * So replace them with the empty string - |
|
165 */ |
|
166 str = str.replace(/[\r\n]/g, '') |
|
167 return eval("'" + str + "'"); |
|
168 } |
|
169 |
|
170 |
|
171 function addThis() |
|
172 { |
|
173 statusitems[UBound] = status; |
|
174 actualvalues[UBound] = actual; |
|
175 expectedvalues[UBound] = expect; |
|
176 UBound++; |
|
177 } |
|
178 |
|
179 |
|
180 function test() |
|
181 { |
|
182 enterFunc('test'); |
|
183 printBugNumber(BUGNUMBER); |
|
184 printStatus(summary); |
|
185 |
|
186 for (var i=0; i<UBound; i++) |
|
187 { |
|
188 reportCompare(expectedvalues[i], actualvalues[i], statusitems[i]); |
|
189 } |
|
190 |
|
191 exitFunc ('test'); |
|
192 } |