1/* ***** BEGIN LICENSE BLOCK *****
2* Version: NPL 1.1/GPL 2.0/LGPL 2.1
3*
4* The contents of this file are subject to the Netscape Public License
5* Version 1.1 (the "License"); you may not use this file except in
6* compliance with the License. You may obtain a copy of the License at
7* http://www.mozilla.org/NPL/
8*
9* Software distributed under the License is distributed on an "AS IS" basis,
10* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11* for the specific language governing rights and limitations under the
12* License.
13*
14* The Original Code is JavaScript Engine testing utilities.
15*
16* The Initial Developer of the Original Code is Netscape Communications Corp.
17* Portions created by the Initial Developer are Copyright (C) 2002
18* the Initial Developer. All Rights Reserved.
19*
20* Contributor(s): rogerl@netscape.com, pschwartau@netscape.com
21*
22* Alternatively, the contents of this file may be used under the terms of
23* either the GNU General Public License Version 2 or later (the "GPL"), or
24* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25* in which case the provisions of the GPL or the LGPL are applicable instead
26* of those above. If you wish to allow use of your version of this file only
27* under the terms of either the GPL or the LGPL, and not to allow others to
28* use your version of this file under the terms of the NPL, indicate your
29* decision by deleting the provisions above and replace them with the notice
30* and other provisions required by the GPL or the LGPL. If you do not delete
31* the provisions above, a recipient may use your version of this file under
32* the terms of any one of the NPL, the GPL or the LGPL.
33*
34* ***** END LICENSE BLOCK *****
35*
36*
37* Date:    15 July 2002
38* SUMMARY: Testing functions with double-byte names
39* See http://bugzilla.mozilla.org/show_bug.cgi?id=58274
40*
41* Here is a sample of the problem:
42*
43*    js> function f\u02B1 () {}
44*
45*    js> f\u02B1.toSource();
46*    function f�() {}
47*
48*    js> f\u02B1.toSource().toSource();
49*    (new String("function f\xB1() {}"))
50*
51*
52* See how the high-byte information (the 02) has been lost?
53* The same thing was happening with the toString() method:
54*
55*    js> f\u02B1.toString();
56*
57*    function f�() {
58*    }
59*
60*    js> f\u02B1.toString().toSource();
61*    (new String("\nfunction f\xB1() {\n}\n"))
62*
63*/
64//-----------------------------------------------------------------------------
65var UBound = 0;
66var bug = 58274;
67var summary = 'Testing functions with double-byte names';
68var ERR = 'UNEXPECTED ERROR! \n';
69var ERR_MALFORMED_NAME = ERR + 'Could not find function name in: \n\n';
70var status = '';
71var statusitems = [];
72var actual = '';
73var actualvalues = [];
74var expect= '';
75var expectedvalues = [];
76var sEval;
77var sName;
78
79
80sEval = "function f\u02B2() {return 42;}";
81eval(sEval);
82sName = getFunctionName(f\u02B2);
83
84// Test function call -
85status = inSection(1);
86actual = f\u02B2();
87expect = 42;
88addThis();
89
90// Test both characters of function name -
91status = inSection(2);
92actual = sName[0];
93expect = sEval[9];
94addThis();
95
96status = inSection(3);
97actual = sName[1];
98expect = sEval[10];
99addThis();
100
101
102
103sEval = "function f\u02B2\u0AAA () {return 84;}";
104eval(sEval);
105sName = getFunctionName(f\u02B2\u0AAA);
106
107// Test function call -
108status = inSection(4);
109actual = f\u02B2\u0AAA();
110expect = 84;
111addThis();
112
113// Test all three characters of function name -
114status = inSection(5);
115actual = sName[0];
116expect = sEval[9];
117addThis();
118
119status = inSection(6);
120actual = sName[1];
121expect = sEval[10];
122addThis();
123
124status = inSection(7);
125actual = sName[2];
126expect = sEval[11];
127addThis();
128
129
130
131
132//-----------------------------------------------------------------------------
133test();
134//-----------------------------------------------------------------------------
135
136
137
138/*
139 * Goal: test that f.toString() contains the proper function name.
140 *
141 * Note, however, f.toString() is implementation-independent. For example,
142 * it may begin with '\nfunction' instead of 'function'. Therefore we use
143 * a regexp to make sure we extract the name properly.
144 *
145 * Here we assume that f has been defined by means of a function statement,
146 * and not a function expression (where it wouldn't have to have a name).
147 *
148 * Rhino uses a Unicode representation for f.toString(); whereas
149 * SpiderMonkey uses an ASCII representation, putting escape sequences
150 * for non-ASCII characters. For example, if a function is called f\u02B1,
151 * then in Rhino the toString() method will present a 2-character Unicode
152 * string for its name, whereas SpiderMonkey will present a 7-character
153 * ASCII string for its name: the string literal 'f\u02B1'.
154 *
155 * So we force the lexer to condense the string before using it.
156 * This will give uniform results in Rhino and SpiderMonkey.
157 */
158function getFunctionName(f)
159{
160  var s = condenseStr(f.toString());
161  var re = /\s*function\s+(\S+)\s*\(/;
162  var arr = s.match(re);
163
164  if (!(arr && arr[1]))
165    return ERR_MALFORMED_NAME + s;
166  return arr[1];
167}
168
169
170/*
171 * This function is the opposite of functions like escape(), which take
172 * Unicode characters and return escape sequences for them. Here, we force
173 * the lexer to turn escape sequences back into single characters.
174 *
175 * Note we can't simply do |eval(str)|, since in practice |str| will be an
176 * identifier somewhere in the program (e.g. a function name); thus |eval(str)|
177 * would return the object that the identifier represents: not what we want.
178 *
179 * So we surround |str| lexicographically with quotes to force the lexer to
180 * evaluate it as a string. Have to strip out any linefeeds first, however -
181 */
182function condenseStr(str)
183{
184  /*
185   * You won't be able to do the next step if |str| has
186   * any carriage returns or linefeeds in it. For example:
187   *
188   *  js> eval("'" + '\nHello' + "'");
189   *  1: SyntaxError: unterminated string literal:
190   *  1: '
191   *  1: ^
192   *
193   * So replace them with the empty string -
194   */
195  str = str.replace(/[\r\n]/g, '')
196  return eval("'" + str + "'");
197}
198
199
200function addThis()
201{
202  statusitems[UBound] = status;
203  actualvalues[UBound] = actual;
204  expectedvalues[UBound] = expect;
205  UBound++;
206}
207
208
209function test()
210{
211  enterFunc('test');
212  printBugNumber(bug);
213  printStatus(summary);
214
215  for (var i=0; i<UBound; i++)
216  {
217    reportCompare(expectedvalues[i], actualvalues[i], statusitems[i]);
218  }
219
220  exitFunc ('test');
221}
222