Revision: 3857
Author: felix8a
Date: Thu Nov 19 23:47:53 2009
Log: fix various domita test issues
http://codereview.appspot.com/157093

This fixes:

bug 1131 - bridal constructClone doesn't set the "class"
  attribute properly on IE[67].

bug 1140 - testUseMap fails on various browsers, because it's
  doing un-normalized html comparison.  after this change, it
  still fails on IE[67] because you can't set an element's @name
  after it's created.

bug 1142 - two cloneNode tests fail on IE8-std.

bug 1143 - _testSideEffectTestFramework fails on IE.

bug 1162 - Array.slice behaves differently on various browsers
  when the end arg === undefined.

bug 1168 - "Ready for testing" box never turns green on IE[67].

[email protected]

http://code.google.com/p/google-caja/source/detail?r=3857

Modified:
 /trunk/src/com/google/caja/cajita.js
 /trunk/src/com/google/caja/plugin/bridal.js
 /trunk/tests/com/google/caja/plugin/domita_test.html
 /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html

=======================================
--- /trunk/src/com/google/caja/cajita.js        Tue Nov 17 11:07:08 2009
+++ /trunk/src/com/google/caja/cajita.js        Thu Nov 19 23:47:53 2009
@@ -87,16 +87,24 @@
 }

 /**
- * Provide Array.slice like Firefox.  You can slice anything, and the
- * result is always an array.  This behaves differently from Firefox in the
- * exotic case of an array-like x with typeof x !== 'object'.
+ * Provide Array.slice similar to Firefox.  You can slice anything, and the
+ * result is always an array.  Hazards:
+ *
+ *  - In IE, Array.prototype.slice.call(void 0) throws an error, and we
+ *    need it to return [].
+ *
+ *  - In IE[678] and Firefox 3, x.slice(0, undefined) returns [] rather
+ *    than x.  We don't care about that incompatibility, but we do need
+ *    Array.slice(x) to return x.
+ *
+ *  - In Firefox 3.x, Array.slice works on any array-like x.  We only
+ *    handle typeof x === 'object'.
  */
 if (Array.slice === void 0) {
-  Array.slice = function(self, start, end) {
+  Array.slice = function(self, opt_start, opt_end) {
     if (self && typeof self === 'object') {
-      if (arguments.length < 2) { start = 0; }
-      if (arguments.length < 3) { end = self.length; }
-      return Array.prototype.slice.call(self, start, end);
+      if (opt_end === void 0) { opt_end = self.length; }
+      return Array.prototype.slice.call(self, opt_start, opt_end);
     } else {
       return [];
     }
=======================================
--- /trunk/src/com/google/caja/plugin/bridal.js Fri Nov 13 13:37:15 2009
+++ /trunk/src/com/google/caja/plugin/bridal.js Thu Nov 19 23:47:53 2009
@@ -36,7 +36,6 @@
   var isWebkit = !isOpera && navigator.userAgent.indexOf('WebKit') !== -1;

   var featureAttachEvent = !!(document.createElement('div').attachEvent);
-  var featureSetAttributeExtraParam = isIE;
   /**
    * Does the extended form of extendedCreateElement work?
* From http://msdn.microsoft.com/en-us/library/ms536389.aspx :<blockquote>
@@ -134,7 +133,7 @@
       var attrs = node.attributes;
       for (var i = 0, attr; (attr = attrs[i]); ++i) {
         if (attr.specified && !endsWith__.test(attr.name)) {
-          clone.setAttribute(attr.nodeName, attr.nodeValue);
+          bridal.setAttribute(clone, attr.nodeName, attr.nodeValue);
         }
       }
     } else {
=======================================
--- /trunk/tests/com/google/caja/plugin/domita_test.html Fri Nov 13 13:37:15 2009 +++ /trunk/tests/com/google/caja/plugin/domita_test.html Thu Nov 19 23:47:53 2009
@@ -66,7 +66,7 @@
         function _testSideEffectTestFramework() {
           assertFalse(checkGlobalSideEffect());
           var s = document.createElement('SCRIPT');
-          s.innerHTML = 'globalSideEffect()';
+          s.text = 'globalSideEffect()';
           document.body.appendChild(s);
           assertTrue(checkGlobalSideEffect());
           assertFalse(checkGlobalSideEffect());
@@ -164,7 +164,7 @@

       function readyForAutomatedTesting() {
         var e = document.getElementById('automatedTestingReadyIndicator');
-        e.setAttribute('class', 'readytotest');
+        bridal.setAttribute(e, 'class', 'readytotest');
         e.innerHTML = 'Ready for testing';
       }

@@ -458,6 +458,8 @@
       });
       window.toString = function () { return '[WINDOW]'; };

+      document.title += isValija ? ' valija' : ' cajita';
+
       inlineHtml(
           isValija
               ? 'domita_test_untrusted_valija.out.html'
@@ -468,10 +470,8 @@
       this.evaluateAsyncRequirements(function (pass) {
         if (!pass) {
           document.title = document.title.replace(
-              / - all tests passed$/, ' - async tests failed');
-        }
-        assertTrue(document.title,
-                   /(?: - all tests passed)?$/.test(document.title));
+              /all tests passed/, 'async tests failed');
+        }
       });

       readyForAutomatedTesting();
=======================================
--- /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html Fri Nov 13 13:37:15 2009 +++ /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html Thu Nov 19 23:47:53 2009
@@ -329,7 +329,7 @@
 <div class="testcontainer" id="test-strange-ids"></div>

 <div class="testcontainer" id="test-clone-node-structure">
-  <p>I have <b title="I have attributes">content</b></p>
+  <p class="cloneable">some <label for="x">content</label></p>
 </div>

 <p class="testcontainer" id="test-compat-mode">Compat Mode:</p>
@@ -635,8 +635,12 @@
 }

 /**
- * Canonicalize well formed innerHTML output, by making sure that attributes
- * are ordered by name, and have quoted values.
+ * Canonicalize innerHTML output:
+ *   - collapse all whitespace to a single space
+ *   - remove whitespace between adjacent tags
+ *   - lowercase tagnames and attribute names
+ *   - sort attributes by name
+ *   - quote attribute values
  *
  * Without this step, it's impossible to compare innerHTML cross-browser.
  */
@@ -656,7 +660,7 @@
       function (_, tagStart, tagBody) {
         var attrs = [];
         for (var m; tagBody && (m = tagBody.match(htmlAttribute));) {
-          var name = m[1];
+          var name = m[1].toLowerCase();
           var value = m[2];
           var hasValue = value != null;
           if (hasValue && (new RegExp('^["\']')).test(value)) {
@@ -669,15 +673,18 @@
           tagBody = tagBody.substring(m[0].length);
         }
         attrs.sort();
-        return tagStart + ' ' + attrs.join(' ') + '>';
+        attrs.unshift(tagStart);
+        return attrs.join(' ') + '>';
       });
   s = s.replace(
       htmlTag,
       function (_, open, name, body) {
         return open + name.toLowerCase() + (body || '') + '>';
       });
-  // Remove ignorable whitespace.
-  s = s.replace(ignorableWhitespace, '');
+  // Collapse whitespace.
+  s = s.replace(new RegExp('\\s+', 'g'), ' ');
+  s = s.replace(new RegExp('^ | $', 'g'), '');
+  s = s.replace(new RegExp('[>]\\s+[<]', 'g'), '><');
   // Normalize escaping of text nodes since Safari doesn't escape loose >.
   s = s.replace(
       tagEntityOrText,
@@ -1009,7 +1016,8 @@
 jsunitRegister('testDocumentWrite',
                function testDocumentWrite() {
// TODO(mikesamuel): This is wrong because we don't allow the insertion point
-  // to move above it's starting position
+  // to move above its starting position
+  var el = document.getElementById('test-document-write');
   assertEquals(
       ''
       + '<div>'
@@ -1021,8 +1029,7 @@
         + '<p>Written afterwards</p>'
         + '<p>More written afterwards</p>'
       + '</div>',
-      document.getElementById('test-document-write').innerHTML
-           .replace(new RegExp('[\\r\\n]\\s*', 'g'), ''));
+      canonInnerHtml(el.innerHTML));
   pass('test-document-write');
 });

@@ -1812,18 +1819,29 @@
     }
   }

+  // These cases are critical, because they affect the correctness of
+  // valija's fn.apply() implementation.  IE is the problem case, because
+  // it throws an error when you Array.prototype.slice.call(null).
   assertArray([], Array.slice(null), 'null');
   assertArray([], Array.slice(void 0), 'void 0');

-  // note difference between missing arg and undefined arg.
+  // These are expected behavior that work fine on all browsers.
   assertArray([9], Array.slice([9]), '([9])');
+  assertArray([9], Array.slice([9], null), '([9], null)');
   assertArray([9], Array.slice([9], void 0), '([9], void 0)');
- assertArray([], Array.slice([9], void 0, void 0), '([9], void 0, void 0)');
+  assertArray([],  Array.slice([9], null, 0), '([9], null, 0)');
   assertArray([],  Array.slice([9], void 0, 0), '([9], void 0, 0)');
+  assertArray([],  Array.slice([9], null, null), '([9], null, null)');
+  assertArray([],  Array.slice([9], void 0, null), '([9], void 0, null)');

   assertArray([2,3,4], Array.slice([0,1,2,3,4,5,6], 2, 5));
   assertArray([2,3], Array.slice([0,1,2,3], 2, 5));

+  // es5 says end===undefined is the same as end===length, and most
+  // browsers agree.  Firefox 3.x disagrees and treats it as end===0.
+  // Nothing depends on this behavior, so we ignore the incompatibility.
+ //assertArray([9], Array.slice([9], null, void 0), '([9], null, void 0)');
+
   pass('test-array-slice');
 });

