scope-001.js revision cad810f21b803229eb11403f9209855525a25d57
1/*
2* The contents of this file are subject to the Netscape Public
3* License Version 1.1 (the "License"); you may not use this file
4* except in compliance with the License. You may obtain a copy of
5* the License at http://www.mozilla.org/NPL/
6*
7* Software distributed under the License is distributed on an "AS
8* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9* implied. See the License for the specific language governing
10* rights and limitations under the License.
11*
12* The Original Code is mozilla.org code.
13*
14* The Initial Developer of the Original Code is Netscape
15* Communications Corporation.  Portions created by Netscape are
16* Copyright (C) 1998 Netscape Communications Corporation. All
17* Rights Reserved.
18*
19* Contributor(s): pschwartau@netscape.com, rogerl@netscape.com
20* Date: 28 May 2001
21*
22* SUMMARY:  Functions are scoped statically, not dynamically
23*
24* See ECMA Section 10.1.4 Scope Chain and Identifier Resolution
25* (This section defines the scope chain of an execution context)
26*
27* See ECMA Section 12.10 The with Statement
28*
29* See ECMA Section 13 Function Definition
30* (This section defines the scope chain of a function object as that
31*  of the running execution context when the function was declared)
32*/
33//-------------------------------------------------------------------------------------------------
34var UBound = 0;
35var bug = '(none)';
36var summary = 'Testing that functions are scoped statically, not dynamically';
37var self = this;  // capture a reference to the global object
38var status = '';
39var statusitems = [ ];
40var actual = '';
41var actualvalues = [ ];
42var expect= '';
43var expectedvalues = [ ];
44
45/*
46 * In this section the expected value is 1, not 2.
47 *
48 * Why? f captures its scope chain from when it's declared, and imposes that chain
49 * when it's executed. In other words, f's scope chain is from when it was compiled.
50 * Since f is a top-level function, this is the global object only. Hence 'a' resolves to 1.
51 */
52status = 'Section A of test';
53var a = 1;
54function f()
55{
56  return a;
57}
58var obj = {a:2};
59with (obj)
60{
61  actual = f();
62}
63expect = 1;
64addThis();
65
66
67/*
68 * In this section the expected value is 2, not 1. That is because here
69 * f's associated scope chain now includes 'obj' before the global object.
70 */
71status = 'Section B of test';
72var a = 1;
73var obj = {a:2};
74with (obj)
75{
76  function f()
77  {
78    return a;
79  }
80  actual = f();
81}
82// Mozilla result, which contradicts IE and the ECMA spec: expect = 2;
83expect = 1;
84addThis();
85
86
87/*
88 * Like Section B , except that we call f outside the with block.
89 * By the principles explained above, we still expect 2 -
90 */
91status = 'Section C of test';
92var a = 1;
93var obj = {a:2};
94with (obj)
95{
96  function f()
97  {
98    return a;
99  }
100}
101actual = f();
102// Mozilla result, which contradicts IE and the ECMA spec: expect = 2;
103expect = 1;
104addThis();
105
106
107/*
108 * Like Section C, but with one more level of indirection -
109 */
110status = 'Section D of test';
111var a = 1;
112var obj = {a:2, obj:{a:3}};
113with (obj)
114{
115  with (obj)
116  {
117    function f()
118    {
119      return a;
120    }
121  }
122}
123actual = f();
124// Mozilla result, which contradicts IE and the ECMA spec: expect = 3;
125expect = 1;
126addThis();
127
128
129/*
130 * Like Section C, but here we actually delete obj before calling f.
131 * We still expect 2 -
132 */
133status = 'Section E of test';
134var a = 1;
135var obj = {a:2};
136with (obj)
137{
138  function f()
139  {
140    return a;
141  }
142}
143delete obj;
144actual = f();
145// Mozilla result, which contradicts IE and the ECMA spec: expect = 2;
146expect = 1;
147addThis();
148
149
150/*
151 * Like Section E. Here we redefine obj and call f under with (obj) -
152 * We still expect 2 -
153 */
154status = 'Section F of test';
155var a = 1;
156var obj = {a:2};
157with (obj)
158{
159  function f()
160  {
161    return a;
162  }
163}
164delete obj;
165var obj = {a:3};
166with (obj)
167{
168  actual = f();
169}
170// Mozilla result, which contradicts IE and the ECMA spec: expect = 2;  // NOT 3 !!!
171expect = 1;
172addThis();
173
174
175/*
176 * Explicitly verify that f exists at global level, even though
177 * it was defined under the with(obj) block -
178 */
179status = 'Section G of test';
180var a = 1;
181var obj = {a:2};
182with (obj)
183{
184  function f()
185  {
186    return a;
187  }
188}
189actual = String([obj.hasOwnProperty('f'), self.hasOwnProperty('f')]);
190expect = String([false, true]);
191addThis();
192
193
194/*
195 * Explicitly verify that f exists at global level, even though
196 * it was defined under the with(obj) block -
197 */
198status = 'Section H of test';
199var a = 1;
200var obj = {a:2};
201with (obj)
202{
203  function f()
204  {
205    return a;
206  }
207}
208actual = String(['f' in obj, 'f' in self]);
209expect = String([false, true]);
210addThis();
211
212
213
214//-------------------------------------------------------------------------------------------------
215test();
216//-------------------------------------------------------------------------------------------------
217
218
219function addThis()
220{
221  statusitems[UBound] = status;
222  actualvalues[UBound] = actual;
223  expectedvalues[UBound] = expect;
224  UBound++;
225  resetTestVars();
226}
227
228
229function resetTestVars()
230{
231  delete a;
232  delete obj;
233  delete f;
234}
235
236
237function test()
238{
239  enterFunc ('test');
240  printBugNumber (bug);
241  printStatus (summary);
242
243  for (var i = 0; i < UBound; i++)
244  {
245    reportCompare(expectedvalues[i], actualvalues[i], statusitems[i]);
246  }
247
248  exitFunc ('test');
249}
250