1/*
2Copyright (c) 2001-2005 World Wide Web Consortium,
3(Massachusetts Institute of Technology, European Research Consortium
4for Informatics and Mathematics, Keio University). All
5Rights Reserved. This work is distributed under the W3C(r) Software License [1] in the
6hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7the 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
232function size(collection)
233{
234  return collection.length;
235}
236
237function same(expected, actual)
238{
239  return expected === actual;
240}
241
242function 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
252function 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
261function 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
270function EventMonitor() {
271  this.atEvents = new Array();
272  this.bubbledEvents = new Array();
273  this.capturedEvents = new Array();
274  this.allEvents = new Array();
275}
276
277EventMonitor.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
294function 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
305function DOMErrorMonitor() {
306  this.allErrors = new Array();
307}
308
309DOMErrorMonitor.prototype.handleError = function(err) {
310    errorMonitor.allErrors[errorMonitor.allErrors.length] = new DOMErrorImpl(err);
311}
312
313DOMErrorMonitor.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
322function 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
330function UserDataMonitor() {
331	this.allNotifications = new Array();
332}
333
334UserDataMonitor.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
341function 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
361HTMLBuilder.prototype.hasFeature = function(feature, version) {
362    return document.implementation.hasFeature(feature, version);
363}
364
365HTMLBuilder.prototype.getImplementation = function() {
366  return document.implementation;
367}
368
369HTMLBuilder.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
386HTMLBuilder.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
433HTMLBuilder.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
496HTMLBuilder.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
506HTMLBuilder.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
513HTMLBuilder.prototype.canSetImplementationAttribute = function(attribute, value) {
514    var supported = this.getImplementationAttribute(attribute);
515    return (supported == value);
516}
517
518
519
520
521function createConfiguredBuilder() {
522    return new HTMLBuilder();
523}
524
525function catchInitializationError(buildr, ex) {
526   buildr.initializationError = ex;
527   buildr.initializationFatalError = ex;
528}
529
530
531function 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
542function 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));
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
586function checkInitialization(buildr, testname) {
587   return buildr.initializationError;
588}
589
590function preload(docRef, varname, href) {
591   return builder.preload(docRef, varname, href);
592}
593
594
595function load(docRef, varname, href) {
596   return builder.load(docRef, varname, href);
597}
598
599
600function getImplementationAttribute(attr) {
601    return builder.getImplementationAttribute(attr);
602}
603
604
605function setImplementationAttribute(attribute, value) {
606    builder.setImplementationAttribute(attribute, value);
607}
608
609function createXPathEvaluator(doc) {
610    try {
611        return doc.getFeature("XPath", null);
612    }
613    catch(ex) {
614    }
615    return doc;
616}
617
618
619function getImplementation() {
620    return builder.getImplementation();
621}
622
623function 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
634function assertNull(id, actual) {
635   if (actual != null) {
636       throw "failure:" + id + ": assertNull failed, actual " + actual;
637   }
638}
639
640
641function assertTrue(id, actual) {
642   if (!actual) {
643       throw "failure:" + id + ": assertTrue failed";
644   }
645}
646
647
648function assertFalse(id, actual) {
649   if (actual) {
650       throw "failure:" + id +  ": assertTrue failed";
651   }
652}
653
654function assertNotNull(id, actual) {
655   if (actual == null) {
656       throw "failure:" + id + ": assertNotNull failed";
657   }
658}
659
660function fail(id) {
661    throw "failure:" + id +  ": fail";
662}
663
664
665
666function 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
684function 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
696function 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//
704if (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}
744