Commit 0c7a8ec9 authored by dglazkov's avatar dglazkov Committed by Commit bot

Add first bindings unit test and enable testing.

Also:
* Quick refactor of jinja2 context creation into a builder.
* Switched Attribute/Method to dicts.
* Added a bit more meat more to header template.
* Added nicer parameter handling to run-bindings-tests
* Added stub helper for unit tests.

BUG=654129
R=bashi,yukishiino,haraken

Review-Url: https://codereview.chromium.org/2568693002
Cr-Commit-Position: refs/heads/master@{#437989}
parent b46a672f
...@@ -38,46 +38,62 @@ def includes_for_type(idl_type): ...@@ -38,46 +38,62 @@ def includes_for_type(idl_type):
def interface_context(idl_interface): def interface_context(idl_interface):
attributes = [] builder = InterfaceContextBuilder(MODULE_PYNAME)
methods = [] builder.set_class_name(idl_interface.name)
includes = set()
for idl_attribute in idl_interface.attributes: for idl_attribute in idl_interface.attributes:
attributes.append(Attribute.create(idl_attribute)) builder.add_attribute(idl_attribute)
includes.update(includes_for_type(idl_attribute.idl_type))
for idl_operation in idl_interface.operations: for idl_operation in idl_interface.operations:
if idl_operation.name: builder.add_operation(idl_operation)
methods.append(Method.create(idl_operation))
return { return builder.build()
'code_generator': MODULE_PYNAME,
'class_name': idl_interface.name,
'cpp_includes': includes, class InterfaceContextBuilder(object):
'attributes': attributes, def __init__(self, code_generator):
'methods': methods, self.result = {'code_generator': code_generator}
}
class Attribute(object):
def __init__(self, name, return_type):
self.name = name
self.return_type = return_type
@staticmethod
def create(idl_attribute):
name = idl_attribute.name
return_type = idl_attribute.idl_type.preprocessed_type.base_type
return Attribute(name, return_type)
def set_class_name(self, class_name):
self.result['class_name'] = class_name
class Method(object): def _ensure_set(self, name):
def __init__(self, name, return_type): return self.result.setdefault(name, set())
self.name = name
self.return_type = return_type
@staticmethod def _ensure_list(self, name):
def create(idl_operation): return self.result.setdefault(name, [])
def add_attribute(self, idl_attribute):
self._ensure_list('attributes').append(
self.create_attribute(idl_attribute))
self._ensure_set('cpp_includes').update(
includes_for_type(idl_attribute.idl_type))
def add_operation(self, idl_operation):
if idl_operation.name:
self._ensure_list('methods').append(
self.create_method(idl_operation))
self._ensure_set('cpp_includes').update(
includes_for_type(idl_operation.idl_type))
def create_method(self, idl_operation):
name = idl_operation.name name = idl_operation.name
return_type = idl_operation.idl_type.preprocessed_type.base_type return_type = idl_operation.idl_type.preprocessed_type.base_type
return Method(name, return_type) return {
'name': name,
'return_type': return_type
}
def create_attribute(self, idl_attribute):
name = idl_attribute.name
return_type = idl_attribute.idl_type.preprocessed_type.base_type
return {
'name': name,
'return_type': return_type
}
def build(self):
return self.result
class CodeGeneratorWebModule(CodeGeneratorBase): class CodeGeneratorWebModule(CodeGeneratorBase):
...@@ -102,7 +118,7 @@ class CodeGeneratorWebModule(CodeGeneratorBase): ...@@ -102,7 +118,7 @@ class CodeGeneratorWebModule(CodeGeneratorBase):
# TODO(dglazkov): Implement callback interfaces. # TODO(dglazkov): Implement callback interfaces.
# TODO(dglazkov): Make sure partial interfaces are handled. # TODO(dglazkov): Make sure partial interfaces are handled.
if interface.is_callback or interface.is_partial: if interface.is_callback or interface.is_partial:
raise ValueError("Partial or callback interfaces are not supported") raise ValueError('Partial or callback interfaces are not supported')
template_context = interface_context(interface) template_context = interface_context(interface)
......
# Copyright 2016 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.
# pylint: disable=import-error,print-statement,relative-import
"""Unit tests for code_generator_web_module.py."""
import unittest
from code_generator_web_module import InterfaceContextBuilder
class IdlTestingHelper(object):
"""A collection of stub makers and helper utils to make testing code
generation easy."""
def make_stub_object(self):
return type('', (), {})()
def add_idl_type_to_stub(self, stub, return_type):
stub.idl_type = self.make_stub_object()
stub.idl_type.preprocessed_type = self.make_stub_object()
stub.idl_type.preprocessed_type.base_type = return_type
def make_stub_idl_attribute(self, name, return_type):
idl_attribute_stub = self.make_stub_object()
idl_attribute_stub.name = name
self.add_idl_type_to_stub(idl_attribute_stub, return_type)
return idl_attribute_stub
def make_stub_idl_operation(self, name, return_type):
idl_operation_stub = self.make_stub_object()
idl_operation_stub.name = name
self.add_idl_type_to_stub(idl_operation_stub, return_type)
return idl_operation_stub
class InterfaceContextBuilderTest(unittest.TestCase):
def test_empty(self):
builder = InterfaceContextBuilder('test')
self.assertEqual({'code_generator': 'test'}, builder.build())
def test_set_name(self):
builder = InterfaceContextBuilder('test')
builder.set_class_name('foo')
self.assertEqual({
'code_generator': 'test',
'class_name': 'foo',
}, builder.build())
def test_add_attribute(self):
helper = IdlTestingHelper()
builder = InterfaceContextBuilder('test')
attribute = helper.make_stub_idl_attribute('foo', 'bar')
builder.add_attribute(attribute)
self.assertEqual({
'code_generator': 'test',
'cpp_includes': set(['bar']),
'attributes': [{'name': 'foo', 'return_type': 'bar'}],
}, builder.build())
def test_add_method(self):
helper = IdlTestingHelper()
builder = InterfaceContextBuilder('test')
operation = helper.make_stub_idl_operation('foo', 'bar')
builder.add_operation(operation)
self.assertEqual({
'code_generator': 'test',
'cpp_includes': set(['bar']),
'methods': [{'name': 'foo', 'return_type': 'bar'}],
}, builder.build())
...@@ -2,6 +2,24 @@ ...@@ -2,6 +2,24 @@
{% include 'copyright_block.txt' %} {% include 'copyright_block.txt' %}
// TODO(dglazkov): Implement generating the header file. // TODO(dglazkov): Use chromium-style path.
#ifndef {{class_name}}_h
#define {{class_name}}_h
{% endfilter %} {% for include_file in header_includes %}
\ No newline at end of file #include "{{include_file}}"
{% endfor %}
namespace blink {
namespace api {
class {{class_name}} {
};
} // namespace api
} // namespace blink
#endif // {{class_name}}_h
{% endfilter %}
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include "WebTestInterface3.h" #include "WebTestInterface3.h"
// TODO(dglazkov): Implement generating includes. // TODO(dglazkov): Implement generating includes.
#include "Webvoid.h"
#include "WebIterator.h"
#include "WebDOMString.h" #include "WebDOMString.h"
namespace blink { namespace blink {
......
...@@ -7,4 +7,17 @@ ...@@ -7,4 +7,17 @@
// clang-format off // clang-format off
// TODO(dglazkov): Implement generating the header file. // TODO(dglazkov): Use chromium-style path.
#ifndef TestInterface3_h
#define TestInterface3_h
namespace blink {
namespace api {
class TestInterface3 {
};
} // namespace api
} // namespace blink
#endif // TestInterface3_h
...@@ -26,7 +26,10 @@ ...@@ -26,7 +26,10 @@
import sys import sys
from webkitpy.bindings.bindings_tests import run_bindings_tests from webkitpy.bindings.bindings_tests import run_bindings_tests
from webkitpy.common import webkit_finder
webkit_finder.add_typ_dir_to_sys_path()
import typ
def main(argv): def main(argv):
"""Runs Blink bindings IDL compiler on test IDL files and compares the """Runs Blink bindings IDL compiler on test IDL files and compares the
...@@ -36,15 +39,38 @@ def main(argv): ...@@ -36,15 +39,38 @@ def main(argv):
(this is automatically done as a presubmit script), (this is automatically done as a presubmit script),
and submit changes to the test results in the same patch. and submit changes to the test results in the same patch.
This makes it easier to track and review changes in generated code. This makes it easier to track and review changes in generated code.
Options:
--reset-results: Overwrites reference files with the generated results.
--verbose: Show output on success and logging messages (not just failure)
""" """
reset_results = '--reset-results' in argv argument_parser = typ.ArgumentParser()
verbose = '--verbose' in argv argument_parser.add_argument('--reset-results',
default=False,
action='store_true',
help='Overwrites reference files with the generated results.')
argument_parser.add_argument('--skip-unit-tests',
default=False,
action='store_true',
help='Skip running unit tests (only run reference tests).')
argument_parser.add_argument('--skip-reference-tests',
default=False,
action='store_true',
help='Skip running reference tests (only run unit tests).')
# First, run bindings unit tests.
runner = typ.Runner()
runner.parse_args(argument_parser, argv[1:])
args = runner.args
if argument_parser.exit_status is not None:
return argument_parser.exit_status
runner.args.top_level_dir = webkit_finder.get_bindings_scripts_dir()
if not args.skip_unit_tests:
return_code, _, _ = runner.run()
if return_code != 0:
return return_code
if args.skip_reference_tests:
return 0
return run_bindings_tests(reset_results, verbose) # Now run the bindings end-to-end tests.
return run_bindings_tests(args.reset_results, args.verbose)
if __name__ == '__main__': if __name__ == '__main__':
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment