1 description("Make sure prototypes are set up using the window a property came from, instead of the lexical global object.")
3 var subframe = document.createElement("iframe");
4 document.body.appendChild(subframe);
5 var inner = subframe.contentWindow; // Call it "inner" to make shouldBe output shorter
7 var skippedProperties = [
8 // These reach outside the frame:
9 "parent", "top", "opener", "frameElement",
10 // These are defined by DumpRenderTree
11 "GCController", "layoutTestController",
12 "objCController", "textInputController", "navigationController",
13 "eventSender", "objCPlugin", "objCPluginFunction",
14 "appleScriptController", "plainText", "accessibilityController",
16 // Skip our test property
18 // Ignore fooConstructor.prototype, fooInstance.__proto__ is more likely to fail.
20 // Skip Geolocation until it is supported on most platforms.
22 // Skip webkitURL until it is supported on most platforms.
26 var skippedPropertiesSet = {};
27 for (var i = 0; i < skippedProperties.length; i++)
28 skippedPropertiesSet[skippedProperties[i]] = true;
30 // Stash a property on the prototypes.
31 window.Object.prototype.isInner = false;
32 inner.Object.prototype.isInner = true;
34 function propertiesOnObject(object) {
36 for (property in object) {
37 if (skippedPropertiesSet[property])
39 properties.push(property);
44 var resultsByType = {};
46 function classNameForObject(object)
48 // call will use the global object if passed null or undefined, so special case those:
51 var result = Object.prototype.toString.call(object);
52 // remove '[object ' and ']'
53 return result.split(' ')[1].split(']')[0];
56 function constructorNamesForWindow(globalObject)
59 for (var property in globalObject) {
60 var value = inner[property];
63 var type = classNameForObject(value);
64 // Ignore these properties because they do not exist in all implementations. They will be tested separately
65 if (type == "WebGLRenderingContextConstructor" ||
66 type == "WebGLActiveInfoConstructor" ||
67 type == "WebGLBufferConstructor" ||
68 type == "WebGLFramebufferConstructor" ||
69 type == "WebGLProgramConstructor" ||
70 type == "WebGLRenderbufferConstructor" ||
71 type == "WebGLShaderConstructor" ||
72 type == "WebGLTextureConstructor" ||
73 type == "WebGLUniformLocationConstructor" ||
74 type == "ArrayBufferConstructor" ||
75 type == "DataViewConstructor" ||
76 type =="Float32ArrayConstructor" ||
77 type =="Float64ArrayConstructor" ||
78 type =="Int8ArrayConstructor" ||
79 type =="Int16ArrayConstructor" ||
80 type =="Int32ArrayConstructor" ||
81 type =="Uint8ArrayConstructor" ||
82 type =="Uint16ArrayConstructor" ||
83 type =="Uint32ArrayConstructor" ||
84 type == "FileErrorConstructor" ||
85 type == "FileReaderConstructor" ||
86 type == "WebKitBlobBuilderConstructor" ||
87 type == "HTMLProgressElementConstructor")
88 continue; // We ignore WebGLRenderingContext and test it elsewhere, since it is not in all builds
89 if (!type.match('Constructor$'))
93 return propertiesOnObject(namesSet).sort();
96 function makeCrawlObject(value, valuePath)
100 'valuePath' : valuePath
104 function evalToCrawlObject(path)
106 // This allows us to add things to the end of the crawl list
107 // without the early-eval changing the test results.
108 function LazyEvalCrawlObject(path){
109 this.valuePath = path;
112 this.__defineGetter__("value", function(){
114 value = eval(this.valuePath);
119 return new LazyEvalCrawlObject(path);
122 function pushPropertyValuesWithUnseenTypes(toCrawl, parentObject, parentPath)
124 var propertiesToCrawl = propertiesOnObject(parentObject);
125 propertiesToCrawl.push("__proto__");
126 propertiesToCrawl.push("constructor");
128 var parentType = classNameForObject(parentObject);
130 for (var x = 0; x < propertiesToCrawl.length; x++) {
131 var property = propertiesToCrawl[x];
132 var value = parentObject[property];
133 var valuePath = parentPath + "." + property;
134 // CSSStyleDeclaration.item() just returns property names, but we want to crawl the actual CSS values
135 if (parentType == "CSSStyleDeclaration" && parseInt(property)) { // This will skip 0, but that should be OK.
136 valuePath = parentPath + ".getPropertyCSSValue(" + value + ")"
137 value = parentObject.getPropertyCSSValue(value);
139 var type = classNameForObject(value);
142 // We already have other tests which cover window.Foo constructor objects, so skip them.
143 // fooInstance.constructor is the case we want to catch here.
144 if (parentType == "DOMWindow" && type.match("Constructor$") && property != "constructor")
146 if (!resultsByType[type])
147 toCrawl.push(makeCrawlObject(value, valuePath));
151 function crawl(crawlStarts) {
152 while (crawlStarts.length) {
153 var toCrawl = [crawlStarts.shift()];
154 while (toCrawl.length) {
155 var crawlTarget = toCrawl.shift();
156 var object = crawlTarget.value;
157 var type = classNameForObject(object);
158 // If we've already seen an object of this type, and it's not a collection
159 if (resultsByType[type] && !object.item && !object.length) {
160 // Make sure this isn't a new failure before skipping it.
161 if (object.isInner || object.isInner === resultsByType[type].value)
164 if (typeof(object) == "string")
166 if (typeof(object) == "boolean")
168 if (typeof(object) == "number")
171 resultsByType[type] = makeCrawlObject(object.isInner, crawlTarget.valuePath);
172 pushPropertyValuesWithUnseenTypes(toCrawl, object, crawlTarget.valuePath);
177 var tagReplacements = {
186 'tablecaption' : 'caption',
188 'blockquote' : 'quote',
191 function tagNameFromConstructor(constructorName)
193 var expectedObjectName = constructorName.split("Constructor")[0];
194 var match = expectedObjectName.match(/HTML(\w+)Element$/);
197 var tagName = match[1].toLowerCase();
198 if (tagReplacements[tagName])
199 return tagReplacements[tagName];
204 /* Give us more stuff to crawl */
205 /* If you're seeing "Never found..." errors from this test, more should be added here. */
207 var constructorNames = constructorNamesForWindow(inner);
208 for (var x = 0; x < constructorNames.length; x++) {
209 var constructorName = constructorNames[x];
210 var tagName = tagNameFromConstructor(constructorName);
213 if (tagName == 'html')
214 continue; // <html> causes a parse error.
215 htmlToAdd += "<" + tagName + "></" + tagName + ">";
217 htmlToAdd += "<form name='testForm'><input name='testInput'></form><form name='testForm'></form>";
218 htmlToAdd += "<!-- test -->";
219 styleContents = "@charset 'UTF-8';";
220 styleContents += "@import url('dummy.css') print;\n"; // Our parser seems to want this rule first?
221 styleContents += "@variables { Ignored: 2em; }\n"; // For when variables are turned back on
222 styleContents += "@page { margin: 3cm; }\n";
223 styleContents += "@media print { body { margin: 3cm; } }\n"
224 styleContents += "@font-face {font-family:'Times';}\n";
225 styleContents += "ignored {font-family: var(Ignored);}\n"; // a CSSStyleRule
226 styleContents += "@-webkit-keyframes fade { 0% { opacity: 0; } }\n"; // a WebKitCSSKeyframesRule
228 htmlToAdd += "<style id='dummyStyle'>" + styleContents + "</style>";
229 htmlToAdd += "<span id='styledSpan' style='clip: rect(0, 0, 1, 1); content: counter(dummy, square);'></span>";
231 inner.document.body.style.display = "none";
232 inner.document.body.innerHTML = htmlToAdd;
234 var crawlStartPaths = [
235 evalToCrawlObject('inner.document.createElement'),
236 evalToCrawlObject('inner.document.location'), // window.location is tested by other tests, so test document.location in this one.
237 //evalToCrawlObject('inner.testForm'), // Causes many failures
238 evalToCrawlObject('inner.document.forms.testForm'), // NamedNodesCollection has the wrong prototype, test that.
239 evalToCrawlObject('inner'),
240 evalToCrawlObject('inner.document.testForm'),
241 evalToCrawlObject('inner.document.testForm[0].testInput'),
242 evalToCrawlObject('inner.document.getElementsByTagName("canvas")[0].getContext("2d")'), // for CanvasRenderingContext2D
243 evalToCrawlObject('inner.document.getElementsByTagName("canvas")[0].getContext("2d").createPattern(inner.document.getElementsByTagName("img")[0], "")'), // for CanvasRenderingContext2D
244 evalToCrawlObject('inner.document.body.getClientRects()'), // For ClientRectList
245 evalToCrawlObject('inner.document.body.getBoundingClientRect()'), // For ClientRect, getClientRects() returns an empty list for in our test, not sure why.
246 evalToCrawlObject('inner.getComputedStyle(inner.document.body)'),
247 evalToCrawlObject('inner.document.getElementById("dummyStyle").sheet.cssRules'), // For various CSSRule subclasses
248 evalToCrawlObject('inner.document.getElementById("styledSpan").style'),
249 evalToCrawlObject('inner.document.getElementById("styledSpan").style.getPropertyCSSValue("clip").getRectValue()'),
250 evalToCrawlObject('inner.document.getElementById("styledSpan").style.getPropertyCSSValue("content")[0].getCounterValue()'),
251 // Can add more stuff to crawl here.
254 crawl(crawlStartPaths);
255 var sortedTypes = propertiesOnObject(resultsByType).sort();
257 // Run the actual tests
258 for (var x = 0; x < sortedTypes.length; x++) {
259 var type = sortedTypes[x];
260 var result = resultsByType[type];
262 testPassed(type + " from " + result.valuePath);
264 testFailed(type + " from " + result.valuePath);
267 // Add a bunch of fails at the end for stuff we missed in our crawl.
268 for (var x = 0; x < constructorNames.length; x++) {
269 var constructorName = constructorNames[x];
270 var expectedObjectName = constructorName.split("Constructor")[0];
271 if (expectedObjectName.match("Event$"))
272 continue; // Not going to be able to test events with a crawl.
273 if (expectedObjectName.match("Exception$"))
274 continue; // Not going to be able to test exceptions with a crawl.
275 if (expectedObjectName.match("Error$"))
276 continue; // Not going to be able to test errors with a crawl.
277 if (!resultsByType[expectedObjectName])
278 debug("Never found " + expectedObjectName);
281 //document.body.removeChild(subframe);