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 idl_schema 10import model 11import unittest 12 13from collections import defaultdict 14 15class _FakeSchemaLoader(object): 16 def __init__(self, model): 17 self._model = model 18 19 def ResolveType(self, type_name, default): 20 parts = type_name.rsplit('.', 1) 21 if len(parts) == 1: 22 return default if type_name in default.types else None 23 return self._model.namespaces[parts[0]] 24 25class CppTypeGeneratorTest(unittest.TestCase): 26 def setUp(self): 27 self.models = defaultdict(model.Model) 28 29 forbidden_json = CachedLoad('test/forbidden.json') 30 self.models['forbidden'].AddNamespace( 31 forbidden_json[0], 'path/to/forbidden.json') 32 33 permissions_json = CachedLoad('test/permissions.json') 34 self.permissions = self.models['permissions'].AddNamespace( 35 permissions_json[0], 'path/to/permissions.json') 36 37 self.windows_json = CachedLoad('test/windows.json') 38 self.windows = self.models['windows'].AddNamespace(self.windows_json[0], 39 'path/to/window.json') 40 self.tabs_json = CachedLoad('test/tabs.json') 41 self.tabs = self.models['tabs'].AddNamespace(self.tabs_json[0], 42 'path/to/tabs.json') 43 44 self.browser_action_json = CachedLoad('test/browser_action.json') 45 self.browser_action = self.models['browser_action'].AddNamespace( 46 self.browser_action_json[0], 'path/to/browser_action.json') 47 48 self.font_settings_json = CachedLoad('test/font_settings.json') 49 self.font_settings = self.models['font_settings'].AddNamespace( 50 self.font_settings_json[0], 'path/to/font_settings.json') 51 52 self.dependency_tester_json = CachedLoad('test/dependency_tester.json') 53 self.models['dependency_tester'].AddNamespace( 54 self.dependency_tester_json[0], 'path/to/dependency_tester.json') 55 56 content_settings_json = CachedLoad('test/content_settings.json') 57 self.models['content_settings'].AddNamespace( 58 content_settings_json[0], 'path/to/content_settings.json') 59 60 objects_movable_idl = idl_schema.Load('test/objects_movable.idl') 61 self.objects_movable = self.models['objects_movable'].AddNamespace( 62 objects_movable_idl[0], 'path/to/objects_movable.idl', 63 include_compiler_options=True) 64 65 self.simple_api_json = CachedLoad('test/simple_api.json') 66 self.models['simple_api'].AddNamespace( 67 self.simple_api_json[0], 'path/to/simple_api.json') 68 69 self.crossref_enums_json = CachedLoad('test/crossref_enums.json') 70 self.models['crossref_enums'].AddNamespace( 71 self.crossref_enums_json[0], 'path/to/crossref_enums.json') 72 73 self.crossref_enums_array_json = CachedLoad( 74 'test/crossref_enums_array.json') 75 self.models['crossref_enums_array'].AddNamespace( 76 self.crossref_enums_array_json[0], 77 'path/to/crossref_enums_array.json') 78 79 def testGenerateIncludesAndForwardDeclarations(self): 80 m = model.Model() 81 m.AddNamespace(self.windows_json[0], 82 'path/to/windows.json', 83 environment=CppNamespaceEnvironment('%(namespace)s')) 84 m.AddNamespace(self.tabs_json[0], 85 'path/to/tabs.json', 86 environment=CppNamespaceEnvironment('%(namespace)s')) 87 manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) 88 89 self.assertEquals('', manager.GenerateIncludes().Render()) 90 self.assertEquals('#include "path/to/tabs.h"', 91 manager.GenerateIncludes(include_soft=True).Render()) 92 self.assertEquals( 93 'namespace tabs {\n' 94 'struct Tab;\n' 95 '} // namespace tabs', 96 manager.GenerateForwardDeclarations().Render()) 97 98 m = model.Model() 99 m.AddNamespace(self.windows_json[0], 100 'path/to/windows.json', 101 environment=CppNamespaceEnvironment( 102 'foo::bar::%(namespace)s')) 103 m.AddNamespace(self.tabs_json[0], 104 'path/to/tabs.json', 105 environment=CppNamespaceEnvironment( 106 'foo::bar::%(namespace)s')) 107 manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) 108 self.assertEquals( 109 'namespace foo {\n' 110 'namespace bar {\n' 111 'namespace tabs {\n' 112 'struct Tab;\n' 113 '} // namespace tabs\n' 114 '} // namespace bar\n' 115 '} // namespace foo', 116 manager.GenerateForwardDeclarations().Render()) 117 manager = CppTypeGenerator(self.models.get('permissions'), 118 _FakeSchemaLoader(m)) 119 self.assertEquals('', manager.GenerateIncludes().Render()) 120 self.assertEquals('', manager.GenerateIncludes().Render()) 121 self.assertEquals('', manager.GenerateForwardDeclarations().Render()) 122 manager = CppTypeGenerator(self.models.get('content_settings'), 123 _FakeSchemaLoader(m)) 124 self.assertEquals('', manager.GenerateIncludes().Render()) 125 126 def testGenerateIncludesAndForwardDeclarationsDependencies(self): 127 m = model.Model() 128 # Insert 'font_settings' before 'browser_action' in order to test that 129 # CppTypeGenerator sorts them properly. 130 m.AddNamespace(self.font_settings_json[0], 'path/to/font_settings.json') 131 m.AddNamespace(self.browser_action_json[0], 'path/to/browser_action.json') 132 dependency_tester = m.AddNamespace(self.dependency_tester_json[0], 133 'path/to/dependency_tester.json') 134 manager = CppTypeGenerator(m, 135 _FakeSchemaLoader(m), 136 default_namespace=dependency_tester) 137 self.assertEquals('#include "path/to/browser_action.h"\n' 138 '#include "path/to/font_settings.h"', 139 manager.GenerateIncludes().Render()) 140 self.assertEquals('', manager.GenerateForwardDeclarations().Render()) 141 142 def testGetCppTypeSimple(self): 143 manager = CppTypeGenerator(self.models.get('tabs'), _FakeSchemaLoader(None)) 144 self.assertEquals( 145 'int', 146 manager.GetCppType(self.tabs.types['Tab'].properties['id'].type_)) 147 self.assertEquals( 148 'std::string', 149 manager.GetCppType(self.tabs.types['Tab'].properties['status'].type_)) 150 self.assertEquals( 151 'bool', 152 manager.GetCppType(self.tabs.types['Tab'].properties['selected'].type_)) 153 154 def testStringAsType(self): 155 manager = CppTypeGenerator(self.models.get('font_settings'), 156 _FakeSchemaLoader(None)) 157 self.assertEquals( 158 'std::string', 159 manager.GetCppType(self.font_settings.types['FakeStringType'])) 160 161 def testArrayAsType(self): 162 manager = CppTypeGenerator(self.models.get('browser_action'), 163 _FakeSchemaLoader(None)) 164 self.assertEquals( 165 'std::vector<int>', 166 manager.GetCppType(self.browser_action.types['ColorArray'])) 167 168 def testGetCppTypeArray(self): 169 manager = CppTypeGenerator(self.models.get('windows'), 170 _FakeSchemaLoader(None)) 171 self.assertEquals( 172 'std::vector<Window>', 173 manager.GetCppType( 174 self.windows.functions['getAll'].returns_async.params[0].type_)) 175 manager = CppTypeGenerator(self.models.get('permissions'), 176 _FakeSchemaLoader(None)) 177 self.assertEquals( 178 'std::vector<std::string>', 179 manager.GetCppType( 180 self.permissions.types['Permissions'].properties['origins'].type_)) 181 182 manager = CppTypeGenerator(self.models.get('objects_movable'), 183 _FakeSchemaLoader(None)) 184 self.assertEquals( 185 'std::vector<MovablePod>', 186 manager.GetCppType( 187 self.objects_movable.types['MovableParent']. 188 properties['pods'].type_)) 189 190 def testGetCppTypeLocalRef(self): 191 manager = CppTypeGenerator(self.models.get('tabs'), _FakeSchemaLoader(None)) 192 self.assertEquals( 193 'Tab', 194 manager.GetCppType( 195 self.tabs.functions['get'].returns_async.params[0].type_)) 196 197 def testGetCppTypeIncludedRef(self): 198 m = model.Model() 199 m.AddNamespace(self.windows_json[0], 200 'path/to/windows.json', 201 environment=CppNamespaceEnvironment('%(namespace)s')) 202 m.AddNamespace(self.tabs_json[0], 203 'path/to/tabs.json', 204 environment=CppNamespaceEnvironment('%(namespace)s')) 205 manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) 206 self.assertEquals( 207 'std::vector<tabs::Tab>', 208 manager.GetCppType( 209 self.windows.types['Window'].properties['tabs'].type_)) 210 211 def testGetCppTypeWithPadForGeneric(self): 212 manager = CppTypeGenerator(self.models.get('permissions'), 213 _FakeSchemaLoader(None)) 214 self.assertEquals('std::vector<std::string>', 215 manager.GetCppType( 216 self.permissions.types['Permissions'].properties['origins'].type_, 217 is_in_container=False)) 218 self.assertEquals('std::vector<std::string>', 219 manager.GetCppType( 220 self.permissions.types['Permissions'].properties['origins'].type_, 221 is_in_container=True)) 222 self.assertEquals( 223 'bool', 224 manager.GetCppType(self.permissions.functions['contains'].returns_async. 225 params[0].type_, is_in_container=True)) 226 227 def testHardIncludesForEnums(self): 228 """Tests that enums generate hard includes. Note that it's important to use 229 use a separate file (cross_enums) here to isolate the test case so that 230 other types don't cause the hard-dependency. 231 """ 232 m = model.Model() 233 m.AddNamespace(self.crossref_enums_json[0], 234 'path/to/crossref_enums.json', 235 environment=CppNamespaceEnvironment('%(namespace)s')) 236 m.AddNamespace(self.simple_api_json[0], 237 'path/to/simple_api.json', 238 environment=CppNamespaceEnvironment('%(namespace)s')) 239 manager = CppTypeGenerator(self.models.get('crossref_enums'), 240 _FakeSchemaLoader(m)) 241 242 self.assertEquals('#include "path/to/simple_api.h"', 243 manager.GenerateIncludes().Render()) 244 245 def testHardIncludesForEnumArrays(self): 246 """Tests that enums in arrays generate hard includes. Note that it's 247 important to use a separate file (cross_enums_array) here to isolate the 248 test case so that other types don't cause the hard-dependency. 249 """ 250 m = model.Model() 251 m.AddNamespace(self.crossref_enums_array_json[0], 252 'path/to/crossref_enums_array.json', 253 environment=CppNamespaceEnvironment('%(namespace)s')) 254 m.AddNamespace(self.simple_api_json[0], 255 'path/to/simple_api.json', 256 environment=CppNamespaceEnvironment('%(namespace)s')) 257 manager = CppTypeGenerator(self.models.get('crossref_enums_array'), 258 _FakeSchemaLoader(m)) 259 260 self.assertEquals('#include "path/to/simple_api.h"', 261 manager.GenerateIncludes().Render()) 262 263if __name__ == '__main__': 264 unittest.main() 265