@@ -2378,7 +2396,9 @@
       {
         nodeType: 1,
         tagName: 'P',
-        attributes: [],
+        attributes: [
+          { nodeName: 'class', nodeValue: 'cloneable' }
+        ],
         children: [
           // shallow clones contain attrs but not children.
         ]
@@ -2388,20 +2408,19 @@
       {
         nodeType: 1,
         tagName: 'P',
-        attributes: [],
+        attributes: [
+          { nodeName: 'class', nodeValue: 'cloneable' }
+        ],
         children: [
           {
             nodeType: 3,
-            nodeValue: 'I have '
+            nodeValue: 'some '
           },
           {
             nodeType: 1,
-            nodeName: 'B',
+            nodeName: 'LABEL',
             attributes: [
-              {
-                nodeName: 'title',
-                nodeValue: 'I have attributes'
-              }
+              { nodeName: 'for', nodeValue: 'x' }
             ],
             children: [
               {
@@ -3153,6 +3172,7 @@

 jsunitRegister('testUsemap',
                function testUsemap() {
+  var el = document.getElementById('test-usemap');
   assertEquals(
       (''
        + '<map name="foo-xyz___">'
@@ -3160,10 +3180,13 @@
        + '?mime-type=*%2F*&amp;uri=areatarget.html"'
        + ' target="_blank">'
        + '</map>'
-       + '<img usemap="#foo-xyz___"'
- + ' src="http://example.com/?mime-type=image%2F*&amp;uri=mappic.gif";>'),
-      directAccess.getInnerHTML(document.getElementById('test-usemap')));
-  pass('test-usemap');
+       + '<img'
+ + ' src="http://example.com/?mime-type=image%2F*&amp;uri=mappic.gif";'
+       + ' usemap="#foo-xyz___"'
+       + '>'),
+      canonInnerHtml(directAccess.getInnerHTML(el)));
+
+  pass('test-usemap');
 });

 jsunitRegister('testDocumentBodyAppendChild',

Reply via email to