Fix font-variation-settings interpolation test

font-variation-settings is a map, not an array, so the order is
irrelevant when comparing the actual and expected values. Add the
ability to supply a custom comparison function to
interpolation-testcommon.js to support properties like this.

This also exposed one test which incorrectly asserted no interpolation
when there should be interpolation.

Bug: 900581
Change-Id: I6c336e010c9c3642b14c945b3d7ae828f94b3f99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1764801
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Reviewed-by: Xida Chen <xidachen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#689924}
diff --git a/css/css-fonts/animations/font-variation-settings-interpolation.html b/css/css-fonts/animations/font-variation-settings-interpolation.html
index e11079c..cb99d7b 100644
--- a/css/css-fonts/animations/font-variation-settings-interpolation.html
+++ b/css/css-fonts/animations/font-variation-settings-interpolation.html
@@ -20,10 +20,24 @@
 <body></body>
 
 <script>
+
+// Because font-variation-settings is specced as a map rather than a list
+// (https://github.com/w3c/csswg-drafts/issues/1959), browsers are allowed to
+// reorder the output as they see fit.
+function compareFontVariationSettings(actual, expected) {
+  // This is not perfect, but should serve as a reasonable comparison. We split
+  // the inputs into arrays and trim each characteristic, then sort the array
+  // and compare them.
+  const actual_arr = actual.split(',').map(x => x.trim()).sort();
+  const expected_arr = expected.split(',').map(x => x.trim()).sort();
+  assert_array_equals(actual_arr, expected_arr);
+}
+
 test_interpolation({
   property: 'font-variation-settings',
   from: neutralKeyframe,
   to: '"test" 20',
+  comparisonFunction: compareFontVariationSettings,
 }, [
   {at: -0.5, expect: "'test' 5"},
   {at: 0, expect: "'test' 10"},
@@ -43,6 +57,7 @@
   property: 'font-variation-settings',
   from: 'inherit',
   to: "'test' 20",
+  comparisonFunction: compareFontVariationSettings,
 }, [
   {at: -0.5, expect: "'test' 35"},
   {at: 0, expect: "'test' 30"},
@@ -56,6 +71,7 @@
   property: 'font-variation-settings',
   from: 'unset',
   to: "'test' 20",
+  comparisonFunction: compareFontVariationSettings,
 }, [
   {at: -0.5, expect: "'test' 35"},
   {at: 0, expect: "'test' 30"},
@@ -75,6 +91,7 @@
   property: 'font-variation-settings',
   from: "'test' 20",
   to: "'test' 30",
+  comparisonFunction: compareFontVariationSettings,
 }, [
   {at: -0.5, expect: "'test' 15"},
   {at: 0, expect: "'test' 20"},
@@ -88,6 +105,7 @@
   property: 'font-variation-settings',
   from: "'aaaa' 0, 'bbbb' 10, 'cccc' 20",
   to: "'aaaa' 10, 'bbbb' 20, 'cccc' 30",
+  comparisonFunction: compareFontVariationSettings,
 }, [
   {at: -0.5, expect: "'aaaa' -5, 'bbbb' 5, 'cccc' 15"},
   {at: 0, expect: "'aaaa' 0, 'bbbb' 10, 'cccc' 20"},
@@ -97,6 +115,21 @@
   {at: 1.5, expect: "'aaaa' 15, 'bbbb' 25, 'cccc' 35"},
 ]);
 
