1# Copyright (C) 2023 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15import unittest 16import xml.etree.ElementTree as ET 17import os 18import shutil 19 20from generate_adservices_public_xml import AdServicesUiUtil 21from generate_adservices_public_xml import ResourceCategory 22from generate_ota_public_xml import AdServicesOTAUtil 23 24 25class AdServiceUiTests(unittest.TestCase): 26 TEST_DIR = 'test_res/values/' 27 TEST_LAYOUT_DIR = 'test_res/layout/' 28 29 TEST_OTA_DIR = 'test_ota_res/values/' 30 TEST_OTA_LAYOUT_DIR = 'test_ota_res/layout/' 31 TEST_OTA_DRAWABLE_DIR = 'test_ota_res/drawable/' 32 TEST_OTA_COLOR_DIR = 'test_ota_res/color/' 33 34 TEST_STRINGS_FILE = 'test_res/values/strings.xml' 35 TEST_STRINGS_XML = ''' 36 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 37 <string name="permlab_accessAdServicesTopics">access AdServices Topics API</string> 38 <string name="permdesc_accessAdServicesTopics">Allows an application to access AdServices Topics API.</string> 39 </resources> 40 ''' 41 42 TEST_OTA_STRINGS_FILE = 'test_ota_res/values/strings.xml' 43 TEST_OTA_STRINGS_XML = ''' 44 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 45 <string name="permlab_accessAdServicesTopics">Access AdServices Topics API</string> 46 </resources> 47 ''' 48 49 TEST_DIMENS_FILE = 'test_res/values/dimens.xml' 50 TEST_DIMENS_XML = ''' 51 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 52 <dimen name="disabled_button_alpha" format="float">0.7</dimen> 53 <dimen name="enabled_button_alpha" format="float">0.5</dimen> 54 </resources> 55 ''' 56 57 TEST_OTA_DIMENS_FILE = 'test_ota_res/values/dimens.xml' 58 TEST_OTA_DIMENS_XML = ''' 59 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 60 <dimen name="disabled_button_alpha" format="float">0.3</dimen> 61 </resources> 62 ''' 63 64 TEST_LAYOUT_FILE = 'test_res/layout/layout.xml' 65 TEST_LAYOUT_XML = ''' 66 <LinearLayout 67 xmlns:android="http://schemas.android.com/apk/res/android" 68 android:layout_width="match_parent" 69 android:layout_height="match_parent" 70 android:orientation="vertical"> 71 <androidx.fragment.app.FragmentContainerView 72 android:id="@+id/fragment_container_view" 73 android:layout_width="match_parent" 74 android:layout_height="match_parent" /> 75 </LinearLayout> 76 ''' 77 78 TEST_OTA_LAYOUT_FILE = 'test_ota_res/layout/layout.xml' 79 TEST_OTA_LAYOUT_XML = ''' 80 <LinearLayout 81 xmlns:android="http://schemas.android.com/apk/res/android" 82 android:layout_width="match_parent" 83 android:layout_height="match_parent" 84 android:orientation="horizontal"> 85 <androidx.fragment.app.FragmentContainerView 86 android:id="@+id/fragment_container_view" 87 android:layout_width="wrap_content" 88 android:layout_height="match_parent" /> 89 </LinearLayout> 90 ''' 91 92 TEST_STRINGS_MAP_START = '0x7f017fff' 93 TEST_DIMENS_MAP_START = '0x7f027fff' 94 TEST_LAYOUT_MAP_START = '0x7f037fff' 95 TEST_ID_MAP_START = '0x7f047fff' 96 97 TEST_PUBLIC_FILE = 'test_res/values/public.xml' 98 TEST_PUBLIC_XML = ''' 99 <resources> 100 <public type="string" name="permlab_accessAdServicesTopics" id="0x7f017fff" /> 101 <public type="string" name="permdesc_accessAdServicesTopics" id="0x7f017ffe" /> 102 <public type="dimen" name="disabled_button_alpha" id="0x7f027fff" /> 103 <public type="dimen" name="enabled_button_alpha" id="0x7f027ffe" /> 104 </resources> 105 ''' 106 107 TEST_OTA_PUBLIC_FILE = 'test_ota_res/values/public.xml' 108 TEST_OTA_PUBLIC_XML = ''' 109 <resources> 110 <public type="string" name="permlab_accessAdServicesTopics" id="0x7f017fff" /> 111 <public type="dimen" name="disabled_button_alpha" id="0x7f027fff" /> 112 </resources> 113 ''' 114 115 util = AdServicesUiUtil() 116 ota_util = AdServicesOTAUtil() 117 118 def _write(self, xml, filepath): 119 f = open(filepath, "w") 120 f.write(xml) 121 f.close() 122 123 def _generate_test_files(self): 124 os.makedirs(self.TEST_DIR, exist_ok=True) 125 os.makedirs(self.TEST_LAYOUT_DIR, exist_ok=True) 126 127 self._write(self.TEST_STRINGS_XML, self.TEST_STRINGS_FILE) 128 self._write(self.TEST_DIMENS_XML, self.TEST_DIMENS_FILE) 129 self._write(self.TEST_PUBLIC_XML, self.TEST_PUBLIC_FILE) 130 131 def _generate_ota_test_files(self): 132 os.makedirs(self.TEST_OTA_DIR, exist_ok=True) 133 os.makedirs(self.TEST_OTA_LAYOUT_DIR, exist_ok=True) 134 135 self._write(self.TEST_OTA_STRINGS_XML, self.TEST_OTA_STRINGS_FILE) 136 self._write(self.TEST_OTA_DIMENS_XML, self.TEST_OTA_DIMENS_FILE) 137 self._write(self.TEST_OTA_PUBLIC_XML, self.TEST_OTA_PUBLIC_FILE) 138 139 def _delete_dir(self, dir): 140 if os.path.exists(dir): 141 shutil.rmtree(dir) 142 143 def _delete_all_test_files(self): 144 self._delete_dir('test_res') 145 self._delete_dir('test_ota_res') 146 self._delete_dir('__pycache__') 147 148 def _update_res_xml(self, res_dir, res_type, n): 149 root = ET.parse(res_dir).getroot() 150 for res_name in [f"test{res_type}{i}" for i in range(n)]: 151 added_element = ET.SubElement(root, res_type) 152 added_element.set('name', res_name) 153 154 ET.indent(root, space=' ') 155 with open(res_dir, "w+") as file: 156 file.write(ET.tostring(root, encoding="unicode")) 157 158 def _test_util_update_public_xml(self, new_res_count, public_xml, public_xml_dir): 159 old_root = ET.ElementTree(ET.fromstring(public_xml)).getroot() 160 old_mapping = {node.attrib['name']: node.attrib['id'] for node in old_root} 161 162 root = ET.parse(public_xml_dir).getroot() 163 mapping = {node.attrib['name']: node.attrib['id'] for node in root} 164 165 assert (len(old_mapping) + new_res_count == len(mapping)) 166 assert (len(mapping) == len(set(mapping.values()))) 167 for name, _id in mapping.items(): 168 if name in old_mapping: 169 assert (_id == old_mapping[name]) 170 171 def _test_util_compare_public_xmls(self, adservices_public_xml_dir, ota_public_xml_dir): 172 adservices_root = ET.parse(adservices_public_xml_dir).getroot() 173 adservices_mapping = {node.attrib['name']: node.attrib['id'] for node in adservices_root} 174 175 ota_root = ET.parse(ota_public_xml_dir).getroot() 176 ota_mapping = {node.attrib['name']: node.attrib['id'] for node in ota_root} 177 178 assert (len(adservices_mapping) >= len(ota_mapping)) 179 assert (len(adservices_mapping) == len(set(adservices_mapping.values()))) 180 assert (len(ota_mapping) == len(set(ota_mapping.values()))) 181 for name, _id in ota_mapping.items(): 182 assert (_id == adservices_mapping[name]) 183 184 def test_adding_adservices_strings(self): 185 self._generate_test_files() 186 187 new_strings_count = 5 188 self._update_res_xml(self.TEST_STRINGS_FILE, 'string', new_strings_count) 189 self.util.update_public_xml(self.TEST_STRINGS_FILE, 'string', ResourceCategory.Value, 190 self.TEST_DIMENS_MAP_START, self.TEST_PUBLIC_FILE) 191 192 self._test_util_update_public_xml(new_strings_count, self.TEST_PUBLIC_XML, 193 self.TEST_PUBLIC_FILE) 194 195 self._delete_all_test_files() 196 197 def test_adding_adservices_dimens(self): 198 self._generate_test_files() 199 200 new_dimens_count = 2 201 self._update_res_xml(self.TEST_DIMENS_FILE, 'dimen', new_dimens_count) 202 self.util.update_public_xml(self.TEST_DIMENS_FILE, 'dimen', ResourceCategory.Value, 203 self.TEST_DIMENS_MAP_START, self.TEST_PUBLIC_FILE) 204 205 self._test_util_update_public_xml(new_dimens_count, self.TEST_PUBLIC_XML, 206 self.TEST_PUBLIC_FILE) 207 208 self._delete_all_test_files() 209 210 def test_adding_adservices_layouts(self): 211 self._generate_test_files() 212 213 new_layout_count = 1 214 self._write(self.TEST_LAYOUT_XML, self.TEST_LAYOUT_FILE) 215 self.util.update_public_xml(self.TEST_LAYOUT_DIR, 'layout', ResourceCategory.File, 216 self.TEST_LAYOUT_MAP_START, self.TEST_PUBLIC_FILE) 217 218 self._test_util_update_public_xml(new_layout_count, self.TEST_PUBLIC_XML, 219 self.TEST_PUBLIC_FILE) 220 221 self._delete_all_test_files() 222 223 def test_adding_adservices_multiple_res(self): 224 self._generate_test_files() 225 226 new_strings_count = 3 227 self._update_res_xml(self.TEST_STRINGS_FILE, 'string', new_strings_count) 228 self.util.update_public_xml(self.TEST_STRINGS_FILE, 'string', ResourceCategory.Value, 229 self.TEST_DIMENS_MAP_START, self.TEST_PUBLIC_FILE) 230 231 self._test_util_update_public_xml(new_strings_count, self.TEST_PUBLIC_XML, 232 self.TEST_PUBLIC_FILE) 233 234 new_dimens_count = 2 235 self._update_res_xml(self.TEST_DIMENS_FILE, 'dimen', new_dimens_count) 236 self.util.update_public_xml(self.TEST_DIMENS_FILE, 'dimen', ResourceCategory.Value, 237 self.TEST_DIMENS_MAP_START, self.TEST_PUBLIC_FILE) 238 239 self._test_util_update_public_xml(new_strings_count + new_dimens_count, 240 self.TEST_PUBLIC_XML, 241 self.TEST_PUBLIC_FILE) 242 243 new_layout_count = 1 244 self._write(self.TEST_LAYOUT_XML, self.TEST_LAYOUT_FILE) 245 self.util.update_public_xml(self.TEST_LAYOUT_DIR, 'layout', ResourceCategory.File, 246 self.TEST_LAYOUT_MAP_START, self.TEST_PUBLIC_FILE) 247 248 self._test_util_update_public_xml(new_strings_count + new_dimens_count + new_layout_count, 249 self.TEST_PUBLIC_XML, 250 self.TEST_PUBLIC_FILE) 251 252 self._delete_all_test_files() 253 254 def test_adding_ota_strings(self): 255 self._generate_test_files() 256 self._generate_ota_test_files() 257 258 new_strings_count = 5 259 self._update_res_xml(self.TEST_STRINGS_FILE, 'string', new_strings_count) 260 new_ota_strings_count = 3 261 self._update_res_xml(self.TEST_OTA_STRINGS_FILE, 'string', new_ota_strings_count) 262 263 self.util.update_public_xml(self.TEST_STRINGS_FILE, 'string', ResourceCategory.Value, 264 self.TEST_DIMENS_MAP_START, self.TEST_PUBLIC_FILE) 265 self.ota_util.update_ota_public_xml(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE, 266 self.TEST_OTA_DIR, self.TEST_OTA_LAYOUT_DIR, 267 self.TEST_OTA_DRAWABLE_DIR, self.TEST_OTA_COLOR_DIR) 268 269 self._test_util_compare_public_xmls(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE) 270 271 self._delete_all_test_files() 272 273 def test_adding_ota_dimens(self): 274 self._generate_test_files() 275 self._generate_ota_test_files() 276 277 new_dimens_count = 2 278 self._update_res_xml(self.TEST_DIMENS_FILE, 'dimen', new_dimens_count) 279 new_ota_dimens_count = 1 280 self._update_res_xml(self.TEST_OTA_DIMENS_FILE, 'dimen', new_ota_dimens_count) 281 282 self.util.update_public_xml(self.TEST_DIMENS_FILE, 'dimen', ResourceCategory.Value, 283 self.TEST_DIMENS_MAP_START, self.TEST_PUBLIC_FILE) 284 self.ota_util.update_ota_public_xml(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE, 285 self.TEST_OTA_DIR, self.TEST_OTA_LAYOUT_DIR, 286 self.TEST_OTA_DRAWABLE_DIR, self.TEST_OTA_COLOR_DIR) 287 288 self._test_util_compare_public_xmls(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE) 289 290 self._delete_all_test_files() 291 292 def test_adding_ota_layout(self): 293 self._generate_test_files() 294 self._generate_ota_test_files() 295 296 self._write(self.TEST_LAYOUT_XML, self.TEST_LAYOUT_FILE) 297 self._write(self.TEST_OTA_LAYOUT_XML, self.TEST_OTA_LAYOUT_FILE) 298 299 self.util.update_public_xml(self.TEST_LAYOUT_DIR, 'layout', ResourceCategory.File, 300 self.TEST_LAYOUT_MAP_START, self.TEST_PUBLIC_FILE) 301 self.util.update_public_xml(self.TEST_LAYOUT_DIR, 'id', ResourceCategory.Id, 302 self.TEST_ID_MAP_START, self.TEST_PUBLIC_FILE) 303 304 self.ota_util.update_ota_public_xml(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE, 305 self.TEST_OTA_DIR, self.TEST_OTA_LAYOUT_DIR, 306 self.TEST_OTA_DRAWABLE_DIR, self.TEST_OTA_COLOR_DIR) 307 308 self._test_util_compare_public_xmls(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE) 309 310 self._delete_all_test_files() 311 312 def test_adding_ota_multiple_res(self): 313 self._generate_test_files() 314 self._generate_ota_test_files() 315 316 new_strings_count = 3 317 self._update_res_xml(self.TEST_STRINGS_FILE, 'string', new_strings_count) 318 new_ota_strings_count = 2 319 self._update_res_xml(self.TEST_OTA_STRINGS_FILE, 'string', new_ota_strings_count) 320 321 self.util.update_public_xml(self.TEST_STRINGS_FILE, 'string', ResourceCategory.Value, 322 self.TEST_DIMENS_MAP_START, self.TEST_PUBLIC_FILE) 323 self.ota_util.update_ota_public_xml(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE, 324 self.TEST_OTA_DIR, self.TEST_OTA_LAYOUT_DIR, 325 self.TEST_OTA_DRAWABLE_DIR, self.TEST_OTA_COLOR_DIR) 326 327 self._test_util_compare_public_xmls(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE) 328 329 new_dimens_count = 1 330 self._update_res_xml(self.TEST_DIMENS_FILE, 'dimen', new_dimens_count) 331 new_ota_dimens_count = 1 332 self._update_res_xml(self.TEST_OTA_DIMENS_FILE, 'dimen', new_ota_dimens_count) 333 334 self.util.update_public_xml(self.TEST_DIMENS_FILE, 'dimen', ResourceCategory.Value, 335 self.TEST_DIMENS_MAP_START, self.TEST_PUBLIC_FILE) 336 self.ota_util.update_ota_public_xml(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE, 337 self.TEST_OTA_DIR, self.TEST_OTA_LAYOUT_DIR, 338 self.TEST_OTA_DRAWABLE_DIR, self.TEST_OTA_COLOR_DIR) 339 340 self._test_util_compare_public_xmls(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE) 341 342 self._write(self.TEST_LAYOUT_XML, self.TEST_LAYOUT_FILE) 343 self._write(self.TEST_OTA_LAYOUT_XML, self.TEST_OTA_LAYOUT_FILE) 344 345 self.util.update_public_xml(self.TEST_LAYOUT_DIR, 'layout', ResourceCategory.File, 346 self.TEST_LAYOUT_MAP_START, self.TEST_PUBLIC_FILE) 347 self.util.update_public_xml(self.TEST_LAYOUT_DIR, 'id', ResourceCategory.Id, 348 self.TEST_ID_MAP_START, self.TEST_PUBLIC_FILE) 349 350 self.ota_util.update_ota_public_xml(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE, 351 self.TEST_OTA_DIR, self.TEST_OTA_LAYOUT_DIR, 352 self.TEST_OTA_DRAWABLE_DIR, self.TEST_OTA_COLOR_DIR) 353 354 self._test_util_compare_public_xmls(self.TEST_PUBLIC_FILE, self.TEST_OTA_PUBLIC_FILE) 355 356 self._delete_all_test_files() 357 358 359if __name__ == '__main__': 360 unittest.main() 361