servo: Merge #14092 - Sort check on JSON (from kivikakk:sort-check); r=Wafflespeanut
authorYuki Izumi <kivikakk@github.com>
Mon, 07 Nov 2016 07:41:34 -0600
changeset 340085 212737747389e0c7359182724edd02b3c5809987
parent 340084 7bf83aa43a825e1dc4bcc8e3f4731bab6ab3f2af
child 340086 bd248d0160f1e5f77abe116d004f0aa7efea20a6
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWafflespeanut
servo: Merge #14092 - Sort check on JSON (from kivikakk:sort-check); r=Wafflespeanut <!-- Please describe your changes on the following line: --> Check that JSON keys are ordered, and that there's no duplicates (for `resources/prefs.json` and `resources/package-prefs.json`). --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] 🆕 `./mach test-tidy --self-test` does not report any errors - [x] These changes fix #12283 <!-- Either: --> - [x] There are tests for these changes 🎉 <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 94d0c485e10138e0d5b2bd8b41b6a922a22a059f
servo/python/tidy/servo_tidy/tidy.py
servo/python/tidy/servo_tidy_tests/test_tidy.py
servo/python/tidy/servo_tidy_tests/unordered_key.json
servo/resources/package-prefs.json
servo/resources/prefs.json
servo/servo-tidy.toml
--- a/servo/python/tidy/servo_tidy/tidy.py
+++ b/servo/python/tidy/servo_tidy/tidy.py
@@ -22,16 +22,17 @@ import colorama
 import toml
 
 CONFIG_FILE_PATH = os.path.join(".", "servo-tidy.toml")
 
 # Default configs
 config = {
     "skip-check-length": False,
     "skip-check-licenses": False,
+    "check-ordered-json-keys": [],
     "ignore": {
         "files": [
             "./.",   # ignore hidden files
         ],
         "directories": [
             "./.",   # ignore hidden directories
         ],
         "packages": [],
@@ -631,33 +632,47 @@ def check_webidl_spec(file_name, content
     yield (0, "No specification link found.")
 
 
 def check_for_possible_duplicate_json_keys(key_value_pairs):
     keys = [x[0] for x in key_value_pairs]
     seen_keys = set()
     for key in keys:
         if key in seen_keys:
-            raise KeyError(key)
+            raise KeyError("Duplicated Key (%s)" % key)
 
         seen_keys.add(key)
 
 
+def check_for_alphabetical_sorted_json_keys(key_value_pairs):
+    for a, b in zip(key_value_pairs[:-1], key_value_pairs[1:]):
+        if a[0] > b[0]:
+            raise KeyError("Unordered key (found %s before %s)" % (a[0], b[0]))
+
+
+def check_json_requirements(filename):
+    def check_fn(key_value_pairs):
+        check_for_possible_duplicate_json_keys(key_value_pairs)
+        if filename in config["check-ordered-json-keys"]:
+            check_for_alphabetical_sorted_json_keys(key_value_pairs)
+    return check_fn
+
+
 def check_json(filename, contents):
     if not filename.endswith(".json"):
         raise StopIteration
 
     try:
-        json.loads(contents, object_pairs_hook=check_for_possible_duplicate_json_keys)
+        json.loads(contents, object_pairs_hook=check_json_requirements(filename))
     except ValueError as e:
         match = re.search(r"line (\d+) ", e.message)
         line_no = match and match.group(1)
         yield (line_no, e.message)
     except KeyError as e:
-        yield (None, "Duplicated Key (%s)" % e.message)
+        yield (None, e.message)
 
 
 def check_spec(file_name, lines):
     if SPEC_BASE_PATH not in file_name:
         raise StopIteration
     file_name = os.path.relpath(os.path.splitext(file_name)[0], SPEC_BASE_PATH)
     patt = re.compile("^\s*\/\/.+")
 
--- a/servo/python/tidy/servo_tidy_tests/test_tidy.py
+++ b/servo/python/tidy/servo_tidy_tests/test_tidy.py
@@ -166,16 +166,22 @@ class CheckTidiness(unittest.TestCase):
         self.assertEqual('Invalid control character at: line 3 column 40 (char 61)', errors.next()[2])
         self.assertNoMoreErrors(errors)
 
     def test_json_with_duplicate_key(self):
         errors = tidy.collect_errors_for_files(iterFile('duplicate_key.json'), [tidy.check_json], [], print_text=False)
         self.assertEqual('Duplicated Key (the_duplicated_key)', errors.next()[2])
         self.assertNoMoreErrors(errors)
 
+    def test_json_with_unordered_keys(self):
+        tidy.config["check-ordered-json-keys"].append('python/tidy/servo_tidy_tests/unordered_key.json')
+        errors = tidy.collect_errors_for_files(iterFile('unordered_key.json'), [tidy.check_json], [], print_text=False)
+        self.assertEqual('Unordered key (found b before a)', errors.next()[2])
+        self.assertNoMoreErrors(errors)
+
     def test_lock(self):
         errors = tidy.collect_errors_for_files(iterFile('duplicated_package.lock'), [tidy.check_lock], [], print_text=False)
         msg = """duplicate versions for package "test"
 \t\033[93mfound dependency on version 0.4.9\033[0m
 \t\033[91mbut highest version is 0.5.1\033[0m
 \t\033[93mtry upgrading with\033[0m \033[96m./mach cargo-update -p test:0.4.9\033[0m
 \tThe following packages depend on version 0.4.9:
 \t\ttest2"""
new file mode 100644
--- /dev/null
+++ b/servo/python/tidy/servo_tidy_tests/unordered_key.json
@@ -0,0 +1,7 @@
+{
+    "key": "value",
+    "other_key": {
+        "b": 1,
+        "a": 2
+    }
+}
--- a/servo/resources/package-prefs.json
+++ b/servo/resources/package-prefs.json
@@ -2,61 +2,61 @@
   "dom.bluetooth.enabled": false,
   "dom.bluetooth.testing.enabled": false,
   "dom.forcetouch.enabled": true,
   "dom.mouseevent.which.enabled": false,
   "dom.mozbrowser.enabled": true,
   "dom.serviceworker.timeout_seconds": 60,
   "dom.testable_crash.enabled": false,
   "dom.testbinding.enabled": false,
+  "js.asmjs.enabled": true,
+  "js.asyncstack.enabled": false,
   "js.baseline.enabled": true,
-  "js.ion.enabled": true,
-  "js.asmjs.enabled": true,
-  "js.strict.enabled": false,
-  "js.strict.debug.enabled": false,
-  "js.throw_on_asmjs_validation_failure.enabled": false,
-  "js.native_regexp.enabled": true,
-  "js.parallel_parsing.enabled": true,
-  "js.ion.offthread_compilation.enabled": true,
   "js.baseline.unsafe_eager_compilation.enabled": false,
-  "js.ion.unsafe_eager_compilation.enabled": false,
   "js.discard_system_source.enabled": false,
-  "js.asyncstack.enabled": false,
-  "js.throw_on_debuggee_would_run.enabled": false,
   "js.dump_stack_on_debuggee_would_run.enabled": false,
-  "js.werror.enabled": false,
-  "js.shared_memory.enabled": true,
-  "js.mem.high_water_mark": 128,
-  "js.mem.max": -1,
-  "js.mem.gc.per_compartment.enabled": true,
+  "js.ion.enabled": true,
+  "js.ion.offthread_compilation.enabled": true,
+  "js.ion.unsafe_eager_compilation.enabled": false,
+  "js.mem.gc.allocation_threshold_mb": 30,
+  "js.mem.gc.compacting.enabled": true,
+  "js.mem.gc.decommit_threshold_mb": 32,
+  "js.mem.gc.dynamic_heap_growth.enabled": true,
+  "js.mem.gc.dynamic_mark_slice.enabled": true,
+  "js.mem.gc.empty_chunk_count_max": 30,
+  "js.mem.gc.empty_chunk_count_min": 1,
+  "js.mem.gc.high_frequency_heap_growth_max": 300,
+  "js.mem.gc.high_frequency_heap_growth_min": 150,
+  "js.mem.gc.high_frequency_high_limit_mb": 500,
+  "js.mem.gc.high_frequency_low_limit_mb": 100,
+  "js.mem.gc.high_frequency_time_limit_ms": 1000,
   "js.mem.gc.incremental.enabled": true,
   "js.mem.gc.incremental.slice_ms": 10,
-  "js.mem.gc.compacting.enabled": true,
-  "js.mem.gc.high_frequency_time_limit_ms": 1000,
-  "js.mem.gc.dynamic_mark_slice.enabled": true,
+  "js.mem.gc.low_frequency_heap_growth": 150,
+  "js.mem.gc.per_compartment.enabled": true,
   "js.mem.gc.refresh_frame_slices.enabled": true,
-  "js.mem.gc.dynamic_heap_growth.enabled": true,
-  "js.mem.gc.low_frequency_heap_growth": 150,
-  "js.mem.gc.high_frequency_heap_growth_min": 150,
-  "js.mem.gc.high_frequency_heap_growth_max": 300,
-  "js.mem.gc.high_frequency_low_limit_mb": 100,
-  "js.mem.gc.high_frequency_high_limit_mb": 500,
-  "js.mem.gc.allocation_threshold_mb": 30,
-  "js.mem.gc.decommit_threshold_mb": 32,
-  "js.mem.gc.empty_chunk_count_min": 1,
-  "js.mem.gc.empty_chunk_count_max": 30,
+  "js.mem.gc.zeal.frequency": 100,
   "js.mem.gc.zeal.level": 0,
-  "js.mem.gc.zeal.frequency": 100,
-  "layout.columns.enabled": false,
-  "layout.column-width.enabled": false,
+  "js.mem.high_water_mark": 128,
+  "js.mem.max": -1,
+  "js.native_regexp.enabled": true,
+  "js.parallel_parsing.enabled": true,
+  "js.shared_memory.enabled": true,
+  "js.strict.debug.enabled": false,
+  "js.strict.enabled": false,
+  "js.throw_on_asmjs_validation_failure.enabled": false,
+  "js.throw_on_debuggee_would_run.enabled": false,
+  "js.werror.enabled": false,
   "layout.column-count.enabled": false,
   "layout.column-gap.enabled": false,
+  "layout.column-width.enabled": false,
+  "layout.columns.enabled": false,
+  "layout.flex-direction.enabled": false,
   "layout.flex.enabled": false,
-  "layout.flex-direction.enabled": false,
   "layout.text-orientation.enabled": false,
   "layout.viewport.enabled": false,
   "layout.writing-mode.enabled": false,
   "network.http.redirection-limit": 20,
   "network.mime.sniff": false,
+  "shell.builtin-key-shortcuts.enabled": false,
   "shell.homepage": "https://servo.org",
-  "shell.native-titlebar.enabled": false,
-  "shell.builtin-key-shortcuts.enabled": false
+  "shell.native-titlebar.enabled": false
 }
--- a/servo/resources/prefs.json
+++ b/servo/resources/prefs.json
@@ -2,62 +2,62 @@
   "dom.bluetooth.enabled": false,
   "dom.bluetooth.testing.enabled": false,
   "dom.forcetouch.enabled": false,
   "dom.mouseevent.which.enabled": false,
   "dom.mozbrowser.enabled": false,
   "dom.serviceworker.timeout_seconds": 60,
   "dom.testable_crash.enabled": false,
   "dom.testbinding.enabled": false,
+  "js.asmjs.enabled": true,
+  "js.asyncstack.enabled": false,
   "js.baseline.enabled": true,
-  "js.ion.enabled": true,
-  "js.asmjs.enabled": true,
-  "js.strict.enabled": false,
-  "js.strict.debug.enabled": false,
-  "js.throw_on_asmjs_validation_failure.enabled": false,
-  "js.native_regexp.enabled": true,
-  "js.parallel_parsing.enabled": true,
-  "js.ion.offthread_compilation.enabled": true,
   "js.baseline.unsafe_eager_compilation.enabled": false,
-  "js.ion.unsafe_eager_compilation.enabled": false,
   "js.discard_system_source.enabled": false,
-  "js.asyncstack.enabled": false,
-  "js.throw_on_debuggee_would_run.enabled": false,
   "js.dump_stack_on_debuggee_would_run.enabled": false,
-  "js.werror.enabled": false,
-  "js.shared_memory.enabled": true,
-  "js.mem.high_water_mark": 128,
-  "js.mem.max": -1,
-  "js.mem.gc.per_compartment.enabled": true,
+  "js.ion.enabled": true,
+  "js.ion.offthread_compilation.enabled": true,
+  "js.ion.unsafe_eager_compilation.enabled": false,
+  "js.mem.gc.allocation_threshold_mb": 30,
+  "js.mem.gc.compacting.enabled": true,
+  "js.mem.gc.decommit_threshold_mb": 32,
+  "js.mem.gc.dynamic_heap_growth.enabled": true,
+  "js.mem.gc.dynamic_mark_slice.enabled": true,
+  "js.mem.gc.empty_chunk_count_max": 30,
+  "js.mem.gc.empty_chunk_count_min": 1,
+  "js.mem.gc.high_frequency_heap_growth_max": 300,
+  "js.mem.gc.high_frequency_heap_growth_min": 150,
+  "js.mem.gc.high_frequency_high_limit_mb": 500,
+  "js.mem.gc.high_frequency_low_limit_mb": 100,
+  "js.mem.gc.high_frequency_time_limit_ms": 1000,
   "js.mem.gc.incremental.enabled": true,
   "js.mem.gc.incremental.slice_ms": 10,
-  "js.mem.gc.compacting.enabled": true,
-  "js.mem.gc.high_frequency_time_limit_ms": 1000,
-  "js.mem.gc.dynamic_mark_slice.enabled": true,
+  "js.mem.gc.low_frequency_heap_growth": 150,
+  "js.mem.gc.per_compartment.enabled": true,
   "js.mem.gc.refresh_frame_slices.enabled": true,
-  "js.mem.gc.dynamic_heap_growth.enabled": true,
-  "js.mem.gc.low_frequency_heap_growth": 150,
-  "js.mem.gc.high_frequency_heap_growth_min": 150,
-  "js.mem.gc.high_frequency_heap_growth_max": 300,
-  "js.mem.gc.high_frequency_low_limit_mb": 100,
-  "js.mem.gc.high_frequency_high_limit_mb": 500,
-  "js.mem.gc.allocation_threshold_mb": 30,
-  "js.mem.gc.decommit_threshold_mb": 32,
-  "js.mem.gc.empty_chunk_count_min": 1,
-  "js.mem.gc.empty_chunk_count_max": 30,
+  "js.mem.gc.zeal.frequency": 100,
   "js.mem.gc.zeal.level": 0,
-  "js.mem.gc.zeal.frequency": 100,
+  "js.mem.high_water_mark": 128,
+  "js.mem.max": -1,
+  "js.native_regexp.enabled": true,
+  "js.parallel_parsing.enabled": true,
+  "js.shared_memory.enabled": true,
+  "js.strict.debug.enabled": false,
+  "js.strict.enabled": false,
+  "js.throw_on_asmjs_validation_failure.enabled": false,
+  "js.throw_on_debuggee_would_run.enabled": false,
+  "js.werror.enabled": false,
   "layout.animations.test.enabled": false,
-  "layout.columns.enabled": false,
-  "layout.column-width.enabled": false,
   "layout.column-count.enabled": false,
   "layout.column-gap.enabled": false,
+  "layout.column-width.enabled": false,
+  "layout.columns.enabled": false,
+  "layout.flex-direction.enabled": false,
   "layout.flex.enabled": false,
-  "layout.flex-direction.enabled": false,
   "layout.text-orientation.enabled": false,
   "layout.viewport.enabled": false,
   "layout.writing-mode.enabled": false,
   "network.http.redirection-limit": 20,
   "network.mime.sniff": false,
+  "shell.builtin-key-shortcuts.enabled": true,
   "shell.homepage": "http://servo.org",
-  "shell.native-titlebar.enabled": true,
-  "shell.builtin-key-shortcuts.enabled": true
+  "shell.native-titlebar.enabled": true
 }
--- a/servo/servo-tidy.toml
+++ b/servo/servo-tidy.toml
@@ -1,11 +1,15 @@
 [configs]
 skip-check-length = false
 skip-check-licenses = false
+check-ordered-json-keys = [
+  "./resources/prefs.json",
+  "./resources/package-prefs.json",
+]
 
 [ignore]
 # Ignored packages with duplicated versions
 packages = ["lazy_static"]
 # Files that are ignored for all tidy and lint checks.
 files = [
   # Generated and upstream code combined with our own. Could use cleanup
   "./components/style/gecko_bindings/bindings.rs",