#!/usr/bin/env python3 # # Copyright 2019, The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Unittests for AidegenConfig class.""" import os import shutil import tempfile import unittest from unittest import mock from aidegen import constant from aidegen.lib import common_util from aidegen.lib import config # pylint: disable=protected-access class AidegenConfigUnittests(unittest.TestCase): """Unit tests for config.py""" _TMP_DIR = None def setUp(self): """Prepare the testdata related path.""" AidegenConfigUnittests._TMP_DIR = tempfile.mkdtemp() config.AidegenConfig._CONFIG_DIR = os.path.join( AidegenConfigUnittests._TMP_DIR, '.config', 'asuite', 'aidegen') config.AidegenConfig._CONFIG_FILE_PATH = os.path.join( config.AidegenConfig._CONFIG_DIR, config.AidegenConfig._DEFAULT_CONFIG_FILE) config.AidegenConfig._ENABLE_DEBUG_DIR = os.path.join( config.AidegenConfig._CONFIG_DIR, config.AidegenConfig._ENABLE_DEBUG_CONFIG_DIR) config.AidegenConfig.DEBUG_ENABLED_FILE_PATH = os.path.join( config.AidegenConfig._CONFIG_DIR, config.AidegenConfig._ENABLE_DEBUG_CONFIG_FILE) def tearDown(self): """Clear the testdata related path.""" shutil.rmtree(AidegenConfigUnittests._TMP_DIR) @mock.patch('json.load') @mock.patch('builtins.open') @mock.patch('os.path.exists') def test_load_aidegen_config(self, mock_file_exists, mock_file_open, mock_json_load): """Test loading aidegen config.""" mock_file_exists.return_value = False cfg = config.AidegenConfig() cfg._load_aidegen_config() self.assertFalse(mock_file_open.called) self.assertFalse(mock_json_load.called) mock_file_exists.return_value = True cfg = config.AidegenConfig() cfg._load_aidegen_config() self.assertTrue(mock_file_open.called) self.assertTrue(mock_json_load.called) @mock.patch('logging.info') @mock.patch('logging.error') @mock.patch('builtins.open') @mock.patch('os.path.exists') def test_error_load_aidegen_config(self, mock_file_exists, mock_file_open, mock_error, mock_info): """Test loading aidegen config with errors.""" mock_file_exists.return_value = True cfg = config.AidegenConfig() mock_file_open.side_effect = IOError() with self.assertRaises(IOError): cfg._load_aidegen_config() self.assertTrue(mock_error.called) self.assertFalse(mock_info.called) mock_file_open.reset() mock_file_open.side_effect = ValueError() cfg._load_aidegen_config() self.assertTrue(mock_info.called) @mock.patch('json.dump') @mock.patch('builtins.open') @mock.patch.object(config.AidegenConfig, '_is_config_modified') def test_aidegen_config_no_changed(self, mock_is_config_modified, mock_file_open, mock_json_dump): """Skip saving aidegen config when no configuration data is modified.""" mock_is_config_modified.return_value = False cfg = config.AidegenConfig() cfg._save_aidegen_config() self.assertFalse(mock_file_open.called) self.assertFalse(mock_json_dump.called) @mock.patch('json.dump') @mock.patch('builtins.open') @mock.patch.object(config.AidegenConfig, '_is_config_modified') def test_update_aidegen_config(self, mock_is_config_modified, mock_file_open, mock_json_dump): """Save the aidegen config once any configuration data is modified.""" mock_is_config_modified.return_value = True cfg = config.AidegenConfig() cfg._save_aidegen_config() self.assertTrue(mock_file_open.called) self.assertTrue(mock_json_dump.called) @mock.patch('logging.warning') @mock.patch.object(config.AidegenConfig, '_gen_enable_debugger_config') @mock.patch.object(config.AidegenConfig, '_gen_androidmanifest') @mock.patch.object(config.AidegenConfig, '_gen_enable_debug_sub_dir') def test_create_enable_debugger(self, mock_debug, mock_androidmanifest, mock_enable, mock_warning): """Test create_enable_debugger_module.""" cfg = config.AidegenConfig() self.assertTrue(cfg.create_enable_debugger_module('')) mock_debug.side_effect = IOError() self.assertFalse(cfg.create_enable_debugger_module('')) self.assertTrue(mock_warning.called) mock_debug.side_effect = OSError() self.assertFalse(cfg.create_enable_debugger_module('')) self.assertTrue(mock_warning.called) mock_androidmanifest.side_effect = IOError() self.assertFalse(cfg.create_enable_debugger_module('')) self.assertTrue(mock_warning.called) mock_androidmanifest.side_effect = OSError() self.assertFalse(cfg.create_enable_debugger_module('')) self.assertTrue(mock_warning.called) mock_enable.side_effect = IOError() self.assertFalse(cfg.create_enable_debugger_module('')) self.assertTrue(mock_warning.called) mock_enable.side_effect = OSError() self.assertFalse(cfg.create_enable_debugger_module('')) self.assertTrue(mock_warning.called) @mock.patch.object(common_util, 'file_generate') @mock.patch('os.path.exists') def test_gen_debugger_config(self, mock_file_exists, mock_file_generate): """Test generating the enable debugger config.""" cfg = config.AidegenConfig() android_sdk_version = '' mock_file_exists.return_value = False cfg._gen_enable_debugger_config(android_sdk_version) self.assertTrue(mock_file_generate.called) @mock.patch('os.stat') @mock.patch.object(common_util, 'file_generate') @mock.patch('os.path.exists') def test_androidmanifest_no_changed(self, mock_file_exists, mock_file_generate, mock_file_stat): """No generate the AndroidManifest.xml when it exists and size > 0.""" cfg = config.AidegenConfig() mock_file_exists.return_value = True mock_file_stat.return_value.st_size = 1 cfg._gen_androidmanifest() self.assertFalse(mock_file_generate.called) @mock.patch('os.stat') @mock.patch.object(common_util, 'file_generate') @mock.patch('os.path.exists') def test_override_androidmanifest(self, mock_file_exists, mock_file_generate, mock_file_stat): """Override the AndroidManifest.xml when the file size is zero.""" cfg = config.AidegenConfig() mock_file_exists.return_value = True mock_file_stat.return_value.st_size = 0 cfg._gen_androidmanifest() self.assertTrue(mock_file_generate.called) @mock.patch.object(common_util, 'file_generate') @mock.patch('os.path.exists') def test_gen_androidmanifest(self, mock_file_exists, mock_file_generate): """Generate the AndroidManifest.xml when it doesn't exist.""" cfg = config.AidegenConfig() mock_file_exists.return_value = False cfg._gen_androidmanifest() self.assertTrue(mock_file_generate.called) @mock.patch('os.makedirs') @mock.patch('os.path.exists') def test_config_folder_exists(self, mock_folder_exists, mock_makedirs): """Skipping create the config folder once it exists.""" mock_folder_exists.return_value = True config.AidegenConfig() self.assertFalse(mock_makedirs.called) @mock.patch('os.makedirs') @mock.patch('os.path.exists') def test_create_config_folder(self, mock_folder_exists, mock_makedirs): """Create the config folder when it doesn't exist.""" mock_folder_exists.return_value = False config.AidegenConfig() self.assertTrue(mock_makedirs.called) @mock.patch('os.path.isfile') @mock.patch('builtins.open', create=True) def test_deprecated_intellij_version(self, mock_open, mock_isfile): """Test deprecated_intellij_version.""" # Test the idea.sh file contains the deprecated string. cfg = config.AidegenConfig() expected_data = ('#!/bin/sh\n\n' 'SUMMARY="This version of IntelliJ Community Edition ' 'is no longer supported."\n') mock_open.side_effect = [ mock.mock_open(read_data=expected_data).return_value ] mock_isfile.return_value = True self.assertTrue(cfg.deprecated_intellij_version(0)) # Test the idea.sh file doesn't contain the deprecated string. expected_data = ('#!/bin/sh\n\n' 'JAVA_BIN="$JDK/bin/java"\n' '"$JAVA_BIN" \\n') mock_open.side_effect = [ mock.mock_open(read_data=expected_data).return_value ] self.assertFalse(cfg.deprecated_intellij_version(0)) @mock.patch.object(config.AidegenConfig, 'deprecated_studio_version') @mock.patch.object(config.AidegenConfig, 'deprecated_intellij_version') def test_deprecated_version(self, mock_inj, mock_studio): """Test deprecated_version.""" cfg = config.AidegenConfig() ide_name = constant.IDE_INTELLIJ test_path = '' cfg.deprecated_version(ide_name, test_path) self.assertTrue(mock_inj.called) ide_name = constant.IDE_ANDROID_STUDIO cfg.deprecated_version(ide_name, test_path) self.assertTrue(mock_studio.called) test_ide = '' self.assertFalse(cfg.deprecated_version(test_ide, test_path)) @mock.patch.object(os.path, 'isfile') def test_deprecated_studio_version(self, mock_is_file): """Test deprecated_studio_version.""" test_sh_name = 'test.sh' # temp_dir/test temp_base = os.path.join(self._TMP_DIR, 'test') os.mkdir(temp_base) # temp_dir/test/studio/bin os.mkdir(os.path.join(temp_base, 'studio')) test_bin_path = os.path.join(self._TMP_DIR, 'test', 'studio', 'bin') os.mkdir(test_bin_path) # /temp_dir/test/studio/bin/test.sh test_sh_path = os.path.join(self._TMP_DIR, 'test', 'studio', 'bin', test_sh_name) # Real test.sh doesn't exist. cfg = config.AidegenConfig() self.assertTrue(cfg.deprecated_studio_version(test_sh_path)) # The /temp_dir/test/studio/lib doesn't exist case. mock_is_file.return_value = True self.assertTrue(cfg.deprecated_studio_version(test_sh_path)) # The /temp_dir/test/studio/lib exists. test_lib_path = os.path.join(self._TMP_DIR, 'test', 'studio', 'lib') os.mkdir(test_lib_path) self.assertFalse(cfg.deprecated_studio_version(test_sh_path)) shutil.rmtree(temp_base) @mock.patch('os.path.isfile') def test_idea_path_not_file(self, mock_isfile): """Test deprecated_intellij_version.""" # Test the idea_path is not a file. cfg = config.AidegenConfig() mock_isfile.return_value = False self.assertFalse(cfg.deprecated_intellij_version(0)) @mock.patch.object(config.AidegenConfig, 'deprecated_version') @mock.patch.object(config.AidegenConfig, 'deprecated_intellij_version') def test_preferred_version(self, mock_deprecated_intj, mock_deprecated): """Test get preferred IntelliJ version.""" cfg = config.AidegenConfig() cfg._config['preferred_version'] = '' self.assertEqual(cfg.preferred_version(), None) result = 'test_intellij' cfg._config['IntelliJ_preferred_version'] = result mock_deprecated.return_value = False self.assertEqual(cfg.preferred_version(constant.IDE_INTELLIJ), result) self.assertEqual(cfg.preferred_version(result), None) mock_deprecated.return_value = True self.assertEqual(cfg.preferred_version(constant.IDE_INTELLIJ), None) mock_deprecated_intj.return_value = False cfg._config['preferred_version'] = 'a' self.assertEqual(cfg.preferred_version(), 'a') mock_deprecated_intj.return_value = True self.assertEqual(cfg.preferred_version(), None) def test_set_preferred_version(self): """Test set_preferred_version.""" cfg = config.AidegenConfig() cfg._config[config.AidegenConfig._KEY_APPEND] = 'Yes' cfg.set_preferred_version('test', None) self.assertEqual(cfg._config[config.AidegenConfig._KEY_APPEND], 'test') cfg.set_preferred_version('test', constant.IDE_INTELLIJ) self.assertEqual(cfg._config['IntelliJ_preferred_version'], 'test') def test_set_plugin_preference(self): """Test set_plugin_preference.""" cfg = config.AidegenConfig() cfg._config[config.AidegenConfig._KEY_PLUGIN_PREFERENCE] = 'yes' cfg.plugin_preference = 'no' self.assertEqual(cfg._config[ config.AidegenConfig._KEY_PLUGIN_PREFERENCE], 'no') def test_get_plugin_preference(self): """Test get_plugin_preference.""" cfg = config.AidegenConfig() cfg._config[config.AidegenConfig._KEY_PLUGIN_PREFERENCE] = 'yes' self.assertEqual(cfg.plugin_preference, 'yes') @mock.patch('os.makedirs') @mock.patch('os.path.exists') def test_gen_enable_debug_sub_dir(self, mock_file_exists, mock_makedirs): """Test _gen_enable_debug_sub_dir.""" cfg = config.AidegenConfig() mock_file_exists.return_value = True cfg._gen_enable_debug_sub_dir('a') self.assertFalse(mock_makedirs.called) mock_file_exists.return_value = False cfg._gen_enable_debug_sub_dir('a') self.assertTrue(mock_makedirs.called) class IdeaPropertiesUnittests(unittest.TestCase): """Unit tests for IdeaProperties class.""" _CONFIG_DIR = None def setUp(self): """Prepare the testdata related path.""" IdeaPropertiesUnittests._CONFIG_DIR = tempfile.mkdtemp() def tearDown(self): """Clear the testdata related path.""" shutil.rmtree(IdeaPropertiesUnittests._CONFIG_DIR) def test_set_default_properties(self): """Test creating the idea.properties with default content.""" cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) cfg._set_default_idea_properties() expected_data = cfg._PROPERTIES_CONTENT.format( KEY_FILE_SIZE=cfg._KEY_FILESIZE, VALUE_FILE_SIZE=cfg._FILESIZE_LIMIT) generated_file = os.path.join(IdeaPropertiesUnittests._CONFIG_DIR, cfg._PROPERTIES_FILE) generated_content = common_util.read_file_content(generated_file) self.assertEqual(expected_data, generated_content) @mock.patch.object(common_util, 'read_file_content') def test_reset_max_file_size(self, mock_content): """Test reset the file size limit when it's smaller than 100000.""" mock_content.return_value = ('# custom IntelliJ IDEA properties\n' 'idea.max.intellisense.filesize=5000') expected_data = ('# custom IntelliJ IDEA properties\n' 'idea.max.intellisense.filesize=100000') cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) cfg._reset_max_file_size() generated_file = os.path.join(IdeaPropertiesUnittests._CONFIG_DIR, cfg._PROPERTIES_FILE) with open(generated_file, 'r', encoding='utf-8') as properties_file: generated_content = properties_file.read() self.assertEqual(expected_data, generated_content) @mock.patch.object(common_util, 'file_generate') @mock.patch.object(common_util, 'read_file_content') def test_no_reset_max_file_size(self, mock_content, mock_gen_file): """Test when the file size is larger than 100000.""" mock_content.return_value = ('# custom IntelliJ IDEA properties\n' 'idea.max.intellisense.filesize=110000') cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) cfg._reset_max_file_size() self.assertFalse(mock_gen_file.called) @mock.patch.object(config.IdeaProperties, '_reset_max_file_size') @mock.patch.object(config.IdeaProperties, '_set_default_idea_properties') @mock.patch('os.path.exists') def test_set_idea_properties_called(self, mock_file_exists, mock_set_default, mock_reset_file_size): """Test _set_default_idea_properties() method is called.""" mock_file_exists.return_value = False cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) cfg.set_max_file_size() self.assertTrue(mock_set_default.called) self.assertFalse(mock_reset_file_size.called) @mock.patch.object(config.IdeaProperties, '_reset_max_file_size') @mock.patch.object(config.IdeaProperties, '_set_default_idea_properties') @mock.patch('os.path.exists') def test_reset_properties_called(self, mock_file_exists, mock_set_default, mock_reset_file_size): """Test _reset_max_file_size() method is called.""" mock_file_exists.return_value = True cfg = config.IdeaProperties(IdeaPropertiesUnittests._CONFIG_DIR) cfg.set_max_file_size() self.assertFalse(mock_set_default.called) self.assertTrue(mock_reset_file_size.called) if __name__ == '__main__': unittest.main()