summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcalamity@chromium.org <calamity@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-28 05:51:44 +0000
committercalamity@chromium.org <calamity@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-28 05:51:44 +0000
commit25cbf601111a7c4bc0f24ea1e8fc8b0f688ce9d6 (patch)
tree1961d2f1f52421d8714f13ca91e8c615ea0f15cd
parente324f6b9b93237c1488694b2a94cff0f8ec85460 (diff)
downloadchromium_src-25cbf601111a7c4bc0f24ea1e8fc8b0f688ce9d6.zip
chromium_src-25cbf601111a7c4bc0f24ea1e8fc8b0f688ce9d6.tar.gz
chromium_src-25cbf601111a7c4bc0f24ea1e8fc8b0f688ce9d6.tar.bz2
json_schema_compiler: Added wider support for OBJECTs and ENUMs. Used the new 'dependencies' property in the jsons. Refactored to avoid code duplication. Added tests for new features and where tests were lacking.
BUG= TEST=unit_tests --gtest_filter=JsonSchemaCompiler* Review URL: http://codereview.chromium.org/9456007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123909 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--build/json_schema_compile.gypi5
-rw-r--r--chrome/chrome_tests.gypi3
-rw-r--r--chrome/common/extensions/api/extension.json1
-rw-r--r--tools/json_schema_compiler/cc_generator.py238
-rw-r--r--tools/json_schema_compiler/compiler.py23
-rw-r--r--tools/json_schema_compiler/cpp_type_generator.py5
-rw-r--r--tools/json_schema_compiler/cpp_type_generator_test.py6
-rw-r--r--tools/json_schema_compiler/cpp_util.py30
-rw-r--r--tools/json_schema_compiler/h_generator.py131
-rw-r--r--tools/json_schema_compiler/model.py51
-rw-r--r--tools/json_schema_compiler/test/arrays.json (renamed from tools/json_schema_compiler/test/array.json)4
-rw-r--r--tools/json_schema_compiler/test/arrays_unittest.cc (renamed from tools/json_schema_compiler/test/array_unittest.cc)14
-rw-r--r--tools/json_schema_compiler/test/choices_unittest.cc4
-rw-r--r--tools/json_schema_compiler/test/crossref.json35
-rw-r--r--tools/json_schema_compiler/test/crossref_unittest.cc61
-rw-r--r--tools/json_schema_compiler/test/json_schema_compiler_tests.gyp3
-rw-r--r--tools/json_schema_compiler/test/objects.json60
-rw-r--r--tools/json_schema_compiler/test/objects_unittest.cc59
-rw-r--r--tools/json_schema_compiler/test/simple_api_unittest.cc19
-rw-r--r--tools/json_schema_compiler/util.h22
-rw-r--r--tools/json_schema_compiler/util_cc_helper.py34
21 files changed, 539 insertions, 269 deletions
diff --git a/build/json_schema_compile.gypi b/build/json_schema_compile.gypi
index 55d6d30..16dd88c 100644
--- a/build/json_schema_compile.gypi
+++ b/build/json_schema_compile.gypi
@@ -27,6 +27,10 @@
'<(api_gen_dir)/util.cc',
'<(api_gen_dir)/util.h',
'<(api_gen_dir)/util_cc_helper.py',
+ # TODO(calamity): uncomment this when gyp on windows behaves like other
+ # platforms. List expansions of filepaths in inputs expand to different
+ # things.
+ # '<@(json_schema_files)',
],
'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/<(cc_dir)/<(RULE_INPUT_ROOT).cc',
@@ -39,7 +43,6 @@
'--root=<(DEPTH)',
'--destdir=<(SHARED_INTERMEDIATE_DIR)',
'--namespace=<(root_namespace)',
- '<@(json_schema_files)',
],
'message': 'Generating C++ code from <(RULE_INPUT_PATH) jsons',
'process_outputs_as_sources': 1,
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index c1a4ab2..8a47aac 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2123,10 +2123,11 @@
'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/arrays_unittest.cc',
'../tools/json_schema_compiler/test/choices_unittest.cc',
'../tools/json_schema_compiler/test/crossref_unittest.cc',
'../tools/json_schema_compiler/test/enums_unittest.cc',
+ '../tools/json_schema_compiler/test/objects_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',
diff --git a/chrome/common/extensions/api/extension.json b/chrome/common/extensions/api/extension.json
index cbb13c6..347088b 100644
--- a/chrome/common/extensions/api/extension.json
+++ b/chrome/common/extensions/api/extension.json
@@ -1,6 +1,7 @@
[
{
"namespace": "extension",
+ "nocompile": true,
"dependencies": [ "tabs" ],
"types": [
{
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py
index cc9214e..bbda061 100644
--- a/tools/json_schema_compiler/cc_generator.py
+++ b/tools/json_schema_compiler/cc_generator.py
@@ -72,19 +72,23 @@ class CCGenerator(object):
# TODO(calamity): Events
return c
- def _GenerateType(self, cpp_namespace, type_, serializable=True):
+ def _GenerateType(self, cpp_namespace, type_):
"""Generates the function definitions for a type.
"""
classname = cpp_util.Classname(type_.name)
c = code.Code()
- (c.Append('%(namespace)s::%(classname)s() {}')
+ (c.Concat(self._GeneratePropertyFunctions(
+ cpp_namespace, type_.properties.values()))
+ .Append('%(namespace)s::%(classname)s() {}')
.Append('%(namespace)s::~%(classname)s() {}')
.Append()
- .Concat(self._GenerateTypePopulate(cpp_namespace, type_))
- .Append()
)
- if serializable:
+ if type_.from_json:
+ (c.Concat(self._GenerateTypePopulate(cpp_namespace, type_))
+ .Append()
+ )
+ if type_.from_client:
c.Concat(self._GenerateTypeToValue(cpp_namespace, type_))
c.Append()
c.Substitute({'classname': classname, 'namespace': cpp_namespace})
@@ -129,7 +133,7 @@ class CCGenerator(object):
'if (%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s)) {'
)
.Concat(self._GeneratePopulatePropertyFromValue(
- prop, value_var, 'out', 'false'))
+ prop, value_var, dst, 'false'))
.Eblock('}')
)
else:
@@ -137,7 +141,7 @@ class CCGenerator(object):
'if (!%(src)s->GetWithoutPathExpansion("%(key)s", &%(value_var)s))')
.Append(' return false;')
.Concat(self._GeneratePopulatePropertyFromValue(
- prop, value_var, 'out', 'false'))
+ prop, value_var, dst, 'false'))
)
c.Append()
c.Substitute({'value_var': value_var, 'key': prop.name, 'src': src})
@@ -153,50 +157,23 @@ class CCGenerator(object):
.Append()
)
for prop in type_.properties.values():
- c.Concat(self._CreateValueFromProperty(prop, prop.unix_name, 'value'))
+ if prop.optional:
+ if prop.type_ == PropertyType.ENUM:
+ c.Sblock('if (%s != %s)' %
+ (prop.unix_name, self._cpp_type_generator.GetEnumNoneValue(prop)))
+ else:
+ c.Sblock('if (%s.get())' % prop.unix_name)
+ c.Append('value->SetWithoutPathExpansion("%s", %s);' % (
+ prop.name,
+ self._CreateValueFromProperty(prop, prop.unix_name)))
+ if prop.optional:
+ c.Eblock();
(c.Append()
.Append('return value.Pass();')
.Eblock('}')
)
return c
- def _CreateValueFromProperty(self, prop, var, dst):
- """Generates code to serialize a single property in a type.
-
- prop: Property to create from
- var: variable with value to create from
- """
- c = code.Code()
- if prop.type_ == PropertyType.ENUM:
- c.Sblock('switch (%s) {' % var)
- for enum_value in prop.enum_values:
- (c.Append('case %s: {' %
- self._cpp_type_generator.GetEnumValue(prop, enum_value))
- .Append(' %s->SetWithoutPathExpansion('
- '"%s", Value::CreateStringValue("%s"));' %
- (dst, prop.name, enum_value))
- .Append(' break;')
- .Append('}')
- )
- # C++ requires the entire enum to be handled by a switch.
- if prop.optional:
- (c.Append('case %s: {' %
- self._cpp_type_generator.GetEnumNoneValue(prop))
- .Append(' break;')
- .Append('}')
- )
- c.Eblock('}')
- else:
- if prop.optional:
- c.Sblock('if (%s.get())' % var)
- if prop.type_ == PropertyType.ARRAY:
- 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)))
- return c
-
def _GenerateFunction(self, function):
"""Generates the definitions for function structs.
"""
@@ -205,13 +182,8 @@ class CCGenerator(object):
# Params::Populate function
if function.params:
- for param in function.params:
- if param.type_ == PropertyType.OBJECT:
- param_namespace = '%s::Params::%s' % (classname,
- cpp_util.Classname(param.name))
- c.Concat(
- self._GenerateType(param_namespace, param, serializable=False))
- c.Append()
+ c.Concat(self._GeneratePropertyFunctions(classname + '::Params',
+ function.params))
(c.Append('%(name)s::Params::Params() {}')
.Append('%(name)s::Params::~Params() {}')
.Append()
@@ -220,12 +192,81 @@ class CCGenerator(object):
)
# Result::Create function
- c.Concat(self._GenerateFunctionResultCreate(function))
+ if function.callback:
+ c.Concat(self._GenerateFunctionResultCreate(function))
c.Substitute({'name': classname})
return c
+ def _GenerateCreateEnumValue(self, cpp_namespace, prop):
+ """Generates a function that returns the |StringValue| representation of an
+ enum.
+ """
+ c = code.Code()
+ c.Append('// static')
+ c.Sblock('scoped_ptr<Value> %(cpp_namespace)s::CreateEnumValue(%(arg)s) {')
+ c.Sblock('switch (%s) {' % prop.unix_name)
+ if prop.optional:
+ (c.Append('case %s: {' % self._cpp_type_generator.GetEnumNoneValue(prop))
+ .Append(' return scoped_ptr<Value>();')
+ .Append('}')
+ )
+ for enum_value in prop.enum_values:
+ (c.Append('case %s: {' %
+ self._cpp_type_generator.GetEnumValue(prop, enum_value))
+ .Append(' return scoped_ptr<Value>(Value::CreateStringValue("%s"));' %
+ enum_value)
+ .Append('}')
+ )
+ (c.Append('default: {')
+ .Append(' return scoped_ptr<Value>();')
+ .Append('}')
+ )
+ c.Eblock('}')
+ c.Eblock('}')
+ c.Substitute({
+ 'cpp_namespace': cpp_namespace,
+ 'arg': cpp_util.GetParameterDeclaration(
+ prop, self._cpp_type_generator.GetType(prop))
+ })
+ return c
+
+ def _CreateValueFromProperty(self, prop, var):
+ """Creates a Value given a single property. Generated code passes ownership
+ to caller.
+
+ var: variable or variable*
+ """
+ if prop.type_ == PropertyType.CHOICES:
+ # CHOICES conversion not implemented because it's not used. If needed,
+ # write something to generate a function that returns a scoped_ptr<Value>
+ # and put it in _GeneratePropertyFunctions.
+ raise NotImplementedError(
+ 'Conversion of CHOICES to Value not implemented')
+ 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_ == PropertyType.ENUM:
+ return 'CreateEnumValue(%s).release()' % var
+ elif prop.type_ == PropertyType.ARRAY:
+ return '%s.release()' % self._util_cc_helper.CreateValueFromArray(
+ prop, var)
+ elif prop.type_.is_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
+ else:
+ raise NotImplementedError('Conversion of %s to Value not '
+ 'implemented' % repr(prop.type_))
+
def _GenerateParamsCheck(self, function, var):
"""Generates a check for the correct number of arguments when creating
Params.
@@ -312,7 +353,7 @@ class CCGenerator(object):
c = code.Code()
c.Sblock('{')
- if check_type:
+ if check_type and prop.type_ != PropertyType.CHOICES:
(c.Append('if (!%(value_var)s->IsType(%(value_type)s))')
.Append(' return %(failure_value)s;')
)
@@ -358,7 +399,23 @@ class CCGenerator(object):
.Append(' return %(failure_value)s;')
)
elif prop.type_ == PropertyType.CHOICES:
- return self._GeneratePopulateChoices(prop, value_var, dst, failure_value)
+ type_var = '%(dst)s->%(name)s_type'
+ c.Sblock('switch (%(value_var)s->GetType()) {')
+ for choice in self._cpp_type_generator.GetExpandedChoicesInParams([prop]):
+ (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.GetEnumValue(
+ prop, choice.type_.name)))
+ .Append('break;')
+ .Eblock('}')
+ )
+ (c.Append('default:')
+ .Append(' return %(failure_value)s;')
+ )
+ c.Eblock('}')
elif prop.type_ == PropertyType.ENUM:
(c.Append('std::string enum_temp;')
.Append('if (!%(value_var)s->GetAsString(&enum_temp))')
@@ -379,46 +436,32 @@ class CCGenerator(object):
else:
raise NotImplementedError(prop.type_)
c.Eblock('}')
- c.Substitute({
+ sub = {
'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),
- })
+ }
+ if prop.type_ != PropertyType.CHOICES:
+ sub['ctype'] = self._cpp_type_generator.GetType(prop)
+ sub['value_type'] = cpp_util.GetValueType(prop)
+ c.Substitute(sub)
return c
- def _GeneratePopulateChoices(self, prop, value_var, dst, failure_value):
- """Generates the code to populate a PropertyType.CHOICES parameter or
- property. 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|.
+ def _GeneratePropertyFunctions(self, param_namespace, params):
+ """Generate the functions for structures generated by a property such as
+ CreateEnumValue for ENUMs and Populate/ToValue for Params/Result objects.
"""
- type_var = '%s->%s_type' % (dst, prop.unix_name)
-
c = code.Code()
- c.Sblock('switch (%s->GetType()) {' % value_var)
- for choice in self._cpp_type_generator.GetExpandedChoicesInParams([prop]):
- (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.GetEnumValue(
- prop, choice.type_.name)))
- .Append('break;')
- .Eblock('}')
- )
- (c.Append('default:')
- .Append(' return %s;' % failure_value)
- )
- c.Eblock('}')
+ for param in params:
+ if param.type_ == PropertyType.OBJECT:
+ c.Concat(self._GenerateType(
+ param_namespace + '::' + cpp_util.Classname(param.name),
+ param))
+ c.Append()
+ elif param.type_ == PropertyType.ENUM:
+ c.Concat(self._GenerateCreateEnumValue(param_namespace, param))
+ c.Append()
return c
def _GenerateFunctionResultCreate(self, function):
@@ -434,31 +477,28 @@ class CCGenerator(object):
.Append('}')
)
else:
+ expanded_params = self._cpp_type_generator.GetExpandedChoicesInParams(
+ params)
+ c.Concat(self._GeneratePropertyFunctions(
+ classname + '::Result', expanded_params))
+
# If there is a single parameter, this is straightforward. However, if
# the callback parameter is of 'choices', this generates a Create method
# for each choice. This works because only 1 choice can be returned at a
# time.
- for param in self._cpp_type_generator.GetExpandedChoicesInParams(params):
+ for param in expanded_params:
# 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.PopulateListFromArray(
- param_copy, param_copy.unix_name, 'value'))
- .Append('return value;')
- )
- else:
- c.Append('return %s;' %
- cpp_util.CreateValueFromSingleProperty(param_copy,
- param_copy.unix_name))
+ c.Append('return %s;' %
+ self._CreateValueFromProperty(param_copy, param_copy.unix_name))
+ c.Eblock('}')
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 6d3dd63..7965d18 100644
--- a/tools/json_schema_compiler/compiler.py
+++ b/tools/json_schema_compiler/compiler.py
@@ -28,7 +28,7 @@ import sys
if __name__ == '__main__':
parser = optparse.OptionParser(
description='Generates a C++ model of an API from JSON schema',
- usage='usage: %prog [option]... schema [referenced_schema]...')
+ usage='usage: %prog [option]... schema')
parser.add_option('-r', '--root', default='.',
help='logical include root directory. Path to schema files from specified'
'dir will be the include path.')
@@ -44,24 +44,27 @@ if __name__ == '__main__':
root_namespace = opts.namespace
schema = os.path.normpath(args[0])
- referenced_schemas = args[1:]
api_model = model.Model()
- # Load type dependencies into the model.
- for referenced_schema_path in referenced_schemas:
- with open(referenced_schema_path, 'r') as referenced_schema_file:
- referenced_api_defs = json.loads(referenced_schema_file.read())
-
- for namespace in referenced_api_defs:
- api_model.AddNamespace(namespace,
- os.path.relpath(referenced_schema_path, opts.root))
# Actually generate for source file.
with open(schema, 'r') as schema_file:
api_defs = json.loads(schema_file.read())
for target_namespace in api_defs:
+ referenced_schemas = target_namespace.get('dependencies', [])
+ # Load type dependencies into the model.
+ for referenced_schema in referenced_schemas:
+ referenced_schema_path = os.path.join(
+ os.path.dirname(schema), referenced_schema + '.json')
+ with open(referenced_schema_path, 'r') as referenced_schema_file:
+ referenced_api_defs = json.loads(referenced_schema_file.read())
+
+ for namespace in referenced_api_defs:
+ api_model.AddNamespace(namespace,
+ os.path.relpath(referenced_schema_path, opts.root))
+
# Gets the relative path from opts.root to the schema to correctly determine
# the include path.
relpath = os.path.relpath(schema, opts.root)
diff --git a/tools/json_schema_compiler/cpp_type_generator.py b/tools/json_schema_compiler/cpp_type_generator.py
index 186a616..cad64ae 100644
--- a/tools/json_schema_compiler/cpp_type_generator.py
+++ b/tools/json_schema_compiler/cpp_type_generator.py
@@ -189,8 +189,9 @@ class CppTypeGenerator(object):
for function in self._namespace.functions.values():
for param in function.params:
dependencies |= self._PropertyTypeDependencies(param)
- for param in function.callback.params:
- dependencies |= self._PropertyTypeDependencies(param)
+ if function.callback:
+ for param in function.callback.params:
+ dependencies |= self._PropertyTypeDependencies(param)
for type_ in self._namespace.types.values():
for prop in type_.properties.values():
dependencies |= self._PropertyTypeDependencies(prop)
diff --git a/tools/json_schema_compiler/cpp_type_generator_test.py b/tools/json_schema_compiler/cpp_type_generator_test.py
index d9d1082b..81ee04d 100644
--- a/tools/json_schema_compiler/cpp_type_generator_test.py
+++ b/tools/json_schema_compiler/cpp_type_generator_test.py
@@ -62,11 +62,11 @@ class CppTypeGeneratorTest(unittest.TestCase):
manager = CppTypeGenerator('', self.tabs, 'tabs_api')
prop = self.tabs.functions['move'].params[0]
self.assertEquals('TAB_IDS_ARRAY',
- manager.GetChoiceEnumValue(prop, model.PropertyType.ARRAY))
+ manager.GetEnumValue(prop, model.PropertyType.ARRAY))
self.assertEquals('TAB_IDS_INTEGER',
- manager.GetChoiceEnumValue(prop, model.PropertyType.INTEGER))
+ manager.GetEnumValue(prop, model.PropertyType.INTEGER))
self.assertEquals('TabIdsType',
- manager.GetChoicesEnumType(prop))
+ manager.GetEnumType(prop))
def testGetTypeSimple(self):
manager = CppTypeGenerator('', self.tabs, 'tabs_api')
diff --git a/tools/json_schema_compiler/cpp_util.py b/tools/json_schema_compiler/cpp_util.py
index 83d5265..fafc155 100644
--- a/tools/json_schema_compiler/cpp_util.py
+++ b/tools/json_schema_compiler/cpp_util.py
@@ -51,36 +51,12 @@ def GetValueType(prop):
PropertyType.ENUM: 'Value::TYPE_STRING',
PropertyType.REF: 'Value::TYPE_DICTIONARY',
PropertyType.OBJECT: 'Value::TYPE_DICTIONARY',
- PropertyType.ARRAY: 'Value::TYPE_LIST'
+ PropertyType.ARRAY: 'Value::TYPE_LIST',
+ PropertyType.ANY: 'Value::TYPE_DICTIONARY',
}[prop.type_]
-
-def CreateValueFromSingleProperty(prop, var):
- """Creates a Value given a single property. Use for everything except
- PropertyType.ARRAY.
-
- var: variable or variable*
- """
- 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:
- 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 GetParameterDeclaration(param, type_):
- """Gets a const parameter declaration of a given model.Property and its C++
+ """Gets a parameter declaration of a given model.Property and its C++
type.
"""
if param.type_ in (PropertyType.REF, PropertyType.OBJECT, PropertyType.ARRAY,
diff --git a/tools/json_schema_compiler/h_generator.py b/tools/json_schema_compiler/h_generator.py
index dfa4494..3af7ccf 100644
--- a/tools/json_schema_compiler/h_generator.py
+++ b/tools/json_schema_compiler/h_generator.py
@@ -42,6 +42,10 @@ class HGenerator(object):
)
c.Concat(self._cpp_type_generator.GetRootNamespaceStart())
+ # TODO(calamity): These forward declarations should be #includes to allow
+ # $ref types from other files to be used as required params. This requires
+ # some detangling of windows and tabs which will currently lead to circular
+ # #includes.
forward_declarations = (
self._cpp_type_generator.GenerateForwardDeclarations())
if not forward_declarations.IsEmpty():
@@ -50,26 +54,28 @@ class HGenerator(object):
.Append()
)
- (c.Concat(self._cpp_type_generator.GetNamespaceStart())
- .Append()
- .Append('//')
- .Append('// Types')
- .Append('//')
- .Append()
- )
- for type_ in self._namespace.types.values():
- (c.Concat(self._GenerateType(type_))
+ c.Concat(self._cpp_type_generator.GetNamespaceStart())
+ c.Append()
+ if self._namespace.types:
+ (c.Append('//')
+ .Append('// Types')
+ .Append('//')
.Append()
)
- (c.Append('//')
- .Append('// Functions')
- .Append('//')
- .Append()
- )
- for function in self._namespace.functions.values():
- (c.Concat(self._GenerateFunction(function))
+ for type_ in self._namespace.types.values():
+ (c.Concat(self._GenerateType(type_))
+ .Append()
+ )
+ if self._namespace.functions:
+ (c.Append('//')
+ .Append('// Functions')
+ .Append('//')
.Append()
)
+ for function in self._namespace.functions.values():
+ (c.Concat(self._GenerateFunction(function))
+ .Append()
+ )
(c.Append()
.Concat(self._cpp_type_generator.GetNamespaceEnd())
.Concat(self._cpp_type_generator.GetRootNamespaceEnd())
@@ -80,6 +86,9 @@ class HGenerator(object):
return c
def _GenerateEnumDeclaration(self, enum_name, prop, values):
+ """Generate the declaration of a C++ enum for the given property and
+ values.
+ """
c = code.Code()
c.Sblock('enum %s {' % enum_name)
if prop.optional:
@@ -99,16 +108,7 @@ class HGenerator(object):
for prop in props:
if prop.type_ == PropertyType.CHOICES:
enum_name = self._cpp_type_generator.GetChoicesEnumType(prop)
- c.Concat(self._GenerateEnumDeclaration(
- enum_name,
- prop,
- [choice.type_.name for choice in prop.choices.values()]))
c.Append('%s %s_type;' % (enum_name, prop.unix_name))
- elif prop.type_ == PropertyType.ENUM:
- c.Concat(self._GenerateEnumDeclaration(
- self._cpp_type_generator.GetType(prop),
- prop,
- prop.enum_values))
for prop in self._cpp_type_generator.GetExpandedChoicesInParams(props):
if prop.description:
c.Comment(prop.description)
@@ -118,7 +118,7 @@ class HGenerator(object):
c.Append()
return c
- def _GenerateType(self, type_, serializable=True):
+ def _GenerateType(self, type_):
"""Generates a struct for a type.
"""
classname = cpp_util.Classname(type_.name)
@@ -129,17 +129,20 @@ class HGenerator(object):
.Append('~%(classname)s();')
.Append('%(classname)s();')
.Append()
+ .Concat(self._GeneratePropertyStructures(type_.properties.values()))
.Concat(self._GenerateFields(type_.properties.values()))
- .Comment('Populates a %(classname)s object from a Value. Returns'
- ' whether |out| was successfully populated.')
+ )
+ if type_.from_json:
+ (c.Comment('Populates a %s object from a Value. Returns'
+ ' whether |out| was successfully populated.' % classname)
.Append('static bool Populate(const Value& value, %(classname)s* out);')
.Append()
- )
+ )
- if serializable:
+ if type_.from_client:
(c.Comment('Returns a new DictionaryValue representing the'
- ' serialized form of this %(classname)s object. Passes '
- 'ownership to caller.')
+ ' serialized form of this %s object. Passes '
+ 'ownership to caller.' % classname)
.Append('scoped_ptr<DictionaryValue> ToValue() const;')
)
(c.Eblock()
@@ -157,10 +160,13 @@ class HGenerator(object):
(c.Sblock('namespace %s {' % cpp_util.Classname(function.name))
.Concat(self._GenerateFunctionParams(function))
.Append()
- .Concat(self._GenerateFunctionResult(function))
- .Append()
- .Eblock('};')
)
+ if function.callback:
+ (c.Concat(self._GenerateFunctionResult(function))
+ .Append()
+ )
+ c.Eblock('};')
+
return c
def _GenerateFunctionParams(self, function):
@@ -169,25 +175,46 @@ class HGenerator(object):
c = code.Code()
if function.params:
- c.Sblock('struct Params {')
- for param in function.params:
- if param.type_ == PropertyType.OBJECT:
- c.Concat(self._GenerateType(param, serializable=False))
- c.Append()
- (c.Concat(self._GenerateFields(function.params))
- .Append('~Params();')
- .Append()
- .Append('static scoped_ptr<Params> Create(const ListValue& args);')
- .Eblock()
- .Sblock(' private:')
- .Append('Params();')
- .Append()
- .Append('DISALLOW_COPY_AND_ASSIGN(Params);')
- .Eblock('};')
+ (c.Sblock('struct Params {')
+ .Concat(self._GeneratePropertyStructures(function.params))
+ .Concat(self._GenerateFields(function.params))
+ .Append('~Params();')
+ .Append()
+ .Append('static scoped_ptr<Params> Create(const ListValue& args);')
+ .Eblock()
+ .Sblock(' private:')
+ .Append('Params();')
+ .Append()
+ .Append('DISALLOW_COPY_AND_ASSIGN(Params);')
+ .Eblock('};')
)
return c
+ def _GeneratePropertyStructures(self, props):
+ """Generate the structures required by a property such as OBJECT classes
+ and enums.
+ """
+ c = code.Code()
+ for prop in props:
+ if prop.type_ == PropertyType.OBJECT:
+ c.Concat(self._GenerateType(prop))
+ c.Append()
+ elif prop.type_ == PropertyType.CHOICES:
+ c.Concat(self._GenerateEnumDeclaration(
+ self._cpp_type_generator.GetChoicesEnumType(prop),
+ prop,
+ [choice.type_.name for choice in prop.choices.values()]))
+ elif prop.type_ == PropertyType.ENUM:
+ enum_name = self._cpp_type_generator.GetType(prop)
+ c.Concat(self._GenerateEnumDeclaration(
+ enum_name,
+ prop,
+ prop.enum_values))
+ c.Append('static scoped_ptr<Value> CreateEnumValue(%s %s);' %
+ (enum_name, prop.unix_name))
+ return c
+
def _GenerateFunctionResult(self, function):
"""Generates functions for passing a function's result back.
"""
@@ -198,6 +225,8 @@ class HGenerator(object):
if not params:
c.Append('Value* Create();')
else:
+ c.Concat(self._GeneratePropertyStructures(params))
+
# If there is a single parameter, this is straightforward. However, if
# the callback parameter is of 'choices', this generates a Create method
# for each choice. This works because only 1 choice can be returned at a
@@ -205,8 +234,6 @@ class HGenerator(object):
for param in self._cpp_type_generator.GetExpandedChoicesInParams(params):
if param.description:
c.Comment(param.description)
- 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('};')
diff --git a/tools/json_schema_compiler/model.py b/tools/json_schema_compiler/model.py
index 5ff394a..d839ab9 100644
--- a/tools/json_schema_compiler/model.py
+++ b/tools/json_schema_compiler/model.py
@@ -60,13 +60,22 @@ class Type(object):
- |name| the type name
- |description| the description of the type (if provided)
- |properties| a map of property names to their model.Property
+ - |from_client| indicates that instances of the Type can originate from the
+ users of generated code, such as top-level types and function results
+ - |from_json| indicates that instances of the Type can originate from the
+ JSON (as described by the schema), such as top-level types and function
+ parameters
"""
def __init__(self, json):
self.name = json['id']
self.description = json.get('description')
+ self.from_json = True
+ self.from_client = True
self.properties = {}
for prop_name, prop_json in json['properties'].items():
- self.properties[prop_name] = Property(prop_name, prop_json)
+ self.properties[prop_name] = Property(prop_name, prop_json,
+ from_json=True,
+ from_client=True)
class Callback(object):
"""A callback parameter to a Function.
@@ -81,7 +90,8 @@ class Callback(object):
return
elif len(params) == 1:
param = params[0]
- self.params.append(Property(param['name'], param))
+ self.params.append(Property(param['name'], param,
+ from_client=True))
else:
raise AssertionError("Callbacks can have at most a single parameter")
@@ -106,8 +116,8 @@ class Function(object):
assert (not self.callback), self.name + " has more than one callback"
self.callback = Callback(param)
else:
- self.params.append(Property(param['name'], param))
- assert (self.callback), self.name + " does not support callback"
+ self.params.append(Property(param['name'], param,
+ from_json=True))
class Property(object):
"""A property of a type OR a parameter to a function.
@@ -125,9 +135,17 @@ class Property(object):
ARRAY
- |properties| the properties of an OBJECT parameter
"""
- def __init__(self, name, json):
- if not re.match('^[a-z][a-zA-Z0-9]*$', name):
- raise AssertionError('Name %s must be lowerCamelCase' % name)
+ def __init__(self, name, json,
+ from_json=False,
+ from_client=False):
+ """
+ Parameters:
+ - |from_json| indicates that instances of the Type can originate from the
+ JSON (as described by the schema), such as top-level types and function
+ parameters
+ - |from_client| indicates that instances of the Type can originate from the
+ users of generated code, such as top-level types and function results
+ """
self.name = name
self._unix_name = _UnixName(self.name)
self._unix_name_used = False
@@ -154,13 +172,20 @@ class Property(object):
elif json_type == 'number':
self.type_ = PropertyType.DOUBLE
elif json_type == 'array':
- self.item_type = Property(name + "Element", json['items'])
+ self.item_type = Property(name + "Element", json['items'],
+ from_json,
+ from_client)
self.type_ = PropertyType.ARRAY
elif json_type == 'object':
- self.properties = {}
self.type_ = PropertyType.OBJECT
- for key, val in json['properties'].items():
- self.properties[key] = Property(key, val)
+ # These members are read when this OBJECT Property is used as a Type
+ self.properties = {}
+ self.from_json = from_json
+ self.from_client = from_client
+ for key, val in json.get('properties', {}).items():
+ self.properties[key] = Property(key, val,
+ from_json,
+ from_client)
else:
raise NotImplementedError(json_type)
elif 'choices' in json:
@@ -168,7 +193,9 @@ class Property(object):
self.choices = {}
self.type_ = PropertyType.CHOICES
for choice_json in json['choices']:
- choice = Property(self.name, choice_json)
+ choice = Property(self.name, choice_json,
+ from_json,
+ from_client)
# A choice gets its unix_name set in
# cpp_type_generator.GetExpandedChoicesInParams
choice._unix_name = None
diff --git a/tools/json_schema_compiler/test/array.json b/tools/json_schema_compiler/test/arrays.json
index 64dbdd4..26e5825 100644
--- a/tools/json_schema_compiler/test/array.json
+++ b/tools/json_schema_compiler/test/arrays.json
@@ -1,6 +1,6 @@
[
{
- "namespace": "array",
+ "namespace": "arrays",
"types": [
{
"id": "BasicArrayType",
@@ -48,7 +48,7 @@
{
"name": "integerArray",
"type": "function",
- "description": "Increments the given integer.",
+ "description": "Takes some integers.",
"parameters": [
{
"name": "nums",
diff --git a/tools/json_schema_compiler/test/array_unittest.cc b/tools/json_schema_compiler/test/arrays_unittest.cc
index 6db2d5e..405fbb1 100644
--- a/tools/json_schema_compiler/test/array_unittest.cc
+++ b/tools/json_schema_compiler/test/arrays_unittest.cc
@@ -2,11 +2,11 @@
// 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 "tools/json_schema_compiler/test/arrays.h"
#include "testing/gtest/include/gtest/gtest.h"
-using namespace test::api::array;
+using namespace test::api::arrays;
namespace {
@@ -61,7 +61,7 @@ TEST(JsonSchemaCompilerArrayTest, RefArrayType) {
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((size_t) 3, 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);
@@ -87,7 +87,7 @@ TEST(JsonSchemaCompilerArrayTest, IntegerArrayParamsCreate) {
scoped_ptr<IntegerArray::Params> params(
IntegerArray::Params::Create(*params_value));
EXPECT_TRUE(params.get());
- EXPECT_EQ(3UL, params->nums.size());
+ EXPECT_EQ((size_t) 3, params->nums.size());
EXPECT_EQ(2, params->nums[0]);
EXPECT_EQ(4, params->nums[1]);
EXPECT_EQ(8, params->nums[2]);
@@ -102,7 +102,7 @@ TEST(JsonSchemaCompilerArrayTest, RefArrayParamsCreate) {
scoped_ptr<RefArray::Params> params(
RefArray::Params::Create(*params_value));
EXPECT_TRUE(params.get());
- EXPECT_EQ(2UL, params->refs.size());
+ EXPECT_EQ((size_t) 2, params->refs.size());
EXPECT_EQ(1, params->refs[0]->val);
EXPECT_EQ(2, params->refs[1]->val);
}
@@ -115,7 +115,7 @@ TEST(JsonSchemaCompilerArrayTest, ReturnIntegerArrayResultCreate) {
ListValue* list = NULL;
EXPECT_TRUE(result->GetAsList(&list));
int temp;
- EXPECT_EQ(2UL, list->GetSize());
+ EXPECT_EQ((size_t) 2, list->GetSize());
EXPECT_TRUE(list->GetInteger(0, &temp));
EXPECT_EQ(1, temp);
EXPECT_TRUE(list->GetInteger(1, &temp));
@@ -131,7 +131,7 @@ TEST(JsonSchemaCompilerArrayTest, ReturnRefArrayResultCreate) {
scoped_ptr<Value> result(ReturnRefArray::Result::Create(items));
ListValue* list = NULL;
EXPECT_TRUE(result->GetAsList(&list));
- EXPECT_EQ(2UL, list->GetSize());
+ EXPECT_EQ((size_t) 2, list->GetSize());
DictionaryValue* item_value = NULL;
int temp;
EXPECT_TRUE(list->GetDictionary(0, &item_value));
diff --git a/tools/json_schema_compiler/test/choices_unittest.cc b/tools/json_schema_compiler/test/choices_unittest.cc
index 32bab69..dcdfd77 100644
--- a/tools/json_schema_compiler/test/choices_unittest.cc
+++ b/tools/json_schema_compiler/test/choices_unittest.cc
@@ -36,7 +36,7 @@ TEST(JsonSchemaCompilerChoicesTest, TakesIntegersParamsCreate) {
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((size_t) 2, (*params->nums_array).size());
EXPECT_EQ(6, (*params->nums_array)[0]);
EXPECT_EQ(8, (*params->nums_array)[1]);
}
@@ -119,7 +119,7 @@ TEST(JsonSchemaCompilerChoicesTest, ReturnChoices) {
scoped_ptr<Value> array_result(ReturnChoices::Result::Create(integers));
ListValue* list = NULL;
EXPECT_TRUE(array_result->GetAsList(&list));
- EXPECT_EQ(2UL, list->GetSize());
+ EXPECT_EQ((size_t) 2, list->GetSize());
int temp;
EXPECT_TRUE(list->GetInteger(0, &temp));
EXPECT_EQ(1, temp);
diff --git a/tools/json_schema_compiler/test/crossref.json b/tools/json_schema_compiler/test/crossref.json
index 8a74059..02e5c94 100644
--- a/tools/json_schema_compiler/test/crossref.json
+++ b/tools/json_schema_compiler/test/crossref.json
@@ -2,10 +2,21 @@
{
"namespace": "crossref",
"dependencies": ["simple_api"],
- "types": [],
+ "types": [
+ {
+ "id": "CrossrefType",
+ "type": "object",
+ "properties": {
+ "testType": {
+ "$ref": "TestType",
+ "optional": true
+ }
+ }
+ }
+ ],
"functions": [
{
- "name": "TestTypeOptionalParam",
+ "name": "testTypeOptionalParam",
"type": "function",
"description": "Takes TestType as a param.",
"parameters": [
@@ -38,6 +49,26 @@
]
}
]
+ },
+ {
+ "name": "testTypeInObject",
+ "type": "function",
+ "description": "Takes an optional object with a TestType and a bool.",
+ "parameters": [
+ {
+ "name": "paramObject",
+ "type": "object",
+ "properties": {
+ "testType": {"$ref": "TestType", "optional": true},
+ "boolean": {"type": "boolean"}
+ }
+ },
+ {
+ "name": "callback",
+ "type": "function",
+ "parameters": []
+ }
+ ]
}
]
}
diff --git a/tools/json_schema_compiler/test/crossref_unittest.cc b/tools/json_schema_compiler/test/crossref_unittest.cc
index ab39f39..cf7189e 100644
--- a/tools/json_schema_compiler/test/crossref_unittest.cc
+++ b/tools/json_schema_compiler/test/crossref_unittest.cc
@@ -22,10 +22,20 @@ static scoped_ptr<DictionaryValue> CreateTestTypeDictionary() {
} // namespace
+TEST(JsonSchemaCompilerCrossrefTest, CrossrefTypePopulate) {
+ scoped_ptr<CrossrefType> crossref_type(new CrossrefType());
+ scoped_ptr<DictionaryValue> value(new DictionaryValue());
+ value->Set("testType", CreateTestTypeDictionary().release());
+ EXPECT_TRUE(CrossrefType::Populate(*value, crossref_type.get()));
+ EXPECT_TRUE(crossref_type->test_type.get());
+ EXPECT_TRUE(CreateTestTypeDictionary()->Equals(
+ crossref_type->test_type->ToValue().get()));
+ EXPECT_TRUE(value->Equals(crossref_type->ToValue().get()));
+}
+
TEST(JsonSchemaCompilerCrossrefTest, TestTypeOptionalParamCreate) {
scoped_ptr<ListValue> params_value(new ListValue());
- scoped_ptr<DictionaryValue> test_type_value = CreateTestTypeDictionary();
- params_value->Append(test_type_value.release());
+ params_value->Append(CreateTestTypeDictionary().release());
scoped_ptr<TestTypeOptionalParam::Params> params(
TestTypeOptionalParam::Params::Create(*params_value));
EXPECT_TRUE(params.get());
@@ -53,3 +63,50 @@ TEST(JsonSchemaCompilerCrossrefTest, GetTestType) {
scoped_ptr<Value> result(GetTestType::Result::Create(*test_type));
EXPECT_TRUE(value->Equals(result.get()));
}
+
+TEST(JsonSchemaCompilerCrossrefTest, TestTypeInObjectParamsCreate) {
+ {
+ scoped_ptr<ListValue> params_value(new ListValue());
+ scoped_ptr<DictionaryValue> param_object_value(new DictionaryValue());
+ param_object_value->Set("testType", CreateTestTypeDictionary().release());
+ param_object_value->Set("boolean", Value::CreateBooleanValue(true));
+ params_value->Append(param_object_value.release());
+ scoped_ptr<TestTypeInObject::Params> params(
+ TestTypeInObject::Params::Create(*params_value));
+ EXPECT_TRUE(params.get());
+ EXPECT_TRUE(params->param_object.test_type.get());
+ EXPECT_TRUE(params->param_object.boolean);
+ EXPECT_TRUE(CreateTestTypeDictionary()->Equals(
+ params->param_object.test_type->ToValue().get()));
+ }
+ {
+ scoped_ptr<ListValue> params_value(new ListValue());
+ scoped_ptr<DictionaryValue> param_object_value(new DictionaryValue());
+ param_object_value->Set("boolean", Value::CreateBooleanValue(true));
+ params_value->Append(param_object_value.release());
+ scoped_ptr<TestTypeInObject::Params> params(
+ TestTypeInObject::Params::Create(*params_value));
+ EXPECT_TRUE(params.get());
+ EXPECT_FALSE(params->param_object.test_type.get());
+ EXPECT_TRUE(params->param_object.boolean);
+ }
+ {
+ scoped_ptr<ListValue> params_value(new ListValue());
+ scoped_ptr<DictionaryValue> param_object_value(new DictionaryValue());
+ param_object_value->Set("testType", Value::CreateStringValue("invalid"));
+ param_object_value->Set("boolean", Value::CreateBooleanValue(true));
+ params_value->Append(param_object_value.release());
+ scoped_ptr<TestTypeInObject::Params> params(
+ TestTypeInObject::Params::Create(*params_value));
+ EXPECT_FALSE(params.get());
+ }
+ {
+ scoped_ptr<ListValue> params_value(new ListValue());
+ scoped_ptr<DictionaryValue> param_object_value(new DictionaryValue());
+ param_object_value->Set("testType", CreateTestTypeDictionary().release());
+ params_value->Append(param_object_value.release());
+ scoped_ptr<TestTypeInObject::Params> params(
+ TestTypeInObject::Params::Create(*params_value));
+ EXPECT_FALSE(params.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
index d22d83f..8f32acb 100644
--- a/tools/json_schema_compiler/test/json_schema_compiler_tests.gyp
+++ b/tools/json_schema_compiler/test/json_schema_compiler_tests.gyp
@@ -10,10 +10,11 @@
'variables': {
'chromium_code': 1,
'json_schema_files': [
- 'array.json',
+ 'arrays.json',
'choices.json',
'crossref.json',
'enums.json',
+ 'objects.json',
'simple_api.json',
],
'cc_dir': 'tools/json_schema_compiler/test',
diff --git a/tools/json_schema_compiler/test/objects.json b/tools/json_schema_compiler/test/objects.json
new file mode 100644
index 0000000..8fb20b4
--- /dev/null
+++ b/tools/json_schema_compiler/test/objects.json
@@ -0,0 +1,60 @@
+[
+ {
+ "namespace": "objects",
+ "types": [],
+ "functions": [
+ {
+ "name": "objectParam",
+ "type": "function",
+ "description": "Takes an object.",
+ "parameters": [
+ {
+ "name": "info",
+ "type": "object",
+ "properties": {
+ "strings": {
+ "type": "array",
+ "items": {"type": "string"}
+ },
+ "integer": {
+ "type": "integer"
+ },
+ "boolean": {
+ "type": "boolean"
+ }
+ }
+ },
+ {
+ "name": "callback",
+ "type": "function",
+ "parameters": []
+ }
+ ]
+ },
+ {
+ "name": "returnsObject",
+ "description": "Returns an object.",
+ "type": "function",
+ "parameters": [
+ {
+ "name": "callback",
+ "type": "function",
+ "parameters": [
+ {
+ "name": "info",
+ "type": "object",
+ "properties": {
+ "state": {
+ "type": "string",
+ "enum": ["foo", "bar", "baz"]
+ }
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+]
+
diff --git a/tools/json_schema_compiler/test/objects_unittest.cc b/tools/json_schema_compiler/test/objects_unittest.cc
new file mode 100644
index 0000000..b0ed54f
--- /dev/null
+++ b/tools/json_schema_compiler/test/objects_unittest.cc
@@ -0,0 +1,59 @@
+// 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/objects.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using namespace test::api::objects;
+
+TEST(JsonSchemaCompilerObjectsTest, ObjectParamParamsCreate) {
+ {
+ scoped_ptr<ListValue> strings(new ListValue());
+ strings->Append(Value::CreateStringValue("one"));
+ strings->Append(Value::CreateStringValue("two"));
+ scoped_ptr<DictionaryValue> info_value(new DictionaryValue());
+ info_value->Set("strings", strings.release());
+ info_value->Set("integer", Value::CreateIntegerValue(5));
+ info_value->Set("boolean", Value::CreateBooleanValue(true));
+
+ scoped_ptr<ListValue> params_value(new ListValue());
+ params_value->Append(info_value.release());
+ scoped_ptr<ObjectParam::Params> params(
+ ObjectParam::Params::Create(*params_value));
+ EXPECT_TRUE(params.get());
+ EXPECT_EQ((size_t) 2, params->info.strings.size());
+ EXPECT_EQ("one", params->info.strings[0]);
+ EXPECT_EQ("two", params->info.strings[1]);
+ EXPECT_EQ(5, params->info.integer);
+ EXPECT_TRUE(params->info.boolean);
+ }
+ {
+ scoped_ptr<ListValue> strings(new ListValue());
+ strings->Append(Value::CreateStringValue("one"));
+ strings->Append(Value::CreateStringValue("two"));
+ scoped_ptr<DictionaryValue> info_value(new DictionaryValue());
+ info_value->Set("strings", strings.release());
+ info_value->Set("integer", Value::CreateIntegerValue(5));
+
+ scoped_ptr<ListValue> params_value(new ListValue());
+ params_value->Append(info_value.release());
+ scoped_ptr<ObjectParam::Params> params(
+ ObjectParam::Params::Create(*params_value));
+ EXPECT_FALSE(params.get());
+ }
+}
+
+TEST(JsonSchemaCompilerObjectsTest, ReturnsObjectResultCreate) {
+ scoped_ptr<ReturnsObject::Result::Info> info(
+ new ReturnsObject::Result::Info());
+ info->state = ReturnsObject::Result::Info::STATE_FOO;
+ scoped_ptr<Value> result_value(
+ ReturnsObject::Result::Create(*info));
+ DictionaryValue* result_dict = NULL;
+ EXPECT_TRUE(result_value->GetAsDictionary(&result_dict));
+ std::string state;
+ EXPECT_TRUE(result_dict->GetString("state", &state));
+ EXPECT_EQ("foo", state);
+}
diff --git a/tools/json_schema_compiler/test/simple_api_unittest.cc b/tools/json_schema_compiler/test/simple_api_unittest.cc
index b88232b..6cc2832 100644
--- a/tools/json_schema_compiler/test/simple_api_unittest.cc
+++ b/tools/json_schema_compiler/test/simple_api_unittest.cc
@@ -37,6 +37,23 @@ TEST(JsonSchemaCompilerSimpleTest, IncrementIntegerParamsCreate) {
EXPECT_EQ(6, params->num);
}
+TEST(JsonSchemaCompilerSimpleTest, NumberOfParams) {
+ {
+ scoped_ptr<ListValue> params_value(new ListValue());
+ params_value->Append(Value::CreateStringValue("text"));
+ params_value->Append(Value::CreateStringValue("text"));
+ scoped_ptr<OptionalString::Params> params(
+ OptionalString::Params::Create(*params_value));
+ EXPECT_FALSE(params.get());
+ }
+ {
+ scoped_ptr<ListValue> params_value(new ListValue());
+ scoped_ptr<IncrementInteger::Params> params(
+ IncrementInteger::Params::Create(*params_value));
+ EXPECT_FALSE(params.get());
+ }
+}
+
TEST(JsonSchemaCompilerSimpleTest, OptionalStringParamsCreate) {
{
scoped_ptr<ListValue> params_value(new ListValue());
@@ -97,7 +114,7 @@ TEST(JsonSchemaCompilerSimpleTest, TestTypePopulate) {
{
scoped_ptr<TestType> test_type(new TestType());
scoped_ptr<DictionaryValue> value = CreateTestTypeDictionary();
- value->RemoveWithoutPathExpansion("number", NULL);
+ value->Remove("number", NULL);
EXPECT_FALSE(TestType::Populate(*value, test_type.get()));
}
}
diff --git a/tools/json_schema_compiler/util.h b/tools/json_schema_compiler/util.h
index 707c626..f71c93c 100644
--- a/tools/json_schema_compiler/util.h
+++ b/tools/json_schema_compiler/util.h
@@ -150,30 +150,22 @@ void PopulateListFromOptionalArray(
}
-// Sets |out|.|name| to a newly created ListValue containing |from|. Requires
-// GetItemFromList to be implemented for |T|.
template <class T>
-void PopulateDictionaryFromArray(
- const std::vector<T>& from,
- const std::string& name,
- base::DictionaryValue* out) {
+scoped_ptr<Value> CreateValueFromArray(
+ const std::vector<T>& from) {
base::ListValue* list = new base::ListValue();
- out->SetWithoutPathExpansion(name, list);
PopulateListFromArray(from, list);
+ return scoped_ptr<Value>(list);
}
-// If |from| is non-NULL, sets |out|.|name| to a newly created ListValue
-// containing |from|. Requires GetItemFromList to be implemented for |T|.
template <class T>
-void PopulateDictionaryFromOptionalArray(
- const scoped_ptr<std::vector<T> >& from,
- const std::string& name,
- base::DictionaryValue* out) {
+scoped_ptr<Value> CreateValueFromOptionalArray(
+ const scoped_ptr<std::vector<T> >& from) {
if (from.get())
- PopulateDictionaryFromArray(*from, name, out);
+ return CreateValueFromArray(*from);
+ return scoped_ptr<Value>();
}
-
} // namespace api_util
} // namespace extensions
diff --git a/tools/json_schema_compiler/util_cc_helper.py b/tools/json_schema_compiler/util_cc_helper.py
index fe4e858..18dcb02 100644
--- a/tools/json_schema_compiler/util_cc_helper.py
+++ b/tools/json_schema_compiler/util_cc_helper.py
@@ -56,48 +56,22 @@ class UtilCCHelper(object):
return val % sub
- def PopulateDictionaryFromArray(self, array_prop, src, name, dst):
- """Generates code to set dst.name to the array at src
+ def CreateValueFromArray(self, array_prop, src):
+ """Generates code to create a scoped_pt<Value> from the array at src.
src: std::vector or scoped_ptr<std::vector>
- dst: scoped_ptr<DictionaryValue>
"""
prop = array_prop.item_type
sub = {
'namespace': API_UTIL_NAMESPACE,
'src': src,
- 'name': name,
- 'dst': dst,
- 'type': self._type_manager.GetType(prop),
- }
-
- if array_prop.optional:
- val = ('%(namespace)s::PopulateDictionaryFromOptionalArray'
- '(%(src)s, "%(name)s", %(dst)s.get())')
- else:
- val = ('%(namespace)s::PopulateDictionaryFromArray'
- '(%(src)s, "%(name)s", %(dst)s.get())')
-
- return val % sub
-
- 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>
- dst: ListValue*
- """
- prop = array_prop.item_type
- sub = {
- 'namespace': API_UTIL_NAMESPACE,
- 'src': src,
- 'dst': dst,
'type': self._type_manager.GetType(prop),
}
if array_prop.optional:
- val = '%(namespace)s::PopulateListFromOptionalArray(%(src)s, %(dst)s)'
+ val = '%(namespace)s::CreateValueFromOptionalArray(%(src)s)'
else:
- val = '%(namespace)s::PopulateListFromArray(%(src)s, %(dst)s)'
+ val = '%(namespace)s::CreateValueFromArray(%(src)s)'
return val % sub