Bug 632143 patch 4: Extend SVGxxxList mochitest to check animVal up-to-date-ness after baseVal's length is mutated. r=roc a=tests
authorDaniel Holbert <dholbert@cs.stanford.edu>
Tue, 15 Feb 2011 23:54:37 -0800
changeset 62660 ab0dc35174fb344228c57917698d99eeb7b72697
parent 62659 26b045c6f347eddedd85014d67cb34dadd627f7a
child 62661 49186a8f4fa2d6fa25d1fae66fa77f0f9df0f296
child 62709 ca4499e291e4246a4b86a6fb5300661e13245ba5
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersroc, tests
bugs632143
milestone2.0b12pre
Bug 632143 patch 4: Extend SVGxxxList mochitest to check animVal up-to-date-ness after baseVal's length is mutated. r=roc a=tests
content/svg/content/test/test_SVGxxxList.xhtml
--- a/content/svg/content/test/test_SVGxxxList.xhtml
+++ b/content/svg/content/test/test_SVGxxxList.xhtml
@@ -7,17 +7,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="text/javascript" src="/MochiKit/packed.js"></script>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=515116">Mozilla Bug 515116</a>
 <p id="display"></p>
 <div id="content" style="display:none;">
-<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100" height="100">
+<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100" height="100"
+     onload="this.pauseAnimations();">
   <desc>
     <filter>
       <feComponentTransfer>
         <feFuncR id="feFuncR" type="table"/>
       </feComponentTransfer>
     </filter>
   </desc>
   <text id="text">text</text>
@@ -74,16 +75,22 @@ To have the battery of generic tests run
   attr_val_3a:
   attr_val_3b:
     Two attribute values containing three different items.
   attr_val_4
     An attribute value containing four items.
   attr_val_5a:
   attr_val_5b:
     Two attribute values containing five different items.
