1#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6from cpp_namespace_environment import CppNamespaceEnvironment
7from cpp_type_generator import CppTypeGenerator
8from json_schema import CachedLoad
9import model
10import unittest
11
12from collections import defaultdict
13
14class _FakeSchemaLoader(object):
15  def __init__(self, model):
16    self._model = model
17
18  def ResolveType(self, type_name, default):
19    parts = type_name.rsplit('.', 1)
20    if len(parts) == 1:
21      return default if type_name in default.types else None
22    return self._model.namespaces[parts[0]]
23
24class CppTypeGeneratorTest(unittest.TestCase):
25  def setUp(self):
26    self.models = defaultdict(model.Model)
27
28    self.forbidden_json = CachedLoad('test/forbidden.json')
29    self.forbidden = self.models['forbidden'].AddNamespace(
30        self.forbidden_json[0], 'path/to/forbidden.json')
31    self.permissions_json = CachedLoad('test/permissions.json')
32    self.permissions = self.models['permissions'].AddNamespace(
33        self.permissions_json[0], 'path/to/permissions.json')
34    self.windows_json = CachedLoad('test/windows.json')
35    self.windows = self.models['windows'].AddNamespace(self.windows_json[0],
36                                                       'path/to/window.json')
37    self.tabs_json = CachedLoad('test/tabs.json')
38    self.tabs = self.models['tabs'].AddNamespace(self.tabs_json[0],
39                                                 'path/to/tabs.json')
40    self.browser_action_json = CachedLoad('test/browser_action.json')
41    self.browser_action = self.models['browser_action'].AddNamespace(
42        self.browser_action_json[0], 'path/to/browser_action.json')
43    self.font_settings_json = CachedLoad('test/font_settings.json')
44    self.font_settings = self.models['font_settings'].AddNamespace(
45        self.font_settings_json[0], 'path/to/font_settings.json')
46    self.dependency_tester_json = CachedLoad('test/dependency_tester.json')
47    self.dependency_tester = self.models['dependency_tester'].AddNamespace(
48        self.dependency_tester_json[0], 'path/to/dependency_tester.json')
49    self.content_settings_json = CachedLoad('test/content_settings.json')
50    self.content_settings = self.models['content_settings'].AddNamespace(
51        self.content_settings_json[0], 'path/to/content_settings.json')
52
53  def testGenerateIncludesAndForwardDeclarations(self):
54    m = model.Model()
55    m.AddNamespace(self.windows_json[0],
56                   'path/to/windows.json',
57                   environment=CppNamespaceEnvironment('%(namespace)s'))
58    m.AddNamespace(self.tabs_json[0],
59                   'path/to/tabs.json',
60                   environment=CppNamespaceEnvironment('%(namespace)s'))
61    manager = CppTypeGenerator(m, _FakeSchemaLoader(m))
62
63    self.assertEquals('', manager.GenerateIncludes().Render())
64    self.assertEquals('#include "path/to/tabs.h"',
65                      manager.GenerateIncludes(include_soft=True).Render())
66    self.assertEquals(
67        'namespace tabs {\n'
68        'struct Tab;\n'
69        '}  // namespace tabs',
70        manager.GenerateForwardDeclarations().Render())
71
72    m = model.Model()
73    m.AddNamespace(self.windows_json[0],
74                   'path/to/windows.json',
75                   environment=CppNamespaceEnvironment(
76                       'foo::bar::%(namespace)s'))
77    m.AddNamespace(self.tabs_json[0],
78                   'path/to/tabs.json',
79                   environment=CppNamespaceEnvironment(
80                       'foo::bar::%(namespace)s'))
81    manager = CppTypeGenerator(m, _FakeSchemaLoader(m))
82    self.assertEquals(
83        'namespace foo {\n'
84        'namespace bar {\n'
85        'namespace tabs {\n'
86        'struct Tab;\n'
87        '}  // namespace tabs\n'
88        '}  // namespace bar\n'
89        '}  // namespace foo',
90        manager.GenerateForwardDeclarations().Render())
91    manager = CppTypeGenerator(self.models.get('permissions'),
92                               _FakeSchemaLoader(m))
93    self.assertEquals('', manager.GenerateIncludes().Render())
94    self.assertEquals('', manager.GenerateIncludes().Render())
95    self.assertEquals('', manager.GenerateForwardDeclarations().Render())
96    manager = CppTypeGenerator(self.models.get('content_settings'),
97                               _FakeSchemaLoader(m))
98    self.assertEquals('', manager.GenerateIncludes().Render())
99
100  def testGenerateIncludesAndForwardDeclarationsDependencies(self):
101    m = model.Model()
102    # Insert 'font_settings' before 'browser_action' in order to test that
103    # CppTypeGenerator sorts them properly.
104    m.AddNamespace(self.font_settings_json[0], 'path/to/font_settings.json')
105    m.AddNamespace(self.browser_action_json[0], 'path/to/browser_action.json')
106    dependency_tester = m.AddNamespace(self.dependency_tester_json[0],
107                                       'path/to/dependency_tester.json')
108    manager = CppTypeGenerator(m,
109                               _FakeSchemaLoader(m),
110                               default_namespace=dependency_tester)
111    self.assertEquals('#include "path/to/browser_action.h"\n'
112                      '#include "path/to/font_settings.h"',
113                      manager.GenerateIncludes().Render())
114    self.assertEquals('', manager.GenerateForwardDeclarations().Render())
115
116  def testGetCppTypeSimple(self):
117    manager = CppTypeGenerator(self.models.get('tabs'), _FakeSchemaLoader(None))
118    self.assertEquals(
119        'int',
120        manager.GetCppType(self.tabs.types['Tab'].properties['id'].type_))
121    self.assertEquals(
122        'std::string',
123        manager.GetCppType(self.tabs.types['Tab'].properties['status'].type_))
124    self.assertEquals(
125        'bool',
126        manager.GetCppType(self.tabs.types['Tab'].properties['selected'].type_))
127
128  def testStringAsType(self):
129    manager = CppTypeGenerator(self.models.get('font_settings'),
130                               _FakeSchemaLoader(None))
131    self.assertEquals(
132        'std::string',
133        manager.GetCppType(self.font_settings.types['FakeStringType']))
134
135  def testArrayAsType(self):
136    manager = CppTypeGenerator(self.models.get('browser_action'),
137                               _FakeSchemaLoader(None))
138    self.assertEquals(
139        'std::vector<int>',
140        manager.GetCppType(self.browser_action.types['ColorArray']))
141
142  def testGetCppTypeArray(self):
143    manager = CppTypeGenerator(self.models.get('windows'),
144                                _FakeSchemaLoader(None))
145    self.assertEquals(
146        'std::vector<linked_ptr<Window> >',
147        manager.GetCppType(
148            self.windows.functions['getAll'].callback.params[0].type_))
149    manager = CppTypeGenerator(self.models.get('permissions'),
150                               _FakeSchemaLoader(None))
151    self.assertEquals(
152        'std::vector<std::string>',
153        manager.GetCppType(
154            self.permissions.types['Permissions'].properties['origins'].type_))
155
156  def testGetCppTypeLocalRef(self):
157    manager = CppTypeGenerator(self.models.get('tabs'), _FakeSchemaLoader(None))
158    self.assertEquals(
159        'Tab',
160        manager.GetCppType(self.tabs.functions['get'].callback.params[0].type_))
161
162  def testGetCppTypeIncludedRef(self):
163    m = model.Model()
164    m.AddNamespace(self.windows_json[0],
165                   'path/to/windows.json',
166                   environment=CppNamespaceEnvironment('%(namespace)s'))
167    m.AddNamespace(self.tabs_json[0],
168                   'path/to/tabs.json',
169                   environment=CppNamespaceEnvironment('%(namespace)s'))
170    manager = CppTypeGenerator(m, _FakeSchemaLoader(m))
171    self.assertEquals(
172        'std::vector<linked_ptr<tabs::Tab> >',
173        manager.GetCppType(
174            self.windows.types['Window'].properties['tabs'].type_))
175
176  def testGetCppTypeWithPadForGeneric(self):
177    manager = CppTypeGenerator(self.models.get('permissions'),
178                               _FakeSchemaLoader(None))
179    self.assertEquals('std::vector<std::string>',
180        manager.GetCppType(
181            self.permissions.types['Permissions'].properties['origins'].type_,
182            is_in_container=False))
183    self.assertEquals('linked_ptr<std::vector<std::string> >',
184        manager.GetCppType(
185            self.permissions.types['Permissions'].properties['origins'].type_,
186            is_in_container=True))
187    self.assertEquals('bool',
188        manager.GetCppType(
189            self.permissions.functions['contains'].callback.params[0].type_,
190        is_in_container=True))
191
192if __name__ == '__main__':
193  unittest.main()
194