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