summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcalamity@chromium.org <calamity@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-21 01:13:07 +0000
committercalamity@chromium.org <calamity@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-21 01:13:07 +0000
commit712eca0f458b38d5fe47c14932302ad3f14e292d (patch)
tree905236d46f0a4c471745ead8ad371910b89b5bd0
parent17f5abff8f422bbfd63bfbb809a86464fd20f7ce (diff)
downloadchromium_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.gypi5
-rw-r--r--tools/json_schema_compiler/cc_generator.py345
-rw-r--r--tools/json_schema_compiler/compiler.py13
-rw-r--r--tools/json_schema_compiler/cpp_type_generator.py3
-rw-r--r--tools/json_schema_compiler/cpp_util.py79
-rw-r--r--tools/json_schema_compiler/h_generator.py9
-rw-r--r--tools/json_schema_compiler/model.py24
-rw-r--r--tools/json_schema_compiler/test/array.json120
-rw-r--r--tools/json_schema_compiler/test/array_unittest.cc143
-rw-r--r--tools/json_schema_compiler/test/choices.json101
-rw-r--r--tools/json_schema_compiler/test/choices_unittest.cc135
-rw-r--r--tools/json_schema_compiler/test/crossref.json43
-rw-r--r--tools/json_schema_compiler/test/crossref_unittest.cc55
-rw-r--r--tools/json_schema_compiler/test/json_schema_compiler_tests.gyp27
-rw-r--r--tools/json_schema_compiler/test/simple_api.json106
-rw-r--r--tools/json_schema_compiler/test/simple_api_unittest.cc111
-rw-r--r--tools/json_schema_compiler/util_cc_helper.py12
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>