8976ccfaa2f5477db57ca666907f11c022b9d6ca
[WebKit.git] / LayoutTests / dom / xhtml / level2 / html / selfxhtml.js
1 /*
2 Copyright (c) 2001-2005 World Wide Web Consortium, 
3 (Massachusetts Institute of Technology, European Research Consortium 
4 for Informatics and Mathematics, Keio University). All 
5 Rights Reserved. This work is distributed under the W3C(r) Software License [1] in the 
6 hope that it will be useful, but WITHOUT ANY WARRANTY; without even 
7 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
8
9 [1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
10 */
11
12   function assertSize(descr, expected, actual) {
13     var actualSize;
14     assertNotNull(descr, actual);
15     actualSize = actual.length;
16     assertEquals(descr, expected, actualSize);
17   }
18
19   function assertEqualsAutoCase(context, descr, expected, actual) {
20         if (builder.contentType == "text/html") {
21             if(context == "attribute") {
22                 assertEquals(descr, expected.toLowerCase(), actual.toLowerCase());
23             } else {
24                 assertEquals(descr, expected.toUpperCase(), actual);
25             }
26         } else {
27                 assertEquals(descr, expected, actual); 
28         }
29   }
30   
31
32   function assertEqualsCollectionAutoCase(context, descr, expected, actual) {
33     //
34     //  if they aren't the same size, they aren't equal
35     assertEquals(descr, expected.length, actual.length);
36     
37     //
38     //  if there length is the same, then every entry in the expected list
39     //     must appear once and only once in the actual list
40     var expectedLen = expected.length;
41     var expectedValue;
42     var actualLen = actual.length;
43     var i;
44     var j;
45     var matches;
46     for(i = 0; i < expectedLen; i++) {
47         matches = 0;
48         expectedValue = expected[i];
49         for(j = 0; j < actualLen; j++) {
50                 if (builder.contentType == "text/html") {
51                         if (context == "attribute") {
52                                 if (expectedValue.toLowerCase() == actual[j].toLowerCase()) {
53                                         matches++;
54                                 }
55                         } else {
56                                 if (expectedValue.toUpperCase() == actual[j]) {
57                                         matches++;
58                                 }
59                         }
60                 } else {
61                 if(expectedValue == actual[j]) {
62                         matches++;
63                 }
64             }
65         }
66         if(matches == 0) {
67             assert(descr + ": No match found for " + expectedValue,false);
68         }
69         if(matches > 1) {
70             assert(descr + ": Multiple matches found for " + expectedValue, false);
71         }
72     }
73   }
74
75   function assertEqualsCollection(descr, expected, actual) {
76     //
77     //  if they aren't the same size, they aren't equal
78     assertEquals(descr, expected.length, actual.length);
79     //
80     //  if there length is the same, then every entry in the expected list
81     //     must appear once and only once in the actual list
82     var expectedLen = expected.length;
83     var expectedValue;
84     var actualLen = actual.length;
85     var i;
86     var j;
87     var matches;
88     for(i = 0; i < expectedLen; i++) {
89         matches = 0;
90         expectedValue = expected[i];
91         for(j = 0; j < actualLen; j++) {
92             if(expectedValue == actual[j]) {
93                 matches++;
94             }
95         }
96         if(matches == 0) {
97             assert(descr + ": No match found for " + expectedValue,false);
98         }
99         if(matches > 1) {
100             assert(descr + ": Multiple matches found for " + expectedValue, false);
101         }
102     }
103   }
104
105
106   function assertEqualsListAutoCase(context, descr, expected, actual) {
107         var minLength = expected.length;
108         if (actual.length < minLength) {
109             minLength = actual.length;
110         }
111     //
112     for(var i = 0; i < minLength; i++) {
113                 assertEqualsAutoCase(context, descr, expected[i], actual[i]);
114     }
115     //
116     //  if they aren't the same size, they aren't equal
117     assertEquals(descr, expected.length, actual.length);
118   }
119
120
121   function assertEqualsList(descr, expected, actual) {
122         var minLength = expected.length;
123         if (actual.length < minLength) {
124             minLength = actual.length;
125         }
126     //
127     for(var i = 0; i < minLength; i++) {
128         if(expected[i] != actual[i]) {
129                         assertEquals(descr, expected[i], actual[i]);
130         }
131     }
132     //
133     //  if they aren't the same size, they aren't equal
134     assertEquals(descr, expected.length, actual.length);
135   }
136
137   function assertInstanceOf(descr, type, obj) {
138     if(type == "Attr") {
139         assertEquals(descr,2,obj.nodeType);
140         var specd = obj.specified;
141     }
142   }
143
144   function assertSame(descr, expected, actual) {
145     if(expected != actual) {
146         assertEquals(descr, expected.nodeType, actual.nodeType);
147         assertEquals(descr, expected.nodeValue, actual.nodeValue);
148     }
149   }
150
151   function assertURIEquals(assertID, scheme, path, host, file, name, query, fragment, isAbsolute, actual) {
152     //
153     //  URI must be non-null
154     assertNotNull(assertID, actual);
155
156     var uri = actual;
157
158     var lastPound = actual.lastIndexOf("#");
159     var actualFragment = "";
160     if(lastPound != -1) {
161         //
162         //   substring before pound
163         //
164         uri = actual.substring(0,lastPound);
165         actualFragment = actual.substring(lastPound+1);
166     }
167     if(fragment != null) assertEquals(assertID,fragment, actualFragment);
168
169     var lastQuestion = uri.lastIndexOf("?");
170     var actualQuery = "";
171     if(lastQuestion != -1) {
172         //
173         //   substring before pound
174         //
175         uri = actual.substring(0,lastQuestion);
176         actualQuery = actual.substring(lastQuestion+1);
177     }
178     if(query != null) assertEquals(assertID, query, actualQuery);
179
180     var firstColon = uri.indexOf(":");
181     var firstSlash = uri.indexOf("/");
182     var actualPath = uri;
183     var actualScheme = "";
184     if(firstColon != -1 && firstColon < firstSlash) {
185         actualScheme = uri.substring(0,firstColon);
186         actualPath = uri.substring(firstColon + 1);
187     }
188
189     if(scheme != null) {
190         assertEquals(assertID, scheme, actualScheme);
191     }
192
193     if(path != null) {
194         assertEquals(assertID, path, actualPath);
195     }
196
197     if(host != null) {
198         var actualHost = "";
199         if(actualPath.substring(0,2) == "//") {
200             var termSlash = actualPath.substring(2).indexOf("/") + 2;
201             actualHost = actualPath.substring(0,termSlash);
202         }
203         assertEquals(assertID, host, actualHost);
204     }
205
206     if(file != null || name != null) {
207         var actualFile = actualPath;
208         var finalSlash = actualPath.lastIndexOf("/");
209         if(finalSlash != -1) {
210             actualFile = actualPath.substring(finalSlash+1);
211         }
212         if (file != null) {
213             assertEquals(assertID, file, actualFile);
214         }
215         if (name != null) {
216             var actualName = actualFile;
217             var finalDot = actualFile.lastIndexOf(".");
218             if (finalDot != -1) {
219                 actualName = actualName.substring(0, finalDot);
220             }
221             assertEquals(assertID, name, actualName);
222         }
223     }
224
225     if(isAbsolute != null) {
226         assertEquals(assertID, isAbsolute, actualPath.substring(0,1) == "/");
227     }
228   }
229
230
231 // size() used by assertSize element
232 function size(collection)
233 {
234   return collection.length;
235 }
236
237 function same(expected, actual)
238 {
239   return expected === actual;
240 }
241
242 function equalsAutoCase(context, expected, actual) {
243         if (builder.contentType == "text/html") {
244                 if (context == "attribute") {
245                         return expected.toLowerCase() == actual;
246                 }
247                 return expected.toUpperCase() == actual;
248         }
249         return expected == actual;
250 }
251
252 function toLowerArray(src) {
253    var newArray = new Array();
254    var i;
255    for (i = 0; i < src.length; i++) {
256       newArray[i] = src[i].toLowerCase();
257    }
258    return newArray;
259 }
260
261 function createTempURI(scheme) {
262    if (scheme == "http") {
263           return "http://localhost:8080/webdav/tmp" + Math.floor(Math.random() * 100000) + ".xml";
264    }
265    return "file:///tmp/domts" + Math.floor(Math.random() * 100000) + ".xml";
266 }
267
268
269
270 function EventMonitor() {
271   this.atEvents = new Array();
272   this.bubbledEvents = new Array();
273   this.capturedEvents = new Array();
274   this.allEvents = new Array();
275 }
276
277 EventMonitor.prototype.handleEvent = function(evt) {
278     switch(evt.eventPhase) {
279        case 1:
280        monitor.capturedEvents[monitor.capturedEvents.length] = evt;
281        break;
282        
283        case 2:
284        monitor.atEvents[monitor.atEvents.length] = evt;
285        break;
286
287        case 3:
288        monitor.bubbledEvents[monitor.bubbledEvents.length] = evt;
289        break;
290     }
291     monitor.allEvents[monitor.allEvents.length] = evt;
292 }
293
294 function DOMErrorImpl(err) {
295   this.severity = err.severity;
296   this.message = err.message;
297   this.type = err.type;
298   this.relatedException = err.relatedException;
299   this.relatedData = err.relatedData;
300   this.location = err.location;
301 }
302
303
304
305 function DOMErrorMonitor() {
306   this.allErrors = new Array();
307 }
308
309 DOMErrorMonitor.prototype.handleError = function(err) {
310     errorMonitor.allErrors[errorMonitor.allErrors.length] = new DOMErrorImpl(err);
311 }
312
313 DOMErrorMonitor.prototype.assertLowerSeverity = function(id, severity) {
314     var i;
315     for (i = 0; i < this.allErrors.length; i++) {
316         if (this.allErrors[i].severity >= severity) {
317            assertEquals(id, severity - 1, this.allErrors[i].severity);
318         }
319     }
320 }
321
322 function UserDataNotification(operation, key, data, src, dst) {
323     this.operation = operation;
324     this.key = key;
325     this.data = data;
326     this.src = src;
327     this.dst = dst;
328 }
329
330 function UserDataMonitor() {
331         this.allNotifications = new Array();
332 }
333
334 UserDataMonitor.prototype.handle = function(operation, key, data, src, dst) {
335     userDataMonitor.allNotifications[userDataMonitor.allNotifications.length] =
336          new UserDataNotification(operation, key, data, src, dst);
337 }
338
339
340
341 function HTMLBuilder() {
342     this.contentType = "application/xhtml+xml";
343     this.supportedContentTypes = [ "application/xhtml+xml" ];
344
345     this.supportsAsyncChange = false;
346     this.async = false;
347     this.fixedAttributeNames = [
348         "validating",  "expandEntityReferences", "coalescing", 
349         "signed", "hasNullString", "ignoringElementContentWhitespace", "namespaceAware", "ignoringComments", "schemaValidating"];
350
351     this.fixedAttributeValues = [false,  true, false, true, true , false, true, false, false ];
352     this.configurableAttributeNames = [ ];
353     this.configurableAttributeValues = [ ];
354     this.initializationError = null;
355     this.initializationFatalError = null;
356     this.skipIncompatibleTests = true;
357     this.documentURLs = new Array();
358     this.documentVarnames = new Array();
359 }
360
361 HTMLBuilder.prototype.hasFeature = function(feature, version) {
362     return document.implementation.hasFeature(feature, version);
363 }
364
365 HTMLBuilder.prototype.getImplementation = function() {
366   return document.implementation;
367 }
368
369 HTMLBuilder.prototype.preload = function(frame, varname, url) {
370   var i;
371   this.documentVarnames[this.documentVarnames.length] = varname;
372   this.documentURLs[this.documentURLs.length] = url;
373   if (this.documentURLs.length > 1) {
374      //
375      //   if all the urls are not the same
376      //
377      for (i = 1; i < this.documentURLs.length; i++) {
378          if (this.documentURLs[i] != this.documentURLs[0]) {
379              throw "Tests with multiple loads of different documents are not currently supported";
380          }
381      }
382   }
383   return 1;
384 }
385
386 HTMLBuilder.prototype.cloneNode = function(srcNode, doc) {
387    var clone = null;
388    switch(srcNode.nodeType) {
389       //
390       //  element
391       case 1:
392       clone = doc.createElementNS(srcNode.namespaceURI, srcNode.nodeName);
393       var attrs = srcNode.attributes;
394       for(var i = 0; i < attrs.length; i++) {
395           var srcAttr = attrs.item(i);
396           clone.setAttributeNS(srcAttr.namespaceURI, srcAttr.nodeName, srcAttr.nodeValue);
397       }
398       var srcChild = srcNode.firstChild;
399       while(srcChild != null) {
400          var cloneChild = this.cloneNode(srcChild, doc);
401          if (cloneChild != null) {
402              clone.appendChild(cloneChild);
403          }
404          srcChild = srcChild.nextSibling;
405       }
406       break;
407       
408       case 3:
409       clone = doc.createTextNode(srcNode.nodeValue);
410       break;
411       
412       case 4:
413       clone = doc.createCDATASection(srcNode.nodeValue);
414       break;
415       
416       case 5:
417       clone = doc.createEntityReference(srcNode.nodeName);
418       break;
419                   
420       case 7:
421       clone = doc.createProcessingInstruction(srcNode.target, srcNode.data);
422       break;
423       
424       case 8:
425       clone = doc.createComment(srcNode.nodeValue);
426       break;
427    }
428    return clone;
429       
430 }
431
432
433 HTMLBuilder.prototype.load = function(frame, varname, url) {
434   if (this.documentVarnames[0] == varname) {
435         return document;
436   }
437   //
438   //
439   //  not a perfect way to do this
440   //    Document.cloneNode is implementation dependent but exists in L1
441   //       and implemented in IE.  The alternative brute force copy
442   //       only works in L2 or higher implementations and can't copy
443   //       entity and notation definitions, etc.
444   var clone = null;
445   try {
446       clone = document.cloneNode(true);
447   } catch(ex) {
448   }
449   if (clone == null) {
450       clone = document.implementation.createDocument(
451           document.documentElement.namespaceURI,
452           document.documentElement.nodeName,
453           null);
454       //
455       //   Work-around since
456       //   Safari does not create document element 
457       //      create document.      
458       if (clone.documentElement == null) {
459            clone.appendChild(clone.createElementNS(
460               document.documentElement.namespaceURI, 
461               document.documentElement.nodeName));
462       }
463       var attrs = document.documentElement.attributes;
464       for(var i = 0; i < attrs.length; i++) {
465           var srcAttr = attrs.item(i);
466           clone.documentElement.setAttributeNS(
467              srcAttr.namespaceURI, srcAttr.nodeName, srcAttr.nodeValue);
468       }
469
470       var srcNode = document.firstChild;
471       while(srcNode != null && srcNode.nodeType != 1) {
472           if (srcNode.nodeType != 10) {
473                  var cloneNode = this.cloneNode(srcNode, clone);
474              clone.insertBefore(cloneNode, clone.documentElement);
475            }
476            srcNode = srcNode.nextSibling; 
477       }
478       srcNode = document.documentElement.nextSibling;
479       while(srcNode != null) {
480           var cloneNode = this.cloneNode(srcNode, clone);
481           clone.appendChild(cloneNode);
482           srcNode = srcNode.nextSibling;
483       }
484       srcNode = document.documentElement.firstChild;
485       while(srcNode != null) {
486           var cloneNode = this.cloneNode(srcNode, clone);
487           if (cloneNode != null) {
488              clone.documentElement.appendChild(cloneNode);
489           }
490           srcNode = srcNode.nextSibling;
491       }
492   }
493   return clone;
494 }
495
496 HTMLBuilder.prototype.getImplementationAttribute = function(attr) {
497     for (var i = 0; i < this.fixedAttributeNames.length; i++) {
498         if (this.fixedAttributeNames[i] == attr) {
499             return this.fixedAttributeValues[i];
500         }
501     }
502     throw "Unrecognized implementation attribute: " + attr;
503 }
504
505
506 HTMLBuilder.prototype.setImplementationAttribute = function(attribute, value) {
507     var supported = this.getImplementationAttribute(attribute);
508     if (supported != value) {
509         this.initializationError = "HTML loader does not support " + attribute + "=" + value;
510     }
511 }
512
513 HTMLBuilder.prototype.canSetImplementationAttribute = function(attribute, value) {
514     var supported = this.getImplementationAttribute(attribute);
515     return (supported == value);
516 }
517
518
519
520
521 function createConfiguredBuilder() {
522     return new HTMLBuilder();
523 }
524
525 function catchInitializationError(buildr, ex) {
526    buildr.initializationError = ex;
527    buildr.initializationFatalError = ex;
528 }
529
530
531 function checkFeature(feature, version)
532 {
533   if (!builder.hasFeature(feature, version))
534   {
535     //
536     //   don't throw exception so that users can select to ignore the precondition
537     //
538     builder.initializationError = "builder does not support feature " + feature + " version " + version;
539   }
540 }
541
542 function setResult(resultType, message) {
543    var testName = getTargetURI();
544    document.title = testName + ":" + resultType;
545    var xhtmlNS = "http://www.w3.org/1999/xhtml"; 
546    var newBody = document.createElementNS(xhtmlNS, "body");
547    var newTable = document.createElementNS(xhtmlNS, "table");
548    newTable.width = "100%";
549    newTable.border = "1";
550    newBody.appendChild(newTable);
551    var testRow = newTable.insertRow(-1);
552    var testDiv1 = testRow.insertCell(-1);
553    testDiv1.appendChild(document.createTextNode("Test"));
554    var testDiv2 = testRow.insertCell(-1);
555    testDiv2.appendChild(document.createTextNode(testName));
556    var statusRow = newTable.insertRow(-1);
557    var statusDiv1 = statusRow.insertCell(-1);
558    statusDiv1.appendChild(document.createTextNode("Status"));
559    var statusDiv2 = statusRow.insertCell(-1);
560    var style = "color:green";
561    if (resultType == null) {
562                 statusDiv2.appendChild(document.createTextNode("Success"));
563    } else {
564                 statusDiv2.appendChild(document.createTextNode(resultType));
565                 if (resultType == "skip") {
566                     style = "color:blue";
567                 } else {
568                     style = "color:red";
569                 }
570    }
571    newTable.setAttributeNS(null, "style", style);
572    if (message != null) {
573       var messageRow = newTable.insertRow(-1);
574           var messageDiv1 = messageRow.insertCell(-1);
575       messageDiv1.appendChild(document.createTextNode("Message"));
576       var messageDiv2 = messageRow.insertCell(-1);
577       messageDiv2.appendChild(document.createTextNode((message instanceof Error) ? ("Line " + message.line + ": " + message.name) : message));
578    }
579    var oldBody = document.getElementsByTagName("body")[0];
580    oldBody.parentNode.replaceChild(newBody, oldBody);
581    if (parent != window && typeof(parent.setResult) != 'undefined') {
582        parent.setResult(testName, resultType, message);
583    }
584 }
585
586 function checkInitialization(buildr, testname) {
587    return buildr.initializationError;
588 }
589
590 function preload(docRef, varname, href) {
591    return builder.preload(docRef, varname, href);
592 }
593
594
595 function load(docRef, varname, href) {
596    return builder.load(docRef, varname, href);
597 }
598
599
600 function getImplementationAttribute(attr) {
601     return builder.getImplementationAttribute(attr);
602 }
603
604
605 function setImplementationAttribute(attribute, value) {
606     builder.setImplementationAttribute(attribute, value);
607 }
608
609 function createXPathEvaluator(doc) {
610     try {
611         return doc.getFeature("XPath", null);
612     }
613     catch(ex) {
614     }
615     return doc;
616 }
617
618
619 function getImplementation() {
620     return builder.getImplementation();
621 }
622
623 function assertEquals(id, expected, actual) {
624    var myActual;
625    if (expected != actual) {
626        myActual = actual;
627        if (actual == null) {
628           myActual = "null";
629        }
630        throw "failure:" + id + ": assertEquals failed, actual " + myActual + ", expected " + expected + "."; 
631    }
632 }
633
634 function assertNull(id, actual) {
635    if (actual != null) {
636        throw "failure:" + id + ": assertNull failed, actual " + actual;
637    }
638 }
639
640
641 function assertTrue(id, actual) {
642    if (!actual) {
643        throw "failure:" + id + ": assertTrue failed";
644    }
645 }
646
647
648 function assertFalse(id, actual) {
649    if (actual) {
650        throw "failure:" + id +  ": assertTrue failed";
651    }
652 }
653
654 function assertNotNull(id, actual) {
655    if (actual == null) {
656        throw "failure:" + id + ": assertNotNull failed";
657    }
658 }
659
660 function fail(id) {
661     throw "failure:" + id +  ": fail";
662 }
663
664
665
666 function getSuffix(contentType) {
667     switch(contentType) {
668         case "text/html":
669         return ".html";
670
671         case "text/xml":
672         return ".xml";
673
674         case "image/svg+xml":
675         return ".svg";
676
677         case "text/mathml":
678         return ".mml";
679     }
680     return ".xhtml";
681 }
682
683
684 function getResourceURI(name, scheme, contentType) {
685     var base = document.documentURI;
686     if (base == null) {
687        base = "";
688     } else {
689            base = base.substring(0, base.lastIndexOf('/') + 1) + "files/";
690     }
691     return base + name + getSuffix(contentType);
692 }
693
694
695
696 function startTest() {
697
698 //
699 //  WebKit modification: 18-August-2005
700 //
701 //  Inform the test controller that this test has a text-format result and so should
702 //  be dumped as text, and also that the dump should not occur automatically.
703 //
704 if (window.layoutTestController) {
705     layoutTestController.dumpAsText();
706     layoutTestController.waitUntilDone();
707 }
708 //
709 //  End WebKit modification
710 //
711
712         //
713         //   invoke test setup
714         //
715         setUpPage();
716         try {
717             runTest();
718             if (builder.initializationError == null) {
719                setResult(null, null);
720             } else {
721                setResult("skip", builder.initializationError);
722             }
723         } catch(ex) {
724             if (typeof(ex.substring) != 'undefined' && ex.substring(0, 8) == "failure:") {
725             setResult("failure", ex.substring(8));
726         } else {
727             setResult("error", ex);
728         }
729     }
730
731 //
732 //  WebKit modification: 18-August-2005
733 //
734 //  Inform the test controller that this test is complete, so it's time to dump.
735 //
736     if (window.layoutTestController) {
737         layoutTestController.notifyDone();
738     }
739 //
740 //  End WebKit modification
741 //      
742
743 }