+// font-variation-settings is a map, so any order works.
+test_interpolation({
+  property: 'font-variation-settings',
+  from: "'aaaa' 0, 'bbbb' 10, 'cccc' 20",
+  to: "'cccc' 10, 'bbbb' 20, 'aaaa' 30",
+  comparisonFunction: compareFontVariationSettings,
+}, [
+  {at: -0.5, expect: "'aaaa' -15, 'bbbb' 5, 'cccc' 25"},
+  {at: 0, expect: "'aaaa' 0, 'bbbb' 10, 'cccc' 20"},
+  {at: 0.3, expect: "'aaaa' 9, 'bbbb' 13, 'cccc' 17"},
+  {at: 0.7, expect: "'aaaa' 21, 'bbbb' 17, 'cccc' 13"},
+  {at: 1, expect: "'aaaa' 30, 'bbbb' 20, 'cccc' 10"},
+  {at: 1.5, expect: "'aaaa' 45, 'bbbb' 25, 'cccc' 5"},
+]);
+
 test_no_interpolation({
   property: 'font-variation-settings',
   from: "'aaaa' 0, 'bbbb' 10",
@@ -112,12 +145,6 @@
 test_no_interpolation({
   property: 'font-variation-settings',
   from: "'aaaa' 0, 'bbbb' 10, 'cccc' 20",
-  to: "'cccc' 10, 'bbbb' 20, 'aaaa' 30",
-});
-
-test_no_interpolation({
-  property: 'font-variation-settings',
-  from: "'aaaa' 0, 'bbbb' 10, 'cccc' 20",
   to: "'dddd' 10, 'eeee' 20, 'ffff' 30",
 });
 
@@ -126,7 +153,9 @@
   property: 'font-variation-settings',
   from: "'aaaa' 30, 'bbbb' 20",
   to: "'aaaa' 20, 'bbbb' 30",
+  comparisonFunction: compareFontVariationSettings,
 }, [
   {at: 3.40282e+38, expect: "'aaaa' -3.40282e+38, 'bbbb' 3.40282e+38"},
 ]);
+
 </script>
diff --git a/css/support/interpolation-testcommon.js b/css/support/interpolation-testcommon.js
index 62f4079..e7ee011 100644
--- a/css/support/interpolation-testcommon.js
+++ b/css/support/interpolation-testcommon.js
@@ -11,14 +11,12 @@
     return keyframe === neutralKeyframe;
   }
 
-  // For all the CSS interpolation methods, we set the animation duration very
-  // very long so that any advancement in time that does happen is irrelevant
-  // in terms of the progress value. In particular, the animation duration is
-  // 2e9s which is ~63 years.
-  // We then set the delay to be *negative* half the duration, so we are
-  // immediately at the halfway point of the animation. Finally, we using an
-  // easing function that maps halfway (0.5) to whatever progress we actually
-  // want.
+  // For the CSS interpolation methods, we set the animation duration long
+  // enough that any advancement in time during the test is irrelevant in terms
+  // of the progress. We then set the delay to be negative half the duration, so
+  // we are immediately at the halfway point of the animation. Finally, we use
+  // an easing function that maps halfway to whatever progress we actually want.
+
   var cssAnimationsInterpolation = {
     name: 'CSS Animations',
     supportsProperty: function() {return true;},
@@ -233,12 +231,15 @@
     var property = interpolationTest.options.property;
     var from = interpolationTest.options.from;
     var to = interpolationTest.options.to;
+    var comparisonFunction = interpolationTest.options.comparisonFunction;
+
     if ((interpolationTest.options.method && interpolationTest.options.method != interpolationMethod.name)
       || !interpolationMethod.supportsProperty(property)
       || !interpolationMethod.supportsValue(from)
       || !interpolationMethod.supportsValue(to)) {
       return;
     }
+
     var testText = `${interpolationMethod.name}: property <${property}> from ${keyframeText(from)} to ${keyframeText(to)}`;
     var testContainer = createElement(interpolationMethodContainer, 'div');
     createElement(testContainer);
@@ -246,6 +247,14 @@
     if (expectations === expectNoInterpolation) {
       expectations = interpolationMethod.nonInterpolationExpectations(from, to);
     }
+
+    // Setup a standard equality function if an override is not provided.
+    if (!comparisonFunction) {
+      comparisonFunction = (actual, expected) => {
+        assert_equals(normalizeValue(actual), normalizeValue(expected));
+      };
+    }
+
     return expectations.map(function(expectation) {
       var actualTargetContainer = createTargetContainer(testContainer, 'actual');
       var expectedTargetContainer = createTargetContainer(testContainer, 'expected');
@@ -270,9 +279,9 @@
             assert_true(CSS.supports(property, underlying), '\'underlying\' value should be supported');
           }
 
-          assert_equals(
-            normalizeValue(getComputedStyle(target).getPropertyValue(property)),
-            normalizeValue(expectedValue));
+          comparisonFunction(
+              getComputedStyle(target).getPropertyValue(property),
+              expectedValue);
         }, `${testText} at (${expectation.at}) should be [${sanitizeUrls(expectedValue)}]`);
       };
       return target;
@@ -314,6 +323,7 @@
     container.remove();
     interpolationTests = [];
   }
+
   window.test_interpolation = test_interpolation;
   window.test_no_interpolation = test_no_interpolation;
   window.neutralKeyframe = neutralKeyframe;