1#!/usr/bin/env python3 2# 3# Copyright 2019, The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Unittests for AidegenConfig class.""" 18 19import os 20import shutil 21import tempfile 22import unittest 23from unittest import mock 24 25from aidegen import constant 26 27from aidegen.lib import common_util 28from aidegen.lib import config 29 30 31# pylint: disable=protected-access 32class AidegenConfigUnittests(unittest.TestCase): 33 """Unit tests for config.py""" 34 35 _TMP_DIR = None 36 37 def setUp(self): 38 """Prepare the testdata related path.""" 39 AidegenConfigUnittests._TMP_DIR = tempfile.mkdtemp() 40 config.AidegenConfig._CONFIG_DIR = os.path.join( 41 AidegenConfigUnittests._TMP_DIR, '.config', 'asuite', 'aidegen') 42 config.AidegenConfig._CONFIG_FILE_PATH = os.path.join( 43 config.AidegenConfig._CONFIG_DIR, 44 config.AidegenConfig._DEFAULT_CONFIG_FILE) 45 config.AidegenConfig._ENABLE_DEBUG_DIR = os.path.join( 46 config.AidegenConfig._CONFIG_DIR, 47 config.AidegenConfig._ENABLE_DEBUG_CONFIG_DIR) 48 config.AidegenConfig.DEBUG_ENABLED_FILE_PATH = os.path.join( 49 config.AidegenConfig._CONFIG_DIR, 50 config.AidegenConfig._ENABLE_DEBUG_CONFIG_FILE) 51 52 def tearDown(self): 53 """Clear the testdata related path.""" 54 shutil.rmtree(AidegenConfigUnittests._TMP_DIR) 55 56 @mock.patch('json.load') 57 @mock.patch('builtins.open') 58 @mock.patch('os.path.exists') 59 def test_load_aidegen_config(self, mock_file_exists, mock_file_open, 60 mock_json_load): 61 """Test loading aidegen config.""" 62 mock_file_exists.return_value = False 63 cfg = config.AidegenConfig() 64 cfg._load_aidegen_config() 65 self.assertFalse(mock_file_open.called) 66 self.assertFalse(mock_json_load.called) 67 mock_file_exists.return_value = True 68 cfg = config.AidegenConfig() 69 cfg._load_aidegen_config() 70 self.assertTrue(mock_file_open.called) 71 self.assertTrue(mock_json_load.called) 72 73 @mock.patch('logging.info') 74 @mock.patch('logging.error') 75 @mock.patch('builtins.open') 76 @mock.patch('os.path.exists') 77 def test_error_load_aidegen_config(self, mock_file_exists, mock_file_open, 78 mock_error, mock_info): 79 """Test loading aidegen config with errors.""" 80 mock_file_exists.return_value = True 81 cfg = config.AidegenConfig() 82 mock_file_open.side_effect = IOError() 83 with self.assertRaises(IOError): 84 cfg._load_aidegen_config() 85 self.assertTrue(mock_error.called) 86 self.assertFalse(mock_info.called) 87 mock_file_open.reset() 88 mock_file_open.side_effect = ValueError() 89 cfg._load_aidegen_config() 90 self.assertTrue(mock_info.called) 91 92 @mock.patch('json.dump') 93 @mock.patch('builtins.open') 94 @mock.patch.object(config.AidegenConfig, '_is_config_modified') 95 def test_aidegen_config_no_changed(self, mock_is_config_modified, 96 mock_file_open, mock_json_dump): 97 """Skip saving aidegen config when no configuration data is modified.""" 98 mock_is_config_modified.return_value = False 99 cfg = config.AidegenConfig() 100 cfg._save_aidegen_config() 101 self.assertFalse(mock_file_open.called) 102 self.assertFalse(mock_json_dump.called) 103 104 @mock.patch('json.dump') 105 @mock.patch('builtins.open') 106 @mock.patch.object(config.AidegenConfig, '_is_config_modified') 107 def test_update_aidegen_config(self, mock_is_config_modified, 108 mock_file_open, mock_json_dump): 109 """Save the aidegen config once any configuration data is modified.""" 110 mock_is_config_modified.return_value = True 111 cfg = config.AidegenConfig() 112 cfg._save_aidegen_config() 113 self.assertTrue(mock_file_open.called) 114 self.assertTrue(mock_json_dump.called) 115 116 @mock.patch('logging.warning') 117 @mock.patch.object(config.AidegenConfig, '_gen_enable_debugger_config') 118 @mock.patch.object(config.AidegenConfig, '_gen_androidmanifest') 119 @mock.patch.object(config.AidegenConfig, '_gen_enable_debug_sub_dir') 120 def test_create_enable_debugger(self, mock_debug, mock_androidmanifest, 121 mock_enable, mock_warning): 122 """Test create_enable_debugger_module.""" 123 cfg = config.AidegenConfig() 124 self.assertTrue(cfg.create_enable_debugger_module('')) 125 mock_debug.side_effect = IOError() 126 self.assertFalse(cfg.create_enable_debugger_module('')) 127 self.assertTrue(mock_warning.called) 128 mock_debug.side_effect = OSError() 129 self.assertFalse(cfg.create_enable_debugger_module('')) 130 self.assertTrue(mock_warning.called) 131 mock_androidmanifest.side_effect = IOError() 132 self.assertFalse(cfg.create_enable_debugger_module('')) 133 self.assertTrue(mock_warning.called) 134 mock_androidmanifest.side_effect = OSError() 135 self.assertFalse(cfg.create_enable_debugger_module('')) 136 self.assertTrue(mock_warning.called) 137 mock_enable.side_effect = IOError() 138 self.assertFalse(cfg.create_enable_debugger_module('')) 139 self.assertTrue(mock_warning.called) 140 mock_enable.side_effect = OSError() 141 self.assertFalse(cfg.create_enable_debugger_module('')) 142 self.assertTrue(mock_warning.called) 143 144 @mock.patch.object(common_util, 'file_generate') 145 @mock.patch('os.path.exists') 146 def test_gen_debugger_config(self, mock_file_exists, mock_file_generate): 147 """Test generating the enable debugger config.""" 148 cfg = config.AidegenConfig() 149 android_sdk_version = '' 150 mock_file_exists.return_value = False 151 cfg._gen_enable_debugger_config(android_sdk_version) 152 self.assertTrue(mock_file_generate.called) 153 154 @mock.patch('os.stat') 155 @mock.patch.object(common_util, 'file_generate') 156 @mock.patch('os.path.exists') 157 def test_androidmanifest_no_changed(self, mock_file_exists, 158 mock_file_generate, mock_file_stat): 159 """No generate the AndroidManifest.xml when it exists and size > 0.""" 160 cfg = config.AidegenConfig() 161 mock_file_exists.return_value = True 162 mock_file_stat.return_value.st_size = 1 163 cfg._gen_androidmanifest() 164 self.assertFalse(mock_file_generate.called) 165 166 @mock.patch('os.stat') 167 @mock.patch.object(common_util, 'file_generate') 168 @mock.patch('os.path.exists') 169 def test_override_androidmanifest(self, mock_file_exists, 170 mock_file_generate, mock_file_stat): 171 """Override the AndroidManifest.xml when the file size is zero.""" 172 cfg = config.AidegenConfig() 173 mock_file_exists.return_value = True 174 mock_file_stat.return_value.st_size = 0 175 cfg._gen_androidmanifest() 176 self.assertTrue(mock_file_generate.called) 177 178 @mock.patch.object(common_util, 'file_generate') 179 @mock.patch('os.path.exists') 180 def test_gen_androidmanifest(self, mock_file_exists, mock_file_generate): 181 """Generate the AndroidManifest.xml when it doesn't exist.""" 182 cfg = config.AidegenConfig() 183 mock_file_exists.return_value = False 184 cfg._gen_androidmanifest() 185 self.assertTrue(mock_file_generate.called) 186 187 @mock.patch('os.makedirs') 188 @mock.patch('os.path.exists') 189 def test_config_folder_exists(self, mock_folder_exists, mock_makedirs): 190 """Skipping create the config folder once it exists.""" 191 mock_folder_exists.return_value = True 192 config.AidegenConfig() 193 self.assertFalse(mock_makedirs.called) 194 195 @mock.patch('os.makedirs') 196 @mock.patch('os.path.exists') 197 def test_create_config_folder(self, mock_folder_exists, mock_makedirs): 198 """Create the config folder when it doesn't exist.""" 199 mock_folder_exists.return_value = False 200 config.AidegenConfig() 201 self.assertTrue(mock_makedirs.called) 202 203 @mock.patch('os.path.isfile') 204 @mock.patch('builtins.open', create=True) 205 def test_deprecated_intellij_version(self, mock_open, mock_isfile): 206 """Test deprecated_intellij_version.""" 207 # Test the idea.sh file contains the deprecated string. 208 cfg = config.AidegenConfig() 209 expacted_data = ('#!/bin/sh\n\n' 210 'SUMMARY="This version of IntelliJ Community Edition ' 211 'is no longer supported."\n') 212 mock_open.side_effect = [ 213 mock.mock_open(read_data=expacted_data).return_value 214 ] 215 mock_isfile.return_value = True 216 self.assertTrue(cfg.deprecated_intellij_version(0)) 217 218 # Test the idea.sh file doesn't contains the deprecated string. 219 expacted_data = ('#!/bin/sh\n\n' 220 'JAVA_BIN="$JDK/bin/java"\n' 221 '"$JAVA_BIN" \\n') 222 mock_open.side_effect = [ 223 mock.mock_open(read_data=expacted_data).return_value 224 ] 225 self.assertFalse(cfg.deprecated_intellij_version(0)) 226 227 @mock.patch.object(config.AidegenConfig, 'deprecated_studio_version') 228 @mock.patch.object(config.AidegenConfig, 'deprecated_intellij_version') 229 def test_deprecated_version(self, mock_inj, mock_studio): 230 """Test deprecated_version.""" 231 cfg = config.AidegenConfig() 232 ide_name = constant.IDE_INTELLIJ 233 test_path = '' 234 cfg.deprecated_version(ide_name, test_path) 235 self.assertTrue(mock_inj.called) 236 237 ide_name = constant.IDE_ANDROID_STUDIO 238 cfg.deprecated_version(ide_name, test_path) 239 self.assertTrue(mock_studio.called) 240 test_ide = '' 241 self.assertFalse(cfg.deprecated_version(test_ide, test_path)) 242 243 @mock.patch.object(os.path, 'isfile') 244 def test_deprecated_studio_version(self, mock_is_file): 245 """Test deprecated_studio_version.""" 246 test_sh_name = 'test.sh' 247 # temp_dir/test 248 temp_base = os.path.join(self._TMP_DIR, 'test') 249 os.mkdir(temp_base) 250 # temp_dir/test/studio/bin 251 os.mkdir(os.path.join(temp_base, 'studio')) 252 test_bin_path = os.path.join(self._TMP_DIR, 'test', 'studio', 'bin') 253 os.mkdir(test_bin_path) 254 # /temp_dir/test/studio/bin/test.sh 255 test_sh_path = os.path.join(self._TMP_DIR, 'test', 'studio', 'bin', 256 test_sh_name) 257 # Real test.sh doesn't exist. 258 cfg = config.AidegenConfig() 259 self.assertTrue(cfg.deprecated_studio_version(test_sh_path)) 260 # The /temp_dir/test/studio/lib doesn't exist case. 261 mock_is_file.return_value = True 262 self.assertTrue(cfg.deprecated_studio_version(test_sh_path)) 263 # The /temp_dir/test/studio/lib exists. 264 test_lib_path = os.path.join(self._TMP_DIR, 'test', 'studio', 'lib') 265 os.mkdir(test_lib_path) 266 self.assertFalse(cfg.deprecated_studio_version(test_sh_path)) 267 shutil.rmtree(temp_base) 268 269 @mock.patch('os.path.isfile') 270 def test_idea_path_not_file(self, mock_isfile): 271 """Test deprecated_intellij_version.""" 272 # Test the idea_path is not a file. 273 cfg = config.AidegenConfig() 274 mock_isfile.return_value = False 275 self.assertFalse(cfg.deprecated_intellij_version(0)) 276 277 @mock.patch.object(config.AidegenConfig, 'deprecated_version') 278 @mock.patch.object(config.AidegenConfig, 'deprecated_intellij_version') 279 def test_preferred_version(self, mock_deprecated_intj, mock_deprecated): 280 """Test get preferred IntelliJ version.""" 281 cfg = config.AidegenConfig() 282 cfg._config['preferred_version'] = '' 283 self.assertEqual(cfg.preferred_version(), None) 284 285 result = 'test_intellij' 286 cfg._config['IntelliJ_preferred_version'] = result 287 mock_deprecated.return_value = False 288 self.assertEqual(cfg.preferred_version(constant.IDE_INTELLIJ), result) 289 self.assertEqual(cfg.preferred_version(result), None) 290 mock_deprecated.return_value = True 291 self.assertEqual(cfg.preferred_version(constant.IDE_INTELLIJ), None) 292 293 mock_deprecated_intj.return_value = False 294 cfg._config['preferred_version'] = 'a' 295 self.assertEqual(cfg.preferred_version(), 'a') 296 mock_deprecated_intj.return_value = True 297 self.assertEqual(cfg.preferred_version(), None) 298 299 def test_set_preferred_version(self): 300 """Test set_preferred_version.""" 301 cfg = config.AidegenConfig() 302 cfg._config[config.AidegenConfig._KEY_APPEND] = 'Yes' 303 cfg.set_preferred_version('test', None) 304 self.assertEqual(cfg._config[config.AidegenConfig._KEY_APPEND], 'test') 305 cfg.set_preferred_version('test', constant.IDE_INTELLIJ) 306 self.assertEqual(cfg._config['IntelliJ_preferred_version'], 'test') 307 308 def test_set_plugin_preference(self): 309 """Test set_plugin_preference.""" 310 cfg = config.AidegenConfig() 311 cfg._config[config.AidegenConfig._KEY_PLUGIN_PREFERENCE] = 'yes' 312 cfg.plugin_preference = 'no' 313 self.assertEqual(cfg._config[ 314 config.AidegenConfig._KEY_PLUGIN_PREFERENCE], 'no') 315 316 def test_get_plugin_preference(self): 317 """Test get_plugin_preference.""" 318 cfg = config.AidegenConfig() 319 cfg._config[config.AidegenConfig._KEY_PLUGIN_PREFERENCE] = 'yes' 320 self.assertEqual(cfg.plugin_preference, 'yes') 321 322 @mock.patch('os.makedirs') 323 @mock.patch('os.path.exists') 324 def test_gen_enable_debug_sub_dir(self, mock_file_exists, mock_makedirs): 325 """Test _gen_enable_debug_sub_dir.""" 326 cfg = config.AidegenConfig() 327 mock_file_exists.return_value = True 328 cfg._gen_enable_debug_sub_dir('a') 329 self.assertFalse(mock_makedirs.called) 330 mock_file_exists.return_value = False 331 cfg._gen_enable_debug_sub_dir('a') 332 self.assertTrue(mock_makedirs.called) 333 334 335class IdeaPropertiesUnittests(unittest.TestCase): 336 """Unit tests for IdeaProperties class.""" 337 338 _CONFIG_DIR = None 339 340 def setUp(self): 341 """Prepare the testdata related path.""" 342 IdeaPropertiesUnittests._CONFIG_DIR = tempfile.mkdtemp() 343 344 def tearDown(self): 345 """Clear the testdata related path.""" 346 shutil.rmtree(IdeaPropertiesUnittests._CONFIG_DIR) 347 348 def test_set_default_properties(self): 349 """Test creating the idea.properties with default content.""" 350 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 351 cfg._set_default_idea_properties() 352 expected_data = cfg._PROPERTIES_CONTENT.format( 353 KEY_FILE_SIZE=cfg._KEY_FILESIZE, 354 VALUE_FILE_SIZE=cfg._FILESIZE_LIMIT) 355 generated_file = os.path.join(IdeaPropertiesUnittests._CONFIG_DIR, 356 cfg._PROPERTIES_FILE) 357 generated_content = common_util.read_file_content(generated_file) 358 self.assertEqual(expected_data, generated_content) 359 360 @mock.patch.object(common_util, 'read_file_content') 361 def test_reset_max_file_size(self, mock_content): 362 """Test reset the file size limit when it's smaller than 100000.""" 363 mock_content.return_value = ('# custom IntelliJ IDEA properties\n' 364 'idea.max.intellisense.filesize=5000') 365 expected_data = ('# custom IntelliJ IDEA properties\n' 366 'idea.max.intellisense.filesize=100000') 367 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 368 cfg._reset_max_file_size() 369 generated_file = os.path.join(IdeaPropertiesUnittests._CONFIG_DIR, 370 cfg._PROPERTIES_FILE) 371 with open(generated_file) as properties_file: 372 generated_content = properties_file.read() 373 self.assertEqual(expected_data, generated_content) 374 375 @mock.patch.object(common_util, 'file_generate') 376 @mock.patch.object(common_util, 'read_file_content') 377 def test_no_reset_max_file_size(self, mock_content, mock_gen_file): 378 """Test when the file size is larger than 100000.""" 379 mock_content.return_value = ('# custom IntelliJ IDEA properties\n' 380 'idea.max.intellisense.filesize=110000') 381 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 382 cfg._reset_max_file_size() 383 self.assertFalse(mock_gen_file.called) 384 385 @mock.patch.object(config.IdeaProperties, '_reset_max_file_size') 386 @mock.patch.object(config.IdeaProperties, '_set_default_idea_properties') 387 @mock.patch('os.path.exists') 388 def test_set_idea_properties_called(self, mock_file_exists, 389 mock_set_default, 390 mock_reset_file_size): 391 """Test _set_default_idea_properties() method is called.""" 392 mock_file_exists.return_value = False 393 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 394 cfg.set_max_file_size() 395 self.assertTrue(mock_set_default.called) 396 self.assertFalse(mock_reset_file_size.called) 397 398 @mock.patch.object(config.IdeaProperties, '_reset_max_file_size') 399 @mock.patch.object(config.IdeaProperties, '_set_default_idea_properties') 400 @mock.patch('os.path.exists') 401 def test_reset_properties_called(self, mock_file_exists, mock_set_default, 402 mock_reset_file_size): 403 """Test _reset_max_file_size() method is called.""" 404 mock_file_exists.return_value = True 405 cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) 406 cfg.set_max_file_size() 407 self.assertFalse(mock_set_default.called) 408 self.assertTrue(mock_reset_file_size.called) 409 410 411if __name__ == '__main__': 412 unittest.main() 413