+  item_constructor:
+    Function to create a dummy list item.
+  item_is:
+    Function to compare two list items for equality, like "is()". If this
+    property is omitted, it is assumed that we can just compare
+    "item.value" (which is the case for most list types).
 */
 
 var tests = [
   {
     // SVGLengthList test:
     target_element_id: 'text',
     attr_name: 'x',
     prop_name: 'x',
@@ -162,16 +169,27 @@ var tests = [
     attr_val_3a: ' 10,10 50,50 90,10 ',
     attr_val_3b: ' 10,50 50,10 90,50 ',
     attr_val_4 : ' 10,10 50,50 90,10 200,100 ',
     attr_val_5a: ' 10,10 50,50 90,10 130,50 170,10 ',
     attr_val_5b: ' 50,10 50,10 90,50 130,10 170,50 ',
     item_constructor: function() {
       // XXX return different values each time
       return document.getElementById('svg').createSVGPoint();
+    },
+    item_is: function(itemA, itemB, message) {
+      ok(typeof(itemA.x) != 'undefined' &&
+         typeof(itemB.x) != 'undefined',
+         'expecting x property');
+      ok(typeof(itemA.y) != 'undefined' &&
+         typeof(itemB.y) != 'undefined',
+         'expecting y property');
+
+      is(itemA.x, itemB.x, message);
+      is(itemA.y, itemB.y, message);
     }
   },
   {
     // SVGPathSegList test:
     target_element_id: 'path',
     attr_name: 'd',
     prop_name: null, // SVGAnimatedPathData is an inherited interface!
     bv_name: 'pathSegList',
@@ -183,16 +201,24 @@ var tests = [
     attr_val_3a: 'M 10,10 L 50,50 L 90,10',
     attr_val_3b: 'M 10,50 L 50,10 L 90,50',
     attr_val_4 : 'M 10,10 L 50,50 L 90,10 M 200,100',
     attr_val_5a: 'M 10,10 L 50,50 L 90,10 L 130,50 L 170,10',
     attr_val_5b: 'M 50,10 L 50,10 L 90,50 L 130,10 L 170,50',
     item_constructor: function() {
       // XXX return different values each time
       return document.getElementById('path').createSVGPathSegMovetoAbs(1, 1);
+    },
+    item_is: function(itemA, itemB, message) {
+      ok(typeof(itemA.pathSegType) != 'undefined' &&
+         typeof(itemB.pathSegType) != 'undefined',
+         'expecting pathSegType property');
+
+      // NOTE: Just comparing pathSegType - probably sufficient for our purposes
+      is(itemA.pathSegType, itemB.pathSegType, message);
     }
   },
 /*
   {
     // SVGPathSegList test:
     target_element_id: 'path',
     attr_name: 'd',
     prop_name: null, // SVGAnimatedPathData is an inherited interface!
@@ -205,16 +231,24 @@ var tests = [
     attr_val_3a: '',
     attr_val_3b: '',
     attr_val_4 : '',
     attr_val_5a: '',
     attr_val_5b: '',
     item_constructor: function() {
       // XXX return different values each time
       return SVGPathElement.createSVGPathSegLinetoAbs(1, 1);
+    },
+    item_is: function(itemA, itemB, message) {
+      ok(typeof(itemA.pathSegType) != 'undefined' &&
+         typeof(itemB.pathSegType) != 'undefined',
+         'expecting pathSegType property');
+
+      // NOTE: Just comparing pathSegType - probably sufficient for our purposes
+      is(itemA.pathSegType, itemB.pathSegType, message);
     }
   },
   {
     // SVGStringList test:
     target_element_id: 'g',
     attr_name: 'requiredFeatures', // requiredExtensions, systemLanguage, viewTarget
     prop_name: null, // SVGStringList attributes are not animatable
     bv_name: 'requiredFeatures',
@@ -856,16 +890,105 @@ function run_basic_setAttribute_tests()
          'After its attribute changes, list items in the '+t.list_type+' for '+
          t.av_path+' that are at indexes that did not exist prior to the '+
          'attribute change should not be the same objects as any objects '+
          'that were at those indexes at some earlier time.');
     }
   }
 }
 
+/**
+ * This function verifies that a list's animVal is kept in sync with its
+ * baseVal, when we add & remove items from the baseVal.
+ */
+function run_list_mutation_tests()
+{
+  for each (var t in tests) {
+    if (t.animVal) {
+      // Test removeItem()
+      // =================
+      // Save second item in baseVal list; then make it the first item, and
+      // check that animVal is updated accordingly.
+      t.element.setAttribute(t.attr_name, t.attr_val_4);
+
+      var secondVal = t.baseVal.getItem(1);
+      var removedFirstVal = t.baseVal.removeItem(0);
+      t.item_is(t.animVal.getItem(0), secondVal,
+                'animVal for '+t.attr_name+' needs update after first item ' +
+                'removed');
+
+      // Repeat with last item
+      var secondToLastVal = t.baseVal.getItem(1);
+      var removedLastVal = t.baseVal.removeItem(2);
+
+      var threw = false;
+      try {
+        t.animVal.getItem(2);
+      } catch(e) {
+        threw = true;
+      }
+      ok(threw,
+         'The method '+t.attr_name+'.animVal.getItem() for previously-final ' +
+         'index should throw after final item is removed from baseVal.');
+
+      t.item_is(t.animVal.getItem(1), secondToLastVal,
+                'animVal for ' + t.attr_name +' needs update after last item ' +
+                'removed');
+
+      // Test insertItemBefore()
+      // =======================
+      // Reset base value, insert value @ start, check that animVal is updated.
+      t.element.setAttribute(t.attr_name, t.attr_val_3a);
+      t.baseVal.insertItemBefore(removedLastVal, 0);
+      t.item_is(t.animVal.getItem(0), removedLastVal,
+                'animVal for '+t.attr_name+' needs update after insert at ' +
+                'beginning');
+
+      // Repeat with insert at end
+      t.element.setAttribute(t.attr_name, t.attr_val_3a);
+      t.baseVal.insertItemBefore(removedFirstVal, t.baseVal.numberOfItems);
+      t.item_is(t.animVal.getItem(t.baseVal.numberOfItems - 1),
+                removedFirstVal,
+                'animVal for '+t.attr_name+' needs update after insert at end');
+
+      // Test appendItem()
+      // =================
+      var dummy = t.item_constructor();
+      t.baseVal.appendItem(dummy);
+      t.item_is(t.animVal.getItem(t.baseVal.numberOfItems - 1), dummy,
+                'animVal for '+t.attr_name+' needs update after appendItem');
+
+      // Test clear()
+      // ============
+      t.baseVal.clear();
+      threw = false;
+      try {
+        t.animVal.getItem(0);
+      } catch(e) {
+        threw = true;
+      }
+      ok(threw,
+         'The method '+t.attr_name+'.animVal.getItem() should throw after ' +
+         'we\'ve cleared baseVal.');
+
+      is(t.animVal.numberOfItems, 0,
+         'animVal for '+t.attr_name+' should be empty after baseVal cleared');
+
+      // Test initialize()
+      // =================
+      t.element.setAttribute(t.attr_name, t.attr_val_3a);
+      t.baseVal.initialize(dummy);
+
+      is(t.animVal.numberOfItems, 1,
+         'animVal for '+t.attr_name+' should have length 1 after initialize');
+      t.item_is(t.animVal.getItem(0), dummy,
+                'animVal for '+t.attr_name+' needs update after initialize');
+    }
+  }
+}
 
 /**
  * In this function we run a series of tests at various points along the SMIL
  * animation timeline, using SVGSVGElement.setCurrentTime() to move forward
  * along the timeline.
  *
  * Since Mozilla doesn't currently support moving backwards along the timeline
  * we run over all the tests before moving on to the next point in the
@@ -1128,18 +1251,16 @@ function run_animation_timeline_tests()
        ' should be the exact same objects as were at that index before the '+
        'end and unfreezing of the animation occured.');
    }
 }
 
 
 function run_tests()
 {
-    document.getElementById('svg').pauseAnimations();
-
   // Initialize each test object with some useful properties, and create their
   // 'animate' elements. Note that 'prop' and 'animVal' may be null.
   for each (var t in tests) {
     t.element = document.getElementById(t.target_element_id);
     t.prop = t.prop_name ? t.element[t.prop_name] : null;
     t.baseVal = ( t.prop || t.element )[t.bv_name];
     t.animVal = t.av_name ? ( t.prop || t.element )[t.av_name] : null;
     t.bv_path = t.el_type + '.' +
@@ -1147,24 +1268,35 @@ function run_tests()
                 t.bv_name;  // e.g. 'SVGTextElement.x.baseVal'
     if (t.animVal) {
       t.av_path = t.el_type + '.' +
                   (t.prop ? t.prop_name + '.' : '') +
                   t.av_name;
     }
     t.prop_type = t.prop_type || null;
 
+    // use fallback 'is' function, if none was provided.
+    if (!t.item_is) {
+      t.item_is = function(itemA, itemB, message) {
+      ok(typeof(itemA.value) != 'undefined' &&
+         typeof(itemB.value) != 'undefined',
+         'expecting value property');
+        is(itemA.value, itemB.value, message);
+      };
+    }
+
     t.element.appendChild(create_animate_elements(t));
   }
 
   // Run the major test groups:
 
   run_baseVal_API_tests();
   run_animVal_API_tests();
   run_basic_setAttribute_tests();
+  run_list_mutation_tests();
   run_animation_timeline_tests();
 
   // After all the other test manipulations, we check that the following
   // objects have still not changed, since they never should:
 
   for each (var t in tests) {
     if (t.prop) {
       ok(t.prop === t.element[t.prop_name],