diff options
author | calamity@chromium.org <calamity@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-21 01:13:07 +0000 |
---|---|---|
committer | calamity@chromium.org <calamity@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-21 01:13:07 +0000 |
commit | 712eca0f458b38d5fe47c14932302ad3f14e292d (patch) | |
tree | 905236d46f0a4c471745ead8ad371910b89b5bd0 | |
parent | 17f5abff8f422bbfd63bfbb809a86464fd20f7ce (diff) | |
download | chromium_src-712eca0f458b38d5fe47c14932302ad3f14e292d.zip chromium_src-712eca0f458b38d5fe47c14932302ad3f14e292d.tar.gz chromium_src-712eca0f458b38d5fe47c14932302ad3f14e292d.tar.bz2 |
Add tests to tools/json_schema_compiler
Add tests for different json cases by compiling test jsons and running C++
tests against them. Also fixed bugs where tests failed, removed a dead flag and refactored for readability.
BUG=
TEST=
Review URL: http://codereview.chromium.org/9415001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122781 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/chrome_tests.gypi | 5 | ||||
-rw-r--r-- | tools/json_schema_compiler/cc_generator.py | 345 | ||||
-rw-r--r-- | tools/json_schema_compiler/compiler.py | 13 | ||||
-rw-r--r-- | tools/json_schema_compiler/cpp_type_generator.py | 3 | ||||
-rw-r--r-- | tools/json_schema_compiler/cpp_util.py | 79 | ||||
-rw-r--r-- | tools/json_schema_compiler/h_generator.py | 9 | ||||
-rw-r--r-- | tools/json_schema_compiler/model.py | 24 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/array.json | 120 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/array_unittest.cc | 143 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/choices.json | 101 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/choices_unittest.cc | 135 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/crossref.json | 43 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/crossref_unittest.cc | 55 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/json_schema_compiler_tests.gyp | 27 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/simple_api.json | 106 | ||||
-rw-r--r-- | tools/json_schema_compiler/test/simple_api_unittest.cc | 111 | ||||
-rw-r--r-- | tools/json_schema_compiler/util_cc_helper.py | 12 |
17 files changed, 1068 insertions, 263 deletions
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 2d0f6d3..f021149 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1226,6 +1226,7 @@ '../third_party/leveldatabase/leveldatabase.gyp:leveldatabase', '../third_party/libjingle/libjingle.gyp:libjingle', '../third_party/libxml/libxml.gyp:libxml', + '../tools/json_schema_compiler/test/json_schema_compiler_tests.gyp:json_schema_compiler_tests', '../ui/gfx/gl/gl.gyp:gl', '../ui/ui.gyp:ui_resources', '../ui/ui.gyp:ui_resources_standard', @@ -2110,6 +2111,10 @@ 'tools/convert_dict/convert_dict_unittest.cc', '../testing/gtest_mac_unittest.mm', '../third_party/cld/encodings/compact_lang_det/compact_lang_det_unittest_small.cc', + '../tools/json_schema_compiler/test/array_unittest.cc', + '../tools/json_schema_compiler/test/choices_unittest.cc', + '../tools/json_schema_compiler/test/crossref_unittest.cc', + '../tools/json_schema_compiler/test/simple_api_unittest.cc', '../ui/views/test/test_views_delegate.cc', '../ui/views/test/test_views_delegate.h', '../ui/views/test/views_test_base.cc', diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py index 43d7a5e..24007d4 100644 --- a/tools/json_schema_compiler/cc_generator.py +++ b/tools/json_schema_compiler/cc_generator.py @@ -44,20 +44,23 @@ class CCGenerator(object): .Concat(self._cpp_type_generator.GetRootNamespaceStart()) .Concat(self._cpp_type_generator.GetNamespaceStart()) .Append() - .Append('//') - .Append('// Types') - .Append('//') - .Append() ) + if self._namespace.types: + (c.Append('//') + .Append('// Types') + .Append('//') + .Append() + ) for type_ in self._namespace.types.values(): (c.Concat(self._GenerateType(type_.name, type_)) .Append() ) - (c.Append('//') - .Append('// Functions') - .Append('//') - .Append() - ) + if self._namespace.functions: + (c.Append('//') + .Append('// Functions') + .Append('//') + .Append() + ) for function in self._namespace.functions.values(): (c.Concat(self._GenerateFunction(function)) .Append() @@ -111,71 +114,33 @@ class CCGenerator(object): return c def _GenerateTypePopulateProperty(self, prop, src, dst): - """Generate the code to populate a single property. + """Generate the code to populate a single property in a type. src: DictionaryValue* dst: Type* """ c = code.Code() - dst_member = dst + '->' + prop.unix_name - if prop.type_ == PropertyType.ARRAY: - # util_cc_helper deals with optional and required arrays - (c.Append('if (!%s)' % - self._util_cc_helper.GetArray(prop, src, prop.name, dst_member)) - .Append(' return false;') + value_var = prop.unix_name + '_value' + c.Append('Value* %(value_var)s = NULL;') + if prop.optional: + (c.Sblock( + 'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {' + ) + .Concat(self._GeneratePopulatePropertyFromValue( + prop, value_var, 'out', 'false')) + .Eblock('}') ) - elif prop.type_ == PropertyType.CHOICES: - value_var = prop.unix_name + '_value' - c.Append('Value* %(value_var)s = NULL;') - c.Append( - 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') - if prop.optional: - c.Append(' return true;') - else: - c.Append(' return false;') - c.Append() - c.Concat(self._GeneratePopulateChoices(prop, value_var, dst, 'false')) - c.Substitute({'value_var': value_var, 'key': prop.name, 'src': src}) else: - if prop.optional: - if prop.type_.is_fundamental: - (c.Sblock('{') - .Append('%(type)s %(name)s_temp;') - .Append('if (%s)' % self._GeneratePopulatePropertyFunctionCall( - prop, src, '&%s_temp' % prop.unix_name)) - .Append(' out->%(name)s.reset(new %(type)s(%(name)s_temp));') - .Eblock('}') - ) - else: - raise NotImplementedError('Optional %s not implemented' % prop.type_) - else: - (c.Append('if (!%s)' % - self._GeneratePopulatePropertyFunctionCall( - prop, src, '&' + dst_member)) - .Append(' return false;') - ) - c.Substitute({ - 'name': prop.unix_name, - 'type': self._cpp_type_generator.GetType(prop) - }) + (c.Append( + 'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))') + .Append(' return false;') + .Concat(self._GeneratePopulatePropertyFromValue( + prop, value_var, 'out', 'false')) + ) + c.Append() + c.Substitute({'value_var': value_var, 'key': prop.name, 'src': src}) return c - def _GeneratePopulatePropertyFunctionCall(self, prop, src, dst): - """Generates the function call that populates the given property. - - src: DictionaryValue* - dst: Property* or scoped_ptr<Property> - """ - if prop.type_.is_fundamental: - populate_line = cpp_util.GetFundamentalValue( - prop, src, prop.name, dst) - elif prop.type_ in (PropertyType.REF, PropertyType.OBJECT): - populate_line = '%(type)s::Populate(*%(src)s, %(dst)s)' - else: - raise NotImplementedError('%s populate is not implemented' % - prop.type_) - return populate_line - def _GenerateTypeToValue(self, cpp_namespace, type_): """Generates a function that serializes the type into a |DictionaryValue|. """ @@ -203,7 +168,8 @@ class CCGenerator(object): if prop.optional: c.Sblock('if (%s.get())' % var) if prop.type_ == PropertyType.ARRAY: - c.Append('%s;' % self._util_cc_helper.SetArray(prop, var, prop.name, dst)) + c.Append('%s;' % self._util_cc_helper.PopulateDictionaryFromArray( + prop, var, prop.name, dst)) else: c.Append('%s->SetWithoutPathExpansion("%s", %s);' % (dst, prop.name, cpp_util.CreateValueFromSingleProperty(prop, var))) @@ -250,7 +216,7 @@ class CCGenerator(object): if num_required == len(function.params): c.Append('if (%(var)s.GetSize() != %(total)d)') elif not num_required: - c.Append('if (%(var)s.GetSize() > %(total)s)') + c.Append('if (%(var)s.GetSize() > %(total)d)') else: c.Append('if (%(var)s.GetSize() < %(required)d' ' || %(var)s.GetSize() > %(total)d)') @@ -263,7 +229,8 @@ class CCGenerator(object): return c def _GenerateFunctionParamsCreate(self, function): - """Generate function to create an instance of Params given a pointer. + """Generate function to create an instance of Params. The generated + function takes a ListValue of arguments. """ classname = cpp_util.Classname(function.name) c = code.Code() @@ -276,96 +243,120 @@ class CCGenerator(object): c.Substitute({'classname': classname}) for i, param in enumerate(function.params): - dst = 'params->' + param.unix_name # Any failure will cause this function to return. If any argument is # incorrect or missing, those following it are not processed. Note that # this is still correct in the case of multiple optional arguments as an # optional argument at position 4 cannot exist without an argument at # position 3. + failure_value = 'scoped_ptr<Params>()' if param.optional: - failure_value = 'params.Pass()' + arg_missing_value = 'params.Pass()' else: - failure_value = 'scoped_ptr<Params>()' + arg_missing_value = failure_value c.Append() - param_var = param.unix_name + '_param' - # TODO(calamity): Return error on incorrect argument type - if param.type_ == PropertyType.ARRAY: - # util_cc_helper deals with optional and required arrays - (c.Append('ListValue* %(param_var)s = NULL;') - .Append('if (!args.GetList(%(i)d, &%(param_var)s))') - .Append(' return %s;' % failure_value) - .Append('if (!%s)' % self._util_cc_helper.GetArrayFromList( - param, param_var, dst)) - .Append(' return %s;' % failure_value) - ) - c.Substitute({'param_var': param_var, 'i': i}) - elif param.type_ == PropertyType.CHOICES: - value_var = param.unix_name + '_value' - (c.Append('Value* %(value_var)s = NULL;') - .Append('if (!args.Get(%(i)s, &%(value_var)s))') - .Append(' return %s;' % failure_value) - .Append() - .Concat(self._GeneratePopulateChoices(param, value_var, 'params', - 'scoped_ptr<Params>()')) - ) - c.Substitute({'value_var': value_var, 'i': i}) - else: - if param.optional: - dst = dst + '.get()' - else: - dst = '&' + dst - if param.type_ in (PropertyType.REF, PropertyType.OBJECT): - (c.Append('DictionaryValue* %s = NULL;' % param_var) - .Append('if (!args.GetDictionary(%d, &%s))' % (i, param_var)) - .Append(' return %s;' % failure_value) - ) - if param.optional: - c.Append('params->%s.reset(new %s());' % - (param.unix_name, cpp_util.Classname(param.name))) - (c.Append('if (!%(ctype)s::Populate(*%(var)s, %(dst)s))' % { - 'var': param_var, 'dst': dst, - 'ctype': self._cpp_type_generator.GetType(param) - }) - .Append(' return %s;' % failure_value) - ) - elif param.type_.is_fundamental: - if param.optional: - (c.Sblock('{') - .Append('%(type)s %(name)s_temp;') - .Append('if (%s)' % cpp_util.GetValueFromList( - param, 'args', i, '&%s_temp' % param.unix_name)) - .Append( - ' params->%(name)s.reset(new %(type)s(%(name)s_temp));') - .Eblock('}') - ) - c.Substitute({ - 'name': param.unix_name, - 'type': self._cpp_type_generator.GetType(param), - }) - else: - (c.Append( - 'if (!%s)' % cpp_util.GetValueFromList(param, 'args', i, dst)) - .Append(' return %s;' % failure_value) - ) - else: - raise NotImplementedError('%s parameter is not supported' % - param.type_) + value_var = param.unix_name + '_value' + (c.Append('Value* %(value_var)s = NULL;') + .Append('if (!args.Get(%(i)s, &%(value_var)s) || ' + '%(value_var)s->IsType(Value::TYPE_NULL))') + .Append(' return %s;' % arg_missing_value) + .Concat(self._GeneratePopulatePropertyFromValue( + param, value_var, 'params', failure_value)) + ) + c.Substitute({'value_var': value_var, 'i': i}) (c.Append() .Append('return params.Pass();') .Eblock('}') + .Append() ) return c + def _GeneratePopulatePropertyFromValue( + self, prop, value_var, dst, failure_value, check_type=True): + """Generates code to populate a model.Property given a Value*. The + existence of data inside the Value* is assumed so checks for existence + should be performed before the code this generates. + + prop: the property the code is populating. + value_var: a Value* that should represent |prop|. + dst: the object with |prop| as a member. + failure_value: the value to return if |prop| cannot be extracted from + |value_var| + check_type: if true, will check if |value_var| is the correct Value::Type + """ + c = code.Code() + c.Sblock('{') + + if check_type: + (c.Append('if (!%(value_var)s->IsType(%(value_type)s))') + .Append(' return %(failure_value)s;') + ) + + if prop.type_.is_fundamental: + if prop.optional: + (c.Append('%(ctype)s temp;') + .Append('if (%s)' % + cpp_util.GetAsFundamentalValue(prop, value_var, '&temp')) + .Append(' %(dst)s->%(name)s.reset(new %(ctype)s(temp));') + ) + else: + (c.Append('if (!%s)' % + cpp_util.GetAsFundamentalValue( + prop, value_var, '&%s->%s' % (dst, prop.unix_name))) + .Append('return %(failure_value)s;') + ) + elif prop.type_ in (PropertyType.OBJECT, PropertyType.REF): + if prop.optional: + (c.Append('DictionaryValue* dictionary = NULL;') + .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))') + .Append(' return %(failure_value)s;') + .Append('scoped_ptr<%(ctype)s> temp(new %(ctype)s());') + .Append('if (!%(ctype)s::Populate(*dictionary, temp.get()))') + .Append(' return %(failure_value)s;') + .Append('%(dst)s->%(name)s = temp.Pass();') + ) + else: + (c.Append('DictionaryValue* dictionary = NULL;') + .Append('if (!%(value_var)s->GetAsDictionary(&dictionary))') + .Append(' return %(failure_value)s;') + .Append( + 'if (!%(ctype)s::Populate(*dictionary, &%(dst)s->%(name)s))') + .Append(' return %(failure_value)s;') + ) + elif prop.type_ == PropertyType.ARRAY: + # util_cc_helper deals with optional and required arrays + (c.Append('ListValue* list = NULL;') + .Append('if (!%(value_var)s->GetAsList(&list))') + .Append(' return %s;' % failure_value) + .Append('if (!%s)' % self._util_cc_helper.PopulateArrayFromList( + prop, 'list', dst + '->' + prop.unix_name)) + .Append(' return %s;' % failure_value) + ) + elif prop.type_ == PropertyType.CHOICES: + return self._GeneratePopulateChoices(prop, value_var, dst, failure_value) + else: + raise NotImplementedError(prop.type_) + c.Eblock('}') + c.Substitute({ + 'value_var': value_var, + 'name': prop.unix_name, + 'dst': dst, + 'ctype': self._cpp_type_generator.GetType(prop), + 'failure_value': failure_value, + 'value_type': cpp_util.GetValueType(prop), + }) + return c + def _GeneratePopulateChoices(self, prop, value_var, dst, failure_value): """Generates the code to populate a PropertyType.CHOICES parameter or - property. + property. The existence of data inside the Value* is assumed so checks for + existence should be performed before the code this generates. - value_var: Value* - dst: Type* or scoped_ptr<Params> - failure_value: the value to return on failure. Check if the property is - optional BEFORE the code generated by this method as failure_value will be - used to indicate a parsing error. + prop: the property the code is populating.. + value_var: a Value* that should represent |prop|. + dst: the object with |prop| as a member. + failure_value: the value to return if |prop| cannot be extracted from + |value_var| """ type_var = '%s->%s_type' % (dst, prop.unix_name) @@ -374,48 +365,19 @@ class CCGenerator(object): (type_var, self._cpp_type_generator.GetChoiceEnumNoneValue(prop))) c.Sblock('switch (%s->GetType()) {' % value_var) for choice in self._cpp_type_generator.GetExpandedChoicesInParams([prop]): - current_choice = '%s->%s' % (dst, choice.unix_name) - if choice.type_.is_fundamental: - c.Sblock('case %s: {' % { - PropertyType.STRING: 'Value::TYPE_STRING', - PropertyType.INTEGER: 'Value::TYPE_INTEGER', - PropertyType.BOOLEAN: 'Value::TYPE_BOOLEAN', - PropertyType.DOUBLE: 'Value::TYPE_DOUBLE' - }[choice.type_]) - - (c.Append('%(type_var)s = %(enum_value)s;') - .Append('%s.reset(new %s());' % - (current_choice, self._cpp_type_generator.GetType(choice))) - .Append('if (!%s)' % - cpp_util.GetAsFundamentalValue( - choice, value_var, current_choice + '.get()')) - .Append(' return %s;' % failure_value) + (c.Sblock('case %s: {' % cpp_util.GetValueType(choice)) + .Concat(self._GeneratePopulatePropertyFromValue( + choice, value_var, dst, failure_value, check_type=False)) + .Append('%s = %s;' % + (type_var, + self._cpp_type_generator.GetChoiceEnumValue( + prop, choice.type_))) .Append('break;') .Eblock('}') - ) - elif choice.type_ == PropertyType.ARRAY: - # util_cc_helper deals with optional and required arrays - (c.Sblock('case Value::TYPE_LIST: {') - .Append('%(type_var)s = %(enum_value)s;') - .Append('if (!%s)' % self._util_cc_helper.GetArrayFromList( - choice, - 'static_cast<ListValue*>(%s)' % value_var, - current_choice)) - .Append(' return %s;' % failure_value) - .Append('break;') - .Eblock('}') - ) - else: - raise NotImplementedError(choice.type_) - c.Substitute({ - 'type_var': type_var, - 'enum_value': self._cpp_type_generator.GetChoiceEnumValue( - prop, choice.type_), - }) - if not prop.optional: - (c.Append('default:') - .Append(' return %s;' % failure_value) ) + (c.Append('default:') + .Append(' return %s;' % failure_value) + ) c.Eblock('}') return c @@ -425,6 +387,7 @@ class CCGenerator(object): classname = cpp_util.Classname(function.name) c = code.Code() params = function.callback.params + if not params: (c.Append('Value* %s::Result::Create() {' % classname) .Append(' return Value::CreateNullValue();') @@ -436,19 +399,25 @@ class CCGenerator(object): # for each choice. This works because only 1 choice can be returned at a # time. for param in self._cpp_type_generator.GetExpandedChoicesInParams(params): - arg = cpp_util.GetConstParameterDeclaration( - param, self._cpp_type_generator) - c.Sblock('Value* %(classname)s::Result::Create(%(arg)s) {') - if param.type_ == PropertyType.ARRAY: + # We treat this argument as 'required' to avoid wrapping it in a + # scoped_ptr if it's optional. + param_copy = param.Copy() + param_copy.optional = False + c.Sblock('Value* %(classname)s::Result::Create(const %(arg)s) {') + if param_copy.type_ == PropertyType.ARRAY: (c.Append('ListValue* value = new ListValue();') - .Append('%s;' % self._util_cc_helper.SetArrayToList( - param, param.unix_name, 'value')) + .Append('%s;' % self._util_cc_helper.PopulateListFromArray( + param_copy, param_copy.unix_name, 'value')) .Append('return value;') ) else: - c.Append('return %s;' % cpp_util.CreateValueFromSingleProperty(param, - param.unix_name)) - c.Substitute({'classname': classname, 'arg': arg}) + c.Append('return %s;' % + cpp_util.CreateValueFromSingleProperty(param_copy, + param_copy.unix_name)) + c.Substitute({'classname': classname, + 'arg': cpp_util.GetParameterDeclaration( + param_copy, self._cpp_type_generator.GetType(param_copy)) + }) c.Eblock('}') return c diff --git a/tools/json_schema_compiler/compiler.py b/tools/json_schema_compiler/compiler.py index fab0504..d5f0802 100644 --- a/tools/json_schema_compiler/compiler.py +++ b/tools/json_schema_compiler/compiler.py @@ -12,11 +12,10 @@ are in chrome/common/extensions/api. Usage example: compiler.py --root /home/Work/src --namespace extensions windows.json tabs.json - compiler.py --destdir gen --suffix _api --root /home/Work/src + compiler.py --destdir gen --root /home/Work/src --namespace extensions windows.json tabs.json """ -import cpp_util import cc_generator import cpp_type_generator import h_generator @@ -37,15 +36,12 @@ if __name__ == '__main__': help='root directory to output generated files.') parser.add_option('-n', '--namespace', default='generated_api_schemas', help='C++ namespace for generated files. e.g extensions::api.') - parser.add_option('-s', '--suffix', default='', - help='Filename and C++ namespace suffix for generated files.') (opts, args) = parser.parse_args() if not args: sys.exit(parser.get_usage()) dest_dir = opts.destdir root_namespace = opts.namespace - filename_suffix = opts.suffix schema = os.path.normpath(args[0]) referenced_schemas = args[1:] @@ -73,14 +69,15 @@ if __name__ == '__main__': if not namespace: continue - out_file = namespace.name + filename_suffix + # The output filename must match the input filename for gyp to deal with it + # properly. + out_file = namespace.name type_generator = cpp_type_generator.CppTypeGenerator(root_namespace, namespace, out_file) for referenced_namespace in api_model.namespaces.values(): type_generator.AddNamespace( referenced_namespace, - cpp_util.Classname(referenced_namespace.name).lower() + - filename_suffix) + referenced_namespace.unix_name) cc_generator = cc_generator.CCGenerator(namespace, type_generator) cc_code = cc_generator.Generate().Render() h_generator = h_generator.HGenerator(namespace, type_generator) diff --git a/tools/json_schema_compiler/cpp_type_generator.py b/tools/json_schema_compiler/cpp_type_generator.py index 34f3f16..793ae13 100644 --- a/tools/json_schema_compiler/cpp_type_generator.py +++ b/tools/json_schema_compiler/cpp_type_generator.py @@ -26,6 +26,9 @@ class CppTypeGenerator(object): beneath the root namespace. """ for type_ in namespace.types: + if self._type_namespaces.get(type_, namespace) != namespace: + raise ValueError('Type %s is declared in both %s and %s' % + (type_, namespace.name, self._type_namespaces[type_].name)) self._type_namespaces[type_] = namespace self._cpp_namespaces[namespace] = cpp_namespace diff --git a/tools/json_schema_compiler/cpp_util.py b/tools/json_schema_compiler/cpp_util.py index 8762fa6..1c4575a 100644 --- a/tools/json_schema_compiler/cpp_util.py +++ b/tools/json_schema_compiler/cpp_util.py @@ -26,21 +26,6 @@ def Classname(s): """ return '_'.join([x[0].upper() + x[1:] for x in s.split('.')]) -def CreateFundamentalValue(prop, var): - """Returns the C++ code for creating a value of the given property type - using the given variable. - - var: Fundamental or Fundamental* - """ - if prop.optional: - var = '*' + var - return { - PropertyType.STRING: 'Value::CreateStringValue(%s)', - PropertyType.BOOLEAN: 'Value::CreateBooleanValue(%s)', - PropertyType.INTEGER: 'Value::CreateIntegerValue(%s)', - PropertyType.DOUBLE: 'Value::CreateDoubleValue(%s)', - }[prop.type_] % var - def GetAsFundamentalValue(prop, src, dst): """Returns the C++ code for retrieving a fundamental type from a Value into a variable. @@ -55,60 +40,54 @@ def GetAsFundamentalValue(prop, src, dst): PropertyType.DOUBLE: '%s->GetAsDouble(%s)', }[prop.type_] % (src, dst) -def GetFundamentalValue(prop, src, name, dst): - """Returns the C++ code for retrieving a fundamental type from a - DictionaryValue into a variable. - - src: DictionaryValue* - name: key - dst: Property* +def GetValueType(prop): + """Returns the Value::Type corresponding to the model.PropertyType. """ return { - PropertyType.STRING: '%s->GetString("%s", %s)', - PropertyType.BOOLEAN: '%s->GetBoolean("%s", %s)', - PropertyType.INTEGER: '%s->GetInteger("%s", %s)', - PropertyType.DOUBLE: '%s->GetDouble("%s", %s)', - }[prop.type_] % (src, name, dst) + PropertyType.STRING: 'Value::TYPE_STRING', + PropertyType.INTEGER: 'Value::TYPE_INTEGER', + PropertyType.BOOLEAN: 'Value::TYPE_BOOLEAN', + PropertyType.DOUBLE: 'Value::TYPE_DOUBLE', + PropertyType.REF: 'Value::TYPE_DICTIONARY', + PropertyType.OBJECT: 'Value::TYPE_DICTIONARY', + PropertyType.ARRAY: 'Value::TYPE_LIST' + }[prop.type_] + def CreateValueFromSingleProperty(prop, var): """Creates a Value given a single property. Use for everything except PropertyType.ARRAY. - var: raw value + var: variable or variable* """ - if prop.type_ == PropertyType.REF or prop.type_ == PropertyType.OBJECT: + if prop.type_ in (PropertyType.REF, PropertyType.OBJECT): if prop.optional: return '%s->ToValue().release()' % var else: return '%s.ToValue().release()' % var elif prop.type_.is_fundamental: - return CreateFundamentalValue(prop, var) + if prop.optional: + var = '*' + var + return { + PropertyType.STRING: 'Value::CreateStringValue(%s)', + PropertyType.BOOLEAN: 'Value::CreateBooleanValue(%s)', + PropertyType.INTEGER: 'Value::CreateIntegerValue(%s)', + PropertyType.DOUBLE: 'Value::CreateDoubleValue(%s)', + }[prop.type_] % var else: raise NotImplementedError('Conversion of single %s to Value not implemented' % repr(prop.type_)) -def GetValueFromList(prop, src, index, dst): - """Returns the C++ code for retrieving a fundamental type from a - DictionaryValue into a variable. - - src: ListValue& - index: int - dst: Property* +def GetParameterDeclaration(param, type_): + """Gets a const parameter declaration of a given model.Property and its C++ + type. """ - return { - PropertyType.REF: '%s.GetDictionary(%d, %s)', - PropertyType.STRING: '%s.GetString(%d, %s)', - PropertyType.BOOLEAN: '%s.GetBoolean(%d, %s)', - PropertyType.INTEGER: '%s.GetInteger(%d, %s)', - PropertyType.DOUBLE: '%s.GetDouble(%d, %s)', - }[prop.type_] % (src, index, dst) - -def GetConstParameterDeclaration(param, type_generator): - if param.type_.is_fundamental: - arg = 'const %(type)s %(name)s' + if param.type_ in (PropertyType.REF, PropertyType.OBJECT, PropertyType.ARRAY, + PropertyType.STRING): + arg = '%(type)s& %(name)s' else: - arg = 'const %(type)s& %(name)s' + arg = '%(type)s %(name)s' return arg % { - 'type': type_generator.GetType(param, wrap_optional=True), + 'type': type_, 'name': param.unix_name, } diff --git a/tools/json_schema_compiler/h_generator.py b/tools/json_schema_compiler/h_generator.py index ed85dd5..7b83622 100644 --- a/tools/json_schema_compiler/h_generator.py +++ b/tools/json_schema_compiler/h_generator.py @@ -97,7 +97,7 @@ class HGenerator(object): c.Append(self._cpp_type_generator.GetChoiceEnumNoneValue(prop) + ',') for choice in prop.choices.values(): c.Append( - self._cpp_type_generator.GetChoiceEnumValue( prop, choice.type_) + self._cpp_type_generator.GetChoiceEnumValue(prop, choice.type_) + ',') (c.Eblock('};') .Append() @@ -196,9 +196,10 @@ class HGenerator(object): for param in self._cpp_type_generator.GetExpandedChoicesInParams(params): if param.description: c.Comment(param.description) - c.Append('Value* Create(%s);' % - cpp_util.GetConstParameterDeclaration( - param, self._cpp_type_generator)) + if param.type_ == PropertyType.OBJECT: + raise NotImplementedError('OBJECT return type not supported') + c.Append('Value* Create(const %s);' % cpp_util.GetParameterDeclaration( + param, self._cpp_type_generator.GetType(param))) c.Eblock('};') return c diff --git a/tools/json_schema_compiler/model.py b/tools/json_schema_compiler/model.py index 9ac7dfd..c8a3c9a 100644 --- a/tools/json_schema_compiler/model.py +++ b/tools/json_schema_compiler/model.py @@ -4,6 +4,7 @@ import os.path import re +import copy class Model(object): """Model of all namespaces that comprise an API. @@ -30,23 +31,24 @@ class Namespace(object): Properties: - |name| the name of the namespace - - |source_file_dir| the directory component of the file that contained the - namespace definition - - |source_file_filename| the filename component of the file that contained - the namespace definition + - |unix_name| the unix_name of the namespace + - |source_file| the file that contained the namespace definition + - |source_file_dir| the directory component of |source_file| + - |source_file_filename| the filename component of |source_file| - |types| a map of type names to their model.Type - |functions| a map of function names to their model.Function """ def __init__(self, json, source_file): self.name = json['namespace'] + self.unix_name = _UnixName(self.name) self.source_file = source_file self.source_file_dir, self.source_file_filename = os.path.split(source_file) self.types = {} self.functions = {} - for type_json in json['types']: + for type_json in json.get('types', []): type_ = Type(type_json) self.types[type_.name] = type_ - for function_json in json['functions']: + for function_json in json.get('functions', []): if not function_json.get('nocompile', False): function = Function(function_json) self.functions[function.name] = function @@ -193,6 +195,14 @@ class Property(object): (self.name, self._unix_name)) self._unix_name = unix_name + def Copy(self): + """Makes a copy of this model.Property object and allow the unix_name to be + set again. + """ + property_copy = copy.copy(self) + property_copy._unix_name_used = False + return property_copy + unix_name = property(GetUnixName, SetUnixName) class PropertyType(object): @@ -217,7 +227,7 @@ class PropertyType(object): ANY = _Info(False, "ANY") def _UnixName(name): - """Returns the unix_style name for a given string in lowerCamelCase format. + """Returns the unix_style name for a given lowerCamelCase string. """ return '_'.join([x.lower() for x in re.findall('[A-Z][a-z_]*', name[0].upper() + name[1:])]) diff --git a/tools/json_schema_compiler/test/array.json b/tools/json_schema_compiler/test/array.json new file mode 100644 index 0000000..64dbdd4 --- /dev/null +++ b/tools/json_schema_compiler/test/array.json @@ -0,0 +1,120 @@ +[ + { + "namespace": "array", + "types": [ + { + "id": "BasicArrayType", + "type": "object", + "properties": { + "strings": { + "type": "array", + "items": {"type": "string"} + }, + "booleans": { + "type": "array", + "items": {"type": "boolean"} + }, + "numbers": { + "type": "array", + "items": {"type": "number"} + }, + "integers": { + "type": "array", + "items": {"type": "integer"} + } + } + }, + { + "id": "Item", + "type": "object", + "properties": { + "val": { + "type": "integer" + } + } + }, + { + "id": "RefArrayType", + "type": "object", + "properties": { + "refs": { + "type": "array", + "items": { "$ref": "Item" } + } + } + } + ], + "functions": [ + { + "name": "integerArray", + "type": "function", + "description": "Increments the given integer.", + "parameters": [ + { + "name": "nums", + "type": "array", + "items": {"type": "integer"} + }, + { + "name": "callback", + "type": "function", + "parameters": [] + } + ] + }, + { + "name": "refArray", + "type": "function", + "description": "Takes some Items.", + "parameters": [ + { + "name": "refs", + "type": "array", + "items": {"$ref": "Item"} + }, + { + "name": "callback", + "type": "function", + "parameters": [] + } + ] + }, + { + "name": "returnIntegerArray", + "type": "function", + "description": "Returns some integers.", + "parameters": [ + { + "name": "callback", + "type": "function", + "parameters": [ + { + "name": "integers", + "type": "array", + "items": {"type": "integer"} + } + ] + } + ] + }, + { + "name": "returnRefArray", + "type": "function", + "description": "Returns some Items.", + "parameters": [ + { + "name": "callback", + "type": "function", + "parameters": [ + { + "name": "refs", + "type": "array", + "items": {"$ref": "Item"} + } + ] + } + ] + } + ] + } +] diff --git a/tools/json_schema_compiler/test/array_unittest.cc b/tools/json_schema_compiler/test/array_unittest.cc new file mode 100644 index 0000000..6db2d5e --- /dev/null +++ b/tools/json_schema_compiler/test/array_unittest.cc @@ -0,0 +1,143 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/json_schema_compiler/test/array.h" + +#include "testing/gtest/include/gtest/gtest.h" + +using namespace test::api::array; + +namespace { + +// TODO(calamity): Change to AppendString etc once kalman's patch goes through +static scoped_ptr<DictionaryValue> CreateBasicArrayTypeDictionary() { + DictionaryValue* value = new DictionaryValue(); + ListValue* strings_value = new ListValue(); + strings_value->Append(Value::CreateStringValue("a")); + strings_value->Append(Value::CreateStringValue("b")); + strings_value->Append(Value::CreateStringValue("c")); + strings_value->Append(Value::CreateStringValue("it's easy as")); + ListValue* integers_value = new ListValue(); + integers_value->Append(Value::CreateIntegerValue(1)); + integers_value->Append(Value::CreateIntegerValue(2)); + integers_value->Append(Value::CreateIntegerValue(3)); + ListValue* booleans_value = new ListValue(); + booleans_value->Append(Value::CreateBooleanValue(false)); + booleans_value->Append(Value::CreateBooleanValue(true)); + ListValue* numbers_value = new ListValue(); + numbers_value->Append(Value::CreateDoubleValue(6.1)); + value->Set("numbers", numbers_value); + value->Set("booleans", booleans_value); + value->Set("strings", strings_value); + value->Set("integers", integers_value); + return scoped_ptr<DictionaryValue>(value); +} + +static Value* CreateItemValue(int val) { + DictionaryValue* value(new DictionaryValue()); + value->Set("val", Value::CreateIntegerValue(val)); + return value; +} + +} // namespace + +TEST(JsonSchemaCompilerArrayTest, BasicArrayType) { + { + scoped_ptr<DictionaryValue> value = CreateBasicArrayTypeDictionary(); + scoped_ptr<BasicArrayType> basic_array_type(new BasicArrayType()); + EXPECT_TRUE(BasicArrayType::Populate(*value, basic_array_type.get())); + EXPECT_TRUE(value->Equals(basic_array_type->ToValue().get())); + } +} + +TEST(JsonSchemaCompilerArrayTest, RefArrayType) { + { + scoped_ptr<DictionaryValue> value(new DictionaryValue()); + scoped_ptr<ListValue> ref_array(new ListValue()); + ref_array->Append(CreateItemValue(1)); + ref_array->Append(CreateItemValue(2)); + ref_array->Append(CreateItemValue(3)); + value->Set("refs", ref_array.release()); + scoped_ptr<RefArrayType> ref_array_type(new RefArrayType()); + EXPECT_TRUE(RefArrayType::Populate(*value, ref_array_type.get())); + EXPECT_EQ(3UL, ref_array_type->refs.size()); + EXPECT_EQ(1, ref_array_type->refs[0]->val); + EXPECT_EQ(2, ref_array_type->refs[1]->val); + EXPECT_EQ(3, ref_array_type->refs[2]->val); + } + { + scoped_ptr<DictionaryValue> value(new DictionaryValue()); + scoped_ptr<ListValue> not_ref_array(new ListValue()); + not_ref_array->Append(CreateItemValue(1)); + not_ref_array->Append(Value::CreateIntegerValue(3)); + value->Set("refs", not_ref_array.release()); + scoped_ptr<RefArrayType> ref_array_type(new RefArrayType()); + EXPECT_FALSE(RefArrayType::Populate(*value, ref_array_type.get())); + } +} + +TEST(JsonSchemaCompilerArrayTest, IntegerArrayParamsCreate) { + scoped_ptr<ListValue> params_value(new ListValue()); + scoped_ptr<ListValue> integer_array(new ListValue()); + integer_array->Append(Value::CreateIntegerValue(2)); + integer_array->Append(Value::CreateIntegerValue(4)); + integer_array->Append(Value::CreateIntegerValue(8)); + params_value->Append(integer_array.release()); + scoped_ptr<IntegerArray::Params> params( + IntegerArray::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_EQ(3UL, params->nums.size()); + EXPECT_EQ(2, params->nums[0]); + EXPECT_EQ(4, params->nums[1]); + EXPECT_EQ(8, params->nums[2]); +} + +TEST(JsonSchemaCompilerArrayTest, RefArrayParamsCreate) { + scoped_ptr<ListValue> params_value(new ListValue()); + scoped_ptr<ListValue> item_array(new ListValue()); + item_array->Append(CreateItemValue(1)); + item_array->Append(CreateItemValue(2)); + params_value->Append(item_array.release()); + scoped_ptr<RefArray::Params> params( + RefArray::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_EQ(2UL, params->refs.size()); + EXPECT_EQ(1, params->refs[0]->val); + EXPECT_EQ(2, params->refs[1]->val); +} + +TEST(JsonSchemaCompilerArrayTest, ReturnIntegerArrayResultCreate) { + std::vector<int> integers; + integers.push_back(1); + integers.push_back(2); + scoped_ptr<Value> result(ReturnIntegerArray::Result::Create(integers)); + ListValue* list = NULL; + EXPECT_TRUE(result->GetAsList(&list)); + int temp; + EXPECT_EQ(2UL, list->GetSize()); + EXPECT_TRUE(list->GetInteger(0, &temp)); + EXPECT_EQ(1, temp); + EXPECT_TRUE(list->GetInteger(1, &temp)); + EXPECT_EQ(2, temp); +} + +TEST(JsonSchemaCompilerArrayTest, ReturnRefArrayResultCreate) { + std::vector<linked_ptr<Item> > items; + items.push_back(linked_ptr<Item>(new Item())); + items.push_back(linked_ptr<Item>(new Item())); + items[0]->val = 1; + items[1]->val = 2; + scoped_ptr<Value> result(ReturnRefArray::Result::Create(items)); + ListValue* list = NULL; + EXPECT_TRUE(result->GetAsList(&list)); + EXPECT_EQ(2UL, list->GetSize()); + DictionaryValue* item_value = NULL; + int temp; + EXPECT_TRUE(list->GetDictionary(0, &item_value)); + EXPECT_TRUE(item_value->GetInteger("val", &temp)); + EXPECT_EQ(1, temp); + EXPECT_TRUE(list->GetDictionary(1, &item_value)); + EXPECT_TRUE(item_value->GetInteger("val", &temp)); + EXPECT_EQ(2, temp); +} diff --git a/tools/json_schema_compiler/test/choices.json b/tools/json_schema_compiler/test/choices.json new file mode 100644 index 0000000..6a13eb5 --- /dev/null +++ b/tools/json_schema_compiler/test/choices.json @@ -0,0 +1,101 @@ +[ + { + "namespace": "choices", + "types": [], + "functions": [ + { + "name": "takesIntegers", + "type": "function", + "description": "Takes one or more integers.", + "parameters": [ + { + "name": "nums", + "choices": [ + {"type": "array", "items": {"type": "integer", "minimum": 0}}, + {"type": "integer"} + ] + }, + { + "name": "callback", + "type": "function", + "parameters": [] + } + ] + }, + { + "name": "takesIntegersOptional", + "type": "function", + "description": "Takes one or more integers.", + "parameters": [ + { + "name": "nums", + "choices": [ + {"type": "array", "items": {"type": "integer", "minimum": 0}}, + {"type": "integer"} + ], + "optional": true + }, + { + "name": "callback", + "type": "function", + "parameters": [] + } + ] + }, + { + "name": "objectWithChoices", + "type": "function", + "description": "Takes an object with one or more strings and optional integer(s).", + "parameters": [ + { + "type": "object", + "name": "stringInfo", + "properties": { + "strings": { + "description": "One or more tab indices to highlight.", + "choices": [ + {"type": "array", "items": {"type": "string", "minimum": 0}}, + {"type": "string"} + ] + }, + "integers": { + "description": "One or more tab indices to highlight.", + "choices": [ + {"type": "array", "items": {"type": "integer", "minimum": 0}}, + {"type": "integer"} + ], + "optional": true + } + } + }, + { + "name": "callback", + "type": "function", + "parameters": [] + } + ] + }, + { + "name": "returnChoices", + "type": "function", + "description": "Gives back a string. Or not.", + "parameters": [ + { + "name": "callback", + "type": "function", + "parameters": [ + { + "name": "result", + "choices": [ + {"type": "array", "items": {"type": "integer", "minimum": 0}}, + {"type": "integer"} + ], + "description": "Some integers." + } + ] + } + ] + } + ] + } +] diff --git a/tools/json_schema_compiler/test/choices_unittest.cc b/tools/json_schema_compiler/test/choices_unittest.cc new file mode 100644 index 0000000..32bab69 --- /dev/null +++ b/tools/json_schema_compiler/test/choices_unittest.cc @@ -0,0 +1,135 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/json_schema_compiler/test/choices.h" + +#include "testing/gtest/include/gtest/gtest.h" + +using namespace test::api::choices; + +TEST(JsonSchemaCompilerChoicesTest, TakesIntegersParamsCreate) { + { + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(Value::CreateBooleanValue(true)); + scoped_ptr<TakesIntegers::Params> params( + TakesIntegers::Params::Create(*params_value)); + EXPECT_FALSE(params.get()); + } + { + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(Value::CreateIntegerValue(6)); + scoped_ptr<TakesIntegers::Params> params( + TakesIntegers::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_EQ(TakesIntegers::Params::NUMS_INTEGER, params->nums_type); + EXPECT_FALSE(params->nums_array.get()); + EXPECT_EQ(6, *params->nums_integer); + } + { + scoped_ptr<ListValue> params_value(new ListValue()); + scoped_ptr<ListValue> integers(new ListValue()); + integers->Append(Value::CreateIntegerValue(6)); + integers->Append(Value::CreateIntegerValue(8)); + params_value->Append(integers.release()); + scoped_ptr<TakesIntegers::Params> params( + TakesIntegers::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_EQ(TakesIntegers::Params::NUMS_ARRAY, params->nums_type); + EXPECT_EQ(2UL, (*params->nums_array).size()); + EXPECT_EQ(6, (*params->nums_array)[0]); + EXPECT_EQ(8, (*params->nums_array)[1]); + } +} + +TEST(JsonSchemaCompilerChoicesTest, ObjectWithChoicesParamsCreate) { + { + scoped_ptr<DictionaryValue> object_param(new DictionaryValue()); + object_param->SetWithoutPathExpansion("strings", + Value::CreateStringValue("asdf")); + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(object_param.release()); + scoped_ptr<ObjectWithChoices::Params> params( + ObjectWithChoices::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_EQ(ObjectWithChoices::Params::StringInfo::STRINGS_STRING, + params->string_info.strings_type); + EXPECT_EQ("asdf", *params->string_info.strings_string); + } + { + scoped_ptr<DictionaryValue> object_param(new DictionaryValue()); + object_param->SetWithoutPathExpansion("strings", + Value::CreateStringValue("asdf")); + object_param->SetWithoutPathExpansion("integers", + Value::CreateIntegerValue(6)); + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(object_param.release()); + scoped_ptr<ObjectWithChoices::Params> params( + ObjectWithChoices::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_EQ(ObjectWithChoices::Params::StringInfo::STRINGS_STRING, + params->string_info.strings_type); + EXPECT_EQ("asdf", *params->string_info.strings_string); + EXPECT_EQ(ObjectWithChoices::Params::StringInfo::INTEGERS_INTEGER, + params->string_info.integers_type); + EXPECT_EQ(6, *params->string_info.integers_integer); + } +} + +TEST(JsonSchemaCompilerChoicesTest, ObjectWithChoicesParamsCreateFail) { + { + scoped_ptr<DictionaryValue> object_param(new DictionaryValue()); + object_param->SetWithoutPathExpansion("strings", + Value::CreateIntegerValue(5)); + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(object_param.release()); + scoped_ptr<ObjectWithChoices::Params> params( + ObjectWithChoices::Params::Create(*params_value)); + EXPECT_FALSE(params.get()); + } + { + scoped_ptr<DictionaryValue> object_param(new DictionaryValue()); + object_param->SetWithoutPathExpansion("strings", + Value::CreateStringValue("asdf")); + object_param->SetWithoutPathExpansion("integers", + Value::CreateStringValue("asdf")); + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(object_param.release()); + scoped_ptr<ObjectWithChoices::Params> params( + ObjectWithChoices::Params::Create(*params_value)); + EXPECT_FALSE(params.get()); + } + { + scoped_ptr<DictionaryValue> object_param(new DictionaryValue()); + object_param->SetWithoutPathExpansion("integers", + Value::CreateIntegerValue(6)); + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(object_param.release()); + scoped_ptr<ObjectWithChoices::Params> params( + ObjectWithChoices::Params::Create(*params_value)); + EXPECT_FALSE(params.get()); + } +} + +TEST(JsonSchemaCompilerChoicesTest, ReturnChoices) { + { + std::vector<int> integers; + integers.push_back(1); + integers.push_back(2); + scoped_ptr<Value> array_result(ReturnChoices::Result::Create(integers)); + ListValue* list = NULL; + EXPECT_TRUE(array_result->GetAsList(&list)); + EXPECT_EQ(2UL, list->GetSize()); + int temp; + EXPECT_TRUE(list->GetInteger(0, &temp)); + EXPECT_EQ(1, temp); + EXPECT_TRUE(list->GetInteger(1, &temp)); + EXPECT_EQ(2, temp); + } + { + scoped_ptr<Value> single_result(ReturnChoices::Result::Create(5)); + int temp; + EXPECT_TRUE(single_result->GetAsInteger(&temp)); + EXPECT_EQ(5, temp); + } +} diff --git a/tools/json_schema_compiler/test/crossref.json b/tools/json_schema_compiler/test/crossref.json new file mode 100644 index 0000000..3931cee --- /dev/null +++ b/tools/json_schema_compiler/test/crossref.json @@ -0,0 +1,43 @@ +[ + { + "namespace": "crossref", + "types": [], + "functions": [ + { + "name": "TestTypeOptionalParam", + "type": "function", + "description": "Takes TestType as a param.", + "parameters": [ + { + "name": "testType", + "$ref": "TestType", + "optional": true + }, + { + "name": "callback", + "type": "function", + "parameters": [] + } + ] + }, + { + "name": "getTestType", + "type": "function", + "description": "Return a TestType.", + "parameters": [ + { + "name": "callback", + "type": "function", + "parameters": [ + { + "name": "result", + "$ref": "TestType", + "description": "A TestType." + } + ] + } + ] + } + ] + } +] diff --git a/tools/json_schema_compiler/test/crossref_unittest.cc b/tools/json_schema_compiler/test/crossref_unittest.cc new file mode 100644 index 0000000..ab39f39 --- /dev/null +++ b/tools/json_schema_compiler/test/crossref_unittest.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/json_schema_compiler/test/simple_api.h" +#include "tools/json_schema_compiler/test/crossref.h" + +#include "testing/gtest/include/gtest/gtest.h" + +using namespace test::api::crossref; + +namespace { + +static scoped_ptr<DictionaryValue> CreateTestTypeDictionary() { + DictionaryValue* value(new DictionaryValue()); + value->SetWithoutPathExpansion("number", Value::CreateDoubleValue(1.1)); + value->SetWithoutPathExpansion("integer", Value::CreateIntegerValue(4)); + value->SetWithoutPathExpansion("string", Value::CreateStringValue("bling")); + value->SetWithoutPathExpansion("boolean", Value::CreateBooleanValue(true)); + return scoped_ptr<DictionaryValue>(value); +} + +} // namespace + +TEST(JsonSchemaCompilerCrossrefTest, TestTypeOptionalParamCreate) { + scoped_ptr<ListValue> params_value(new ListValue()); + scoped_ptr<DictionaryValue> test_type_value = CreateTestTypeDictionary(); + params_value->Append(test_type_value.release()); + scoped_ptr<TestTypeOptionalParam::Params> params( + TestTypeOptionalParam::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_TRUE(params->test_type.get()); + EXPECT_TRUE( + CreateTestTypeDictionary()->Equals(params->test_type->ToValue().get())); +} + +TEST(JsonSchemaCompilerCrossrefTest, TestTypeOptionalParamFail) { + scoped_ptr<ListValue> params_value(new ListValue()); + scoped_ptr<DictionaryValue> test_type_value = CreateTestTypeDictionary(); + test_type_value->RemoveWithoutPathExpansion("number", NULL); + params_value->Append(test_type_value.release()); + scoped_ptr<TestTypeOptionalParam::Params> params( + TestTypeOptionalParam::Params::Create(*params_value)); + EXPECT_FALSE(params.get()); +} + +TEST(JsonSchemaCompilerCrossrefTest, GetTestType) { + scoped_ptr<DictionaryValue> value = CreateTestTypeDictionary(); + scoped_ptr<test::api::simple_api::TestType> test_type( + new test::api::simple_api::TestType()); + EXPECT_TRUE( + test::api::simple_api::TestType::Populate(*value, test_type.get())); + scoped_ptr<Value> result(GetTestType::Result::Create(*test_type)); + EXPECT_TRUE(value->Equals(result.get())); +} diff --git a/tools/json_schema_compiler/test/json_schema_compiler_tests.gyp b/tools/json_schema_compiler/test/json_schema_compiler_tests.gyp new file mode 100644 index 0000000..7781842 --- /dev/null +++ b/tools/json_schema_compiler/test/json_schema_compiler_tests.gyp @@ -0,0 +1,27 @@ +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +{ + 'targets': [ + { + 'target_name': 'json_schema_compiler_tests', + 'type': 'static_library', + 'variables': { + 'chromium_code': 1, + 'json_schema_files': [ + 'array.json', + 'choices.json', + 'crossref.json', + 'simple_api.json', + ], + 'cc_dir': 'tools/json_schema_compiler/test', + 'root_namespace': 'test::api', + }, + 'sources': [ + '<@(json_schema_files)', + ], + 'includes': ['../../../build/json_schema_compile.gypi'], + }, + ], +} diff --git a/tools/json_schema_compiler/test/simple_api.json b/tools/json_schema_compiler/test/simple_api.json new file mode 100644 index 0000000..b107fab --- /dev/null +++ b/tools/json_schema_compiler/test/simple_api.json @@ -0,0 +1,106 @@ +[ + { + "namespace": "simple_api", + "types": [ + { + "id": "TestType", + "type": "object", + "properties": { + "string": { + "type": "string", + "description": "Some string." + }, + "boolean": { + "type": "boolean", + "description": "Some boolean." + }, + "number": { + "type": "number", + "description": "Some double." + }, + "integer": { + "type": "integer", + "description": "Some integer." + } + } + } + ], + "functions": [ + { + "name": "incrementInteger", + "type": "function", + "description": "Increments the given integer.", + "parameters": [ + { + "name": "num", + "type": "integer" + }, + { + "name": "callback", + "type": "function", + "parameters": [ + { + "name": "result", + "type": "integer", + "description": "The incremented value." + } + ] + } + ] + }, + { + "name": "optionalString", + "type": "function", + "description": "Takes a string. Or not.", + "parameters": [ + { + "name": "str", + "type": "string", + "optional": true + }, + { + "name": "callback", + "type": "function", + "parameters": [] + } + ] + }, + { + "name": "optionalCallbackParams", + "type": "function", + "description": "Gives back a string. Or not.", + "parameters": [ + { + "name": "callback", + "type": "function", + "parameters": [ + { + "name": "result", + "$ref": "TestType", + "description": "True if the extension has the specified permissions." + } + ] + } + ] + }, + { + "name": "getTestType", + "type": "function", + "description": "Return a TestType.", + "parameters": [ + { + "name": "callback", + "type": "function", + "parameters": [ + { + "name": "result", + "$ref": "TestType", + "description": "A TestType." + } + ] + } + ] + } + ] + } +] diff --git a/tools/json_schema_compiler/test/simple_api_unittest.cc b/tools/json_schema_compiler/test/simple_api_unittest.cc new file mode 100644 index 0000000..dc959a3 --- /dev/null +++ b/tools/json_schema_compiler/test/simple_api_unittest.cc @@ -0,0 +1,111 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "tools/json_schema_compiler/test/simple_api.h" + +#include "testing/gtest/include/gtest/gtest.h" + +using namespace test::api::simple_api; + +namespace { + +static scoped_ptr<DictionaryValue> CreateTestTypeDictionary() { + scoped_ptr<DictionaryValue> value(new DictionaryValue()); + value->SetWithoutPathExpansion("number", Value::CreateDoubleValue(1.1)); + value->SetWithoutPathExpansion("integer", Value::CreateIntegerValue(4)); + value->SetWithoutPathExpansion("string", Value::CreateStringValue("bling")); + value->SetWithoutPathExpansion("boolean", Value::CreateBooleanValue(true)); + return value.Pass(); +} + +} // namespace + +TEST(JsonSchemaCompilerSimpleTest, IncrementIntegerResultCreate) { + scoped_ptr<Value> result(IncrementInteger::Result::Create(5)); + int temp = 0; + EXPECT_TRUE(result->GetAsInteger(&temp)); + EXPECT_EQ(5, temp); +} + +TEST(JsonSchemaCompilerSimpleTest, IncrementIntegerParamsCreate) { + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(Value::CreateIntegerValue(6)); + scoped_ptr<IncrementInteger::Params> params( + IncrementInteger::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_EQ(6, params->num); +} + +TEST(JsonSchemaCompilerSimpleTest, OptionalStringParamsCreate) { + { + scoped_ptr<ListValue> params_value(new ListValue()); + scoped_ptr<OptionalString::Params> params( + OptionalString::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_FALSE(params->str.get()); + } + { + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(Value::CreateStringValue("asdf")); + scoped_ptr<OptionalString::Params> params( + OptionalString::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_TRUE(params->str.get()); + EXPECT_EQ("asdf", *params->str); + } +} + +TEST(JsonSchemaCompilerSimpleTest, OptionalParamsTakingNull) { + { + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(Value::CreateNullValue()); + scoped_ptr<OptionalString::Params> params( + OptionalString::Params::Create(*params_value)); + EXPECT_TRUE(params.get()); + EXPECT_FALSE(params->str.get()); + } +} + +TEST(JsonSchemaCompilerSimpleTest, OptionalStringParamsWrongType) { + { + scoped_ptr<ListValue> params_value(new ListValue()); + params_value->Append(Value::CreateIntegerValue(5)); + scoped_ptr<OptionalString::Params> params( + OptionalString::Params::Create(*params_value)); + EXPECT_FALSE(params.get()); + } +} + +TEST(JsonSchemaCompilerSimpleTest, NoParamsResultCreate) { + EXPECT_TRUE(Value::Equals(OptionalString::Result::Create(), + Value::CreateNullValue())); +} + +TEST(JsonSchemaCompilerSimpleTest, TestTypePopulate) { + { + scoped_ptr<TestType> test_type(new TestType()); + scoped_ptr<DictionaryValue> value = CreateTestTypeDictionary(); + EXPECT_TRUE(TestType::Populate(*value, test_type.get())); + EXPECT_EQ("bling", test_type->string); + EXPECT_EQ(1.1, test_type->number); + EXPECT_EQ(4, test_type->integer); + EXPECT_EQ(true, test_type->boolean); + EXPECT_TRUE(value->Equals(test_type->ToValue().get())); + } + { + scoped_ptr<TestType> test_type(new TestType()); + scoped_ptr<DictionaryValue> value = CreateTestTypeDictionary(); + value->RemoveWithoutPathExpansion("number", NULL); + EXPECT_FALSE(TestType::Populate(*value, test_type.get())); + } +} + +TEST(JsonSchemaCompilerSimpleTest, GetTestType) { + scoped_ptr<DictionaryValue> value = CreateTestTypeDictionary(); + scoped_ptr<TestType> test_type(new TestType()); + EXPECT_TRUE(TestType::Populate(*value, test_type.get())); + scoped_ptr<Value> result(GetTestType::Result::Create(*test_type)); + EXPECT_TRUE(value->Equals(result.get())); +} + diff --git a/tools/json_schema_compiler/util_cc_helper.py b/tools/json_schema_compiler/util_cc_helper.py index 4c5a13b..fe4e858 100644 --- a/tools/json_schema_compiler/util_cc_helper.py +++ b/tools/json_schema_compiler/util_cc_helper.py @@ -11,7 +11,7 @@ class UtilCCHelper(object): def __init__(self, type_manager): self._type_manager = type_manager - def GetArray(self, array_prop, src, name, dst): + def PopulateArrayFromDictionary(self, array_prop, src, name, dst): """Generates code to get an array from a src.name into dst. src: DictionaryValue* @@ -35,7 +35,7 @@ class UtilCCHelper(object): return val % sub - def GetArrayFromList(self, array_prop, src, dst): + def PopulateArrayFromList(self, array_prop, src, dst): """Generates code to get an array from src into dst. src: ListValue* @@ -56,7 +56,7 @@ class UtilCCHelper(object): return val % sub - def SetArray(self, array_prop, src, name, dst): + def PopulateDictionaryFromArray(self, array_prop, src, name, dst): """Generates code to set dst.name to the array at src src: std::vector or scoped_ptr<std::vector> @@ -75,12 +75,12 @@ class UtilCCHelper(object): val = ('%(namespace)s::PopulateDictionaryFromOptionalArray' '(%(src)s, "%(name)s", %(dst)s.get())') else: - val = ('%(namespace)s::PopulateDictionaryFromArray(%(src)s, ' - '"%(name)s", %(dst)s.get())') + val = ('%(namespace)s::PopulateDictionaryFromArray' + '(%(src)s, "%(name)s", %(dst)s.get())') return val % sub - def SetArrayToList(self, array_prop, src, dst): + def PopulateListFromArray(self, array_prop, src, dst): """Generates code to set dst to the array at src src: std::vector or scoped_ptr<std::vector> |