Index: third_party/WebKit/Source/platform/inspector_protocol/generate-inspector-protocol-version |
diff --git a/third_party/WebKit/Source/platform/inspector_protocol/generate-inspector-protocol-version b/third_party/WebKit/Source/platform/inspector_protocol/generate-inspector-protocol-version |
deleted file mode 100755 |
index 8c13092541378d46aec11f7ebde98ce95453f25b..0000000000000000000000000000000000000000 |
--- a/third_party/WebKit/Source/platform/inspector_protocol/generate-inspector-protocol-version |
+++ /dev/null |
@@ -1,483 +0,0 @@ |
-#!/usr/bin/env python |
-# Copyright (c) 2011 Google Inc. All rights reserved. |
-# |
-# Redistribution and use in source and binary forms, with or without |
-# modification, are permitted provided that the following conditions are |
-# met: |
-# |
-# * Redistributions of source code must retain the above copyright |
-# notice, this list of conditions and the following disclaimer. |
-# * Redistributions in binary form must reproduce the above |
-# copyright notice, this list of conditions and the following disclaimer |
-# in the documentation and/or other materials provided with the |
-# distribution. |
-# * Neither the name of Google Inc. nor the names of its |
-# contributors may be used to endorse or promote products derived from |
-# this software without specific prior written permission. |
-# |
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
-# |
-# Inspector protocol validator. |
-# |
-# Tests that subsequent protocol changes are not breaking backwards compatibility. |
-# Following violations are reported: |
-# |
-# - Domain has been removed |
-# - Command has been removed |
-# - Required command parameter was added or changed from optional |
-# - Required response parameter was removed or changed to optional |
-# - Event has been removed |
-# - Required event parameter was removed or changed to optional |
-# - Parameter type has changed. |
-# |
-# For the parameters with composite types the above checks are also applied |
-# recursively to every property of the type. |
-# |
-# Adding --show_changes to the command line prints out a list of valid public API changes. |
- |
-import collections |
-import copy |
-import os.path |
-import optparse |
-import re |
-import sys |
- |
-try: |
- import json |
-except ImportError: |
- import simplejson as json |
- |
-def list_to_map(items, key): |
- result = {} |
- for item in items: |
- if not "experimental" in item and not "hidden" in item: |
- result[item[key]] = item |
- return result |
- |
- |
-def named_list_to_map(container, name, key): |
- if name in container: |
- return list_to_map(container[name], key) |
- return {} |
- |
- |
-def removed(reverse): |
- if reverse: |
- return "added" |
- return "removed" |
- |
- |
-def required(reverse): |
- if reverse: |
- return "optional" |
- return "required" |
- |
- |
-def compare_schemas(d_1, d_2, reverse): |
- errors = [] |
- domains_1 = copy.deepcopy(d_1) |
- domains_2 = copy.deepcopy(d_2) |
- types_1 = normalize_types_in_schema(domains_1) |
- types_2 = normalize_types_in_schema(domains_2) |
- |
- domains_by_name_1 = list_to_map(domains_1, "domain") |
- domains_by_name_2 = list_to_map(domains_2, "domain") |
- |
- for name in domains_by_name_1: |
- domain_1 = domains_by_name_1[name] |
- if not name in domains_by_name_2: |
- errors.append("%s: domain has been %s" % (name, removed(reverse))) |
- continue |
- compare_domains(domain_1, domains_by_name_2[name], types_1, types_2, errors, reverse) |
- return errors |
- |
- |
-def compare_domains(domain_1, domain_2, types_map_1, types_map_2, errors, reverse): |
- domain_name = domain_1["domain"] |
- commands_1 = named_list_to_map(domain_1, "commands", "name") |
- commands_2 = named_list_to_map(domain_2, "commands", "name") |
- for name in commands_1: |
- command_1 = commands_1[name] |
- if not name in commands_2: |
- errors.append("%s.%s: command has been %s" % (domain_1["domain"], name, removed(reverse))) |
- continue |
- compare_commands(domain_name, command_1, commands_2[name], types_map_1, types_map_2, errors, reverse) |
- |
- events_1 = named_list_to_map(domain_1, "events", "name") |
- events_2 = named_list_to_map(domain_2, "events", "name") |
- for name in events_1: |
- event_1 = events_1[name] |
- if not name in events_2: |
- errors.append("%s.%s: event has been %s" % (domain_1["domain"], name, removed(reverse))) |
- continue |
- compare_events(domain_name, event_1, events_2[name], types_map_1, types_map_2, errors, reverse) |
- |
- |
-def compare_commands(domain_name, command_1, command_2, types_map_1, types_map_2, errors, reverse): |
- context = domain_name + "." + command_1["name"] |
- |
- params_1 = named_list_to_map(command_1, "parameters", "name") |
- params_2 = named_list_to_map(command_2, "parameters", "name") |
- # Note the reversed order: we allow removing but forbid adding parameters. |
- compare_params_list(context, "parameter", params_2, params_1, types_map_2, types_map_1, 0, errors, not reverse) |
- |
- returns_1 = named_list_to_map(command_1, "returns", "name") |
- returns_2 = named_list_to_map(command_2, "returns", "name") |
- compare_params_list(context, "response parameter", returns_1, returns_2, types_map_1, types_map_2, 0, errors, reverse) |
- |
- |
-def compare_events(domain_name, event_1, event_2, types_map_1, types_map_2, errors, reverse): |
- context = domain_name + "." + event_1["name"] |
- params_1 = named_list_to_map(event_1, "parameters", "name") |
- params_2 = named_list_to_map(event_2, "parameters", "name") |
- compare_params_list(context, "parameter", params_1, params_2, types_map_1, types_map_2, 0, errors, reverse) |
- |
- |
-def compare_params_list(context, kind, params_1, params_2, types_map_1, types_map_2, depth, errors, reverse): |
- for name in params_1: |
- param_1 = params_1[name] |
- if not name in params_2: |
- if not "optional" in param_1: |
- errors.append("%s.%s: required %s has been %s" % (context, name, kind, removed(reverse))) |
- continue |
- |
- param_2 = params_2[name] |
- if param_2 and "optional" in param_2 and not "optional" in param_1: |
- errors.append("%s.%s: %s %s is now %s" % (context, name, required(reverse), kind, required(not reverse))) |
- continue |
- type_1 = extract_type(param_1, types_map_1, errors) |
- type_2 = extract_type(param_2, types_map_2, errors) |
- compare_types(context + "." + name, kind, type_1, type_2, types_map_1, types_map_2, depth, errors, reverse) |
- |
- |
-def compare_types(context, kind, type_1, type_2, types_map_1, types_map_2, depth, errors, reverse): |
- if depth > 10: |
- return |
- |
- base_type_1 = type_1["type"] |
- base_type_2 = type_2["type"] |
- |
- if base_type_1 != base_type_2: |
- errors.append("%s: %s base type mismatch, '%s' vs '%s'" % (context, kind, base_type_1, base_type_2)) |
- elif base_type_1 == "object": |
- params_1 = named_list_to_map(type_1, "properties", "name") |
- params_2 = named_list_to_map(type_2, "properties", "name") |
- # If both parameters have the same named type use it in the context. |
- if "id" in type_1 and "id" in type_2 and type_1["id"] == type_2["id"]: |
- type_name = type_1["id"] |
- else: |
- type_name = "<object>" |
- context += " %s->%s" % (kind, type_name) |
- compare_params_list(context, "property", params_1, params_2, types_map_1, types_map_2, depth + 1, errors, reverse) |
- elif base_type_1 == "array": |
- item_type_1 = extract_type(type_1["items"], types_map_1, errors) |
- item_type_2 = extract_type(type_2["items"], types_map_2, errors) |
- compare_types(context, kind, item_type_1, item_type_2, types_map_1, types_map_2, depth + 1, errors, reverse) |
- |
- |
-def extract_type(typed_object, types_map, errors): |
- if "type" in typed_object: |
- result = { "id": "<transient>", "type": typed_object["type"] } |
- if typed_object["type"] == "object": |
- result["properties"] = [] |
- elif typed_object["type"] == "array": |
- result["items"] = typed_object["items"] |
- return result |
- elif "$ref" in typed_object: |
- ref = typed_object["$ref"] |
- if not ref in types_map: |
- errors.append("Can not resolve type: %s" % ref) |
- types_map[ref] = { "id": "<transient>", "type": "object" } |
- return types_map[ref] |
- |
- |
-def normalize_types_in_schema(domains): |
- types = {} |
- for domain in domains: |
- domain_name = domain["domain"] |
- normalize_types(domain, domain_name, types) |
- return types |
- |
- |
-def normalize_types(obj, domain_name, types): |
- if isinstance(obj, list): |
- for item in obj: |
- normalize_types(item, domain_name, types) |
- elif isinstance(obj, dict): |
- for key, value in obj.items(): |
- if key == "$ref" and value.find(".") == -1: |
- obj[key] = "%s.%s" % (domain_name, value) |
- elif key == "id": |
- obj[key] = "%s.%s" % (domain_name, value) |
- types[obj[key]] = obj |
- else: |
- normalize_types(value, domain_name, types) |
- |
- |
-def load_schema(file, domains): |
- if not os.path.isfile(file): |
- return |
- input_file = open(file, "r") |
- json_string = input_file.read() |
- parsed_json = json.loads(json_string) |
- domains += parsed_json["domains"] |
- return parsed_json["version"] |
- |
- |
-def self_test(): |
- def create_test_schema_1(): |
- return [ |
- { |
- "domain": "Network", |
- "types": [ |
- { |
- "id": "LoaderId", |
- "type": "string" |
- }, |
- { |
- "id": "Headers", |
- "type": "object" |
- }, |
- { |
- "id": "Request", |
- "type": "object", |
- "properties": [ |
- { "name": "url", "type": "string" }, |
- { "name": "method", "type": "string" }, |
- { "name": "headers", "$ref": "Headers" }, |
- { "name": "becameOptionalField", "type": "string" }, |
- { "name": "removedField", "type": "string" }, |
- ] |
- } |
- ], |
- "commands": [ |
- { |
- "name": "removedCommand", |
- }, |
- { |
- "name": "setExtraHTTPHeaders", |
- "parameters": [ |
- { "name": "headers", "$ref": "Headers" }, |
- { "name": "mismatched", "type": "string" }, |
- { "name": "becameOptional", "$ref": "Headers" }, |
- { "name": "removedRequired", "$ref": "Headers" }, |
- { "name": "becameRequired", "$ref": "Headers", "optional": True }, |
- { "name": "removedOptional", "$ref": "Headers", "optional": True }, |
- ], |
- "returns": [ |
- { "name": "mimeType", "type": "string" }, |
- { "name": "becameOptional", "type": "string" }, |
- { "name": "removedRequired", "type": "string" }, |
- { "name": "becameRequired", "type": "string", "optional": True }, |
- { "name": "removedOptional", "type": "string", "optional": True }, |
- ] |
- } |
- ], |
- "events": [ |
- { |
- "name": "requestWillBeSent", |
- "parameters": [ |
- { "name": "frameId", "type": "string", "experimental": True }, |
- { "name": "request", "$ref": "Request" }, |
- { "name": "becameOptional", "type": "string" }, |
- { "name": "removedRequired", "type": "string" }, |
- { "name": "becameRequired", "type": "string", "optional": True }, |
- { "name": "removedOptional", "type": "string", "optional": True }, |
- ] |
- }, |
- { |
- "name": "removedEvent", |
- "parameters": [ |
- { "name": "errorText", "type": "string" }, |
- { "name": "canceled", "type": "boolean", "optional": True } |
- ] |
- } |
- ] |
- }, |
- { |
- "domain": "removedDomain" |
- } |
- ] |
- |
- def create_test_schema_2(): |
- return [ |
- { |
- "domain": "Network", |
- "types": [ |
- { |
- "id": "LoaderId", |
- "type": "string" |
- }, |
- { |
- "id": "Request", |
- "type": "object", |
- "properties": [ |
- { "name": "url", "type": "string" }, |
- { "name": "method", "type": "string" }, |
- { "name": "headers", "type": "object" }, |
- { "name": "becameOptionalField", "type": "string", "optional": True }, |
- ] |
- } |
- ], |
- "commands": [ |
- { |
- "name": "addedCommand", |
- }, |
- { |
- "name": "setExtraHTTPHeaders", |
- "parameters": [ |
- { "name": "headers", "type": "object" }, |
- { "name": "mismatched", "type": "object" }, |
- { "name": "becameOptional", "type": "object" , "optional": True }, |
- { "name": "addedRequired", "type": "object" }, |
- { "name": "becameRequired", "type": "object" }, |
- { "name": "addedOptional", "type": "object", "optional": True }, |
- ], |
- "returns": [ |
- { "name": "mimeType", "type": "string" }, |
- { "name": "becameOptional", "type": "string", "optional": True }, |
- { "name": "addedRequired", "type": "string"}, |
- { "name": "becameRequired", "type": "string" }, |
- { "name": "addedOptional", "type": "string", "optional": True }, |
- ] |
- } |
- ], |
- "events": [ |
- { |
- "name": "requestWillBeSent", |
- "parameters": [ |
- { "name": "request", "$ref": "Request" }, |
- { "name": "becameOptional", "type": "string", "optional": True }, |
- { "name": "addedRequired", "type": "string"}, |
- { "name": "becameRequired", "type": "string" }, |
- { "name": "addedOptional", "type": "string", "optional": True }, |
- ] |
- }, |
- { |
- "name": "addedEvent" |
- } |
- ] |
- }, |
- { |
- "domain": "addedDomain" |
- } |
- ] |
- |
- expected_errors = [ |
- "removedDomain: domain has been removed", |
- "Network.removedCommand: command has been removed", |
- "Network.removedEvent: event has been removed", |
- "Network.setExtraHTTPHeaders.mismatched: parameter base type mismatch, 'object' vs 'string'", |
- "Network.setExtraHTTPHeaders.addedRequired: required parameter has been added", |
- "Network.setExtraHTTPHeaders.becameRequired: optional parameter is now required", |
- "Network.setExtraHTTPHeaders.removedRequired: required response parameter has been removed", |
- "Network.setExtraHTTPHeaders.becameOptional: required response parameter is now optional", |
- "Network.requestWillBeSent.removedRequired: required parameter has been removed", |
- "Network.requestWillBeSent.becameOptional: required parameter is now optional", |
- "Network.requestWillBeSent.request parameter->Network.Request.removedField: required property has been removed", |
- "Network.requestWillBeSent.request parameter->Network.Request.becameOptionalField: required property is now optional", |
- ] |
- |
- expected_errors_reverse = [ |
- "addedDomain: domain has been added", |
- "Network.addedEvent: event has been added", |
- "Network.addedCommand: command has been added", |
- "Network.setExtraHTTPHeaders.mismatched: parameter base type mismatch, 'string' vs 'object'", |
- "Network.setExtraHTTPHeaders.removedRequired: required parameter has been removed", |
- "Network.setExtraHTTPHeaders.becameOptional: required parameter is now optional", |
- "Network.setExtraHTTPHeaders.addedRequired: required response parameter has been added", |
- "Network.setExtraHTTPHeaders.becameRequired: optional response parameter is now required", |
- "Network.requestWillBeSent.becameRequired: optional parameter is now required", |
- "Network.requestWillBeSent.addedRequired: required parameter has been added", |
- ] |
- |
- def is_subset(subset, superset, message): |
- for i in range(len(subset)): |
- if subset[i] not in superset: |
- sys.stderr.write("%s error: %s\n" % (message, subset[i])) |
- return False |
- return True |
- |
- def errors_match(expected, actual): |
- return (is_subset(actual, expected, "Unexpected") and |
- is_subset(expected, actual, "Missing")) |
- |
- return (errors_match(expected_errors, |
- compare_schemas(create_test_schema_1(), create_test_schema_2(), False)) and |
- errors_match(expected_errors_reverse, |
- compare_schemas(create_test_schema_2(), create_test_schema_1(), True))) |
- |
- |
- |
-def load_domains_and_baselines(file, domains, baseline_domains): |
- version = load_schema(os.path.normpath(file), domains) |
- suffix = "-%s.%s.json" % (version["major"], version["minor"]) |
- baseline_file = file.replace(".json", suffix) |
- load_schema(os.path.normpath(baseline_file), baseline_domains) |
- return version |
- |
- |
-def main(): |
- if not self_test(): |
- sys.stderr.write("Self-test failed") |
- return 1 |
- |
- cmdline_parser = optparse.OptionParser() |
- cmdline_parser.add_option("--show_changes") |
- cmdline_parser.add_option("--o") |
- arg_options, arg_values = cmdline_parser.parse_args() |
- |
- if len(arg_values) < 1 or not arg_options.o: |
- sys.stderr.write("Usage: %s --o OUTPUT_FILE [--show_changes] PROTOCOL_FOLDER1 ?PROTOCOL_FOLDER2 \n" % sys.argv[0]) |
- return 1 |
- |
- output_path = arg_options.o |
- output_file = open(output_path, "w") |
- |
- domains = [] |
- baseline_domains = [] |
- version = load_domains_and_baselines(arg_values[0], domains, baseline_domains) |
- if len(arg_values) > 1: |
- load_domains_and_baselines(arg_values[1], domains, baseline_domains) |
- |
- expected_errors = [ |
- "Debugger.globalObjectCleared: event has been removed", |
- "Runtime.executionContextCreated.context parameter->Runtime.ExecutionContextDescription.frameId: required property has been removed", |
- "Debugger.canSetScriptSource: command has been removed", |
- "Console.messageRepeatCountUpdated: event has been removed", |
- "Console.messagesCleared: event has been removed" |
- ] |
- |
- errors = compare_schemas(baseline_domains, domains, False) |
- unexpected_errors = [] |
- for i in range(len(errors)): |
- if errors[i] not in expected_errors: |
- unexpected_errors.append(errors[i]) |
- if len(unexpected_errors) > 0: |
- sys.stderr.write(" Compatibility checks FAILED\n") |
- for error in unexpected_errors: |
- sys.stderr.write( " %s\n" % error) |
- return 1 |
- |
- if arg_options.show_changes: |
- changes = compare_schemas(domains, baseline_domains, True) |
- if len(changes) > 0: |
- print " Public changes since %s:" % version |
- for change in changes: |
- print " %s" % change |
- |
- json.dump({"version": version, "domains": domains}, output_file, indent=4, sort_keys=False, separators=(',', ': ')) |
- output_file.close() |
- |
-if __name__ == '__main__': |
- sys.exit(main()) |