Bug 1290988 - Take into account prefs for the CSS properties database. r=tromey
authorGreg Tatum <tatum.creative@gmail.com>
Wed, 14 Sep 2016 10:00:27 -0500
changeset 355446 7d70ac7d03de8f0d2097b8681e811d38545287fa
parent 355445 6ef033c9dcc34591e036aa2c94fa4afef4890330
child 355447 e7da6eac37d3e0c3b2d7c07a3b91ff6f3bcb9bda
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstromey
bugs1290988
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1290988 - Take into account prefs for the CSS properties database. r=tromey This test was causing uplifts to fail because certain CSS properties were disabled via preferences, and the devtools client and platform were out of sync with what properties were supported. This test now uses the preference information to allow in-development features to not break this test. MozReview-Commit-ID: 767xRFMHyw9
devtools/shared/tests/unit/test_css-properties-db.js
--- a/devtools/shared/tests/unit/test_css-properties-db.js
+++ b/devtools/shared/tests/unit/test_css-properties-db.js
@@ -1,48 +1,156 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-// Test that the devtool's client-side css-properties-db matches the values on the
-// platform.
+/**
+ * Test that the devtool's client-side CSS properties database is in sync with the values
+ * on the platform. If they are not, then `mach generate-css-db` needs to be run to
+ * make everything up to date. Nightly, aurora, beta, and release may have different
+ * preferences for what CSS values are enabled. The static CSS properties database can
+ * be slightly different from the target platform as long as there is a preference that
+ * exists that turns off that CSS property.
+ */
 
 "use strict";
 
 const DOMUtils = Components.classes["@mozilla.org/inspector/dom-utils;1"]
                            .getService(Components.interfaces.inIDOMUtils);
 
-const {PSEUDO_ELEMENTS, CSS_PROPERTIES} = require("devtools/shared/css/properties-db");
+const {PSEUDO_ELEMENTS, CSS_PROPERTIES, PREFERENCES} = require("devtools/shared/css/generated/properties-db");
 const {generateCssProperties} = require("devtools/server/actors/css-properties");
+const { Preferences } = require("resource://gre/modules/Preferences.jsm");
 
 function run_test() {
-  // Check that the platform and client match for pseudo elements.
-  deepEqual(PSEUDO_ELEMENTS, DOMUtils.getCSSPseudoElementNames(),
-            "If this assertion fails, then the client side CSS pseudo elements list in " +
-            "devtools is out of date with the pseudo elements on the platform. To fix " +
-            "this assertion open devtools/shared/css/properties-db.js and follow the " +
-            "instructions above the CSS_PSEUDO_ELEMENTS on how to re-generate the list.");
+  const propertiesErrorMessage = "If this assertion fails, then the client side CSS " +
+                                 "properties list in devtools is out of sync with the " +
+                                 "CSS properties on the platform. To fix this " +
+                                 "assertion run `mach generate-css-db` to re-generate " +
+                                 "the client side properties.";
 
-  const propertiesErrorMessage = "If this assertion fails, then the client side CSS " +
-                                 "properties list in devtools is out of date with the " +
-                                 "CSS properties on the platform. To fix this " +
-                                 "assertion open devtools/shared/css/properties-db.js " +
-                                 "and follow the instructions above the CSS_PROPERTIES " +
-                                 "on how to re-generate the list.";
+  // Check that the platform and client match for pseudo elements.
+  deepEqual(PSEUDO_ELEMENTS, DOMUtils.getCSSPseudoElementNames(), `The pseudo elements ` +
+            `match on the client and platform. ${propertiesErrorMessage}`);
 
-  // Check that the platform and client match for CSS properties. Enumerate each property
-  // to aid in debugging.
+  /**
+   * Check that the platform and client match for the details on their CSS properties.
+   * Enumerate each property to aid in debugging. Sometimes these properties don't
+   * completely agree due to differences in preferences. Check the currently set
+   * preference for that property to see if it's enabled.
+   */
   const platformProperties = generateCssProperties();
+
   for (let propertyName in CSS_PROPERTIES) {
     const platformProperty = platformProperties[propertyName];
     const clientProperty = CSS_PROPERTIES[propertyName];
-    deepEqual(platformProperty, clientProperty,
-      `Client and server match for "${propertyName}". ${propertiesErrorMessage}\n`);
+    const deepEqual = isJsonDeepEqual(platformProperty, clientProperty);
+
+    if (deepEqual) {
+      ok(true, `The static database and platform match for "${propertyName}".`);
+    } else {
+      const prefMessage = `The static database and platform do not match ` +
+                          `for "${propertyName}".`;
+      if (getPreference(propertyName) === false) {
+        ok(true, `${prefMessage} However, there is a preference for disabling this ` +
+                 `property on the current build.`);
+      } else {
+        ok(false, `${prefMessage} ${propertiesErrorMessage}`);
+      }
+    }
+  }
+
+  /**
+   * Check that the list of properties on the platform and client are the same. If
+   * they are not, check that there may be preferences that are disabling them on the
+   * target platform.
+   */
+  const mismatches = getKeyMismatches(platformProperties, CSS_PROPERTIES)
+    // Filter out OS-specific properties.
+    .filter(name => name.indexOf("-moz-osx-") === -1);
+
+  if (mismatches.length === 0) {
+    ok(true, "No client and platform CSS property database mismatches were found.");
+  }
+
+  mismatches.forEach(propertyName => {
+    if (getPreference(propertyName) === false) {
+      ok(true, `The static database and platform do not agree on the property ` +
+               `"${propertyName}" This is ok because it is currently disabled through ` +
+               `a preference.`);
+    } else {
+      ok(false, `The static database and platform do not agree on the property ` +
+                `"${propertyName}" ${propertiesErrorMessage}`);
+    }
+  });
+}
+
+/**
+ * Check JSON-serializable objects for deep equality.
+ */
+function isJsonDeepEqual(a, b) {
+  // Handle primitives.
+  if (a === b) {
+    return true;
   }
 
-  // Filter out OS-specific properties.
-  const platformPropertyNames = Object.keys(platformProperties).filter(
-    name => name.indexOf("-moz-osx-") === -1);
-  const clientPlatformNames = Object.keys(CSS_PROPERTIES);
+  // Handle arrays.
+  if (Array.isArray(a) && Array.isArray(b)) {
+    if (a.length !== b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (!isJsonDeepEqual(a[i], b[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  // Handle objects
+  if (typeof a === "object" && typeof b === "object") {
+    for (let key in a) {
+      if (!isJsonDeepEqual(a[key], b[key])) {
+        return false;
+      }
+    }
+
+    return Object.keys(a).length === Object.keys(b).length;
+  }
+
+  // Not something handled by these cases, therefore not equal.
+  return false;
+}
 
-  deepEqual(platformPropertyNames, clientPlatformNames,
-        `The client side CSS properties database names match those found on the ` +
-        `platform. ${propertiesErrorMessage}`);
+/**
+ * Get the preference value of whether this property is enabled. Returns an empty string
+ * if no preference exists.
+ *
+ * @param {String} propertyName
+ * @return {Boolean|undefined}
+ */
+function getPreference(propertyName) {
+  const preference = PREFERENCES.find(([prefPropertyName, preferenceKey]) => {
+    return prefPropertyName === propertyName && !!preferenceKey;
+  });
+
+  if (preference) {
+    return Preferences.get(preference[1]);
+  }
+  return undefined;
 }
+
+/**
+ * Take the keys of two objects, and return the ones that don't match.
+ *
+ * @param {Object} a
+ * @param {Object} b
+ * @return {Array} keys
+ */
+function getKeyMismatches(a, b) {
+  const aNames = Object.keys(a);
+  const bNames = Object.keys(b);
+  const aMismatches = aNames.filter(key => !bNames.includes(key));
+  const bMismatches = bNames.filter(key => {
+    return !aNames.includes(key) && !aMismatches.includes(name);
+  });
+
+  return aMismatches.concat(bMismatches);
+}