Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | # SPDX-License-Identifier: GPL-2.0+ # Copyright (c) 2022 Google LLC # """Tests for cfgutil module""" import os import tempfile import unittest from buildman import cfgutil class TestAdjustCfg(unittest.TestCase): """Tests for config adjustment functions""" def test_adjust_cfg_nop(self): """check various adjustments of config that are nops""" # enable an enabled CONFIG self.assertEqual( 'CONFIG_FRED=y', cfgutil.adjust_cfg_line('CONFIG_FRED=y', {'FRED':'FRED'})[0]) # disable a disabled CONFIG self.assertEqual( '# CONFIG_FRED is not set', cfgutil.adjust_cfg_line( '# CONFIG_FRED is not set', {'FRED':'~FRED'})[0]) # use the adjust_cfg_lines() function self.assertEqual( ['CONFIG_FRED=y'], cfgutil.adjust_cfg_lines(['CONFIG_FRED=y'], {'FRED':'FRED'})) self.assertEqual( ['# CONFIG_FRED is not set'], cfgutil.adjust_cfg_lines(['CONFIG_FRED=y'], {'FRED':'~FRED'})) # handling an empty line self.assertEqual('#', cfgutil.adjust_cfg_line('#', {'FRED':'~FRED'})[0]) def test_adjust_cfg(self): """check various adjustments of config""" # disable a CONFIG self.assertEqual( '# CONFIG_FRED is not set', cfgutil.adjust_cfg_line('CONFIG_FRED=1' , {'FRED':'~FRED'})[0]) # enable a disabled CONFIG self.assertEqual( 'CONFIG_FRED=y', cfgutil.adjust_cfg_line( '# CONFIG_FRED is not set', {'FRED':'FRED'})[0]) # enable a CONFIG that doesn't exist self.assertEqual( ['CONFIG_FRED=y'], cfgutil.adjust_cfg_lines([], {'FRED':'FRED'})) # disable a CONFIG that doesn't exist self.assertEqual( ['# CONFIG_FRED is not set'], cfgutil.adjust_cfg_lines([], {'FRED':'~FRED'})) # disable a value CONFIG self.assertEqual( '# CONFIG_FRED is not set', cfgutil.adjust_cfg_line('CONFIG_FRED="fred"' , {'FRED':'~FRED'})[0]) # setting a value CONFIG self.assertEqual( 'CONFIG_FRED="fred"', cfgutil.adjust_cfg_line('# CONFIG_FRED is not set' , {'FRED':'FRED="fred"'})[0]) # changing a value CONFIG self.assertEqual( 'CONFIG_FRED="fred"', cfgutil.adjust_cfg_line('CONFIG_FRED="ernie"' , {'FRED':'FRED="fred"'})[0]) # setting a value for a CONFIG that doesn't exist self.assertEqual( ['CONFIG_FRED="fred"'], cfgutil.adjust_cfg_lines([], {'FRED':'FRED="fred"'})) def test_convert_adjust_cfg_list(self): """Check conversion of the list of changes into a dict""" self.assertEqual({}, cfgutil.convert_list_to_dict(None)) expect = { 'FRED':'FRED', 'MARY':'~MARY', 'JOHN':'JOHN=0x123', 'ALICE':'ALICE="alice"', 'AMY':'AMY', 'ABE':'~ABE', 'MARK':'MARK=0x456', 'ANNA':'ANNA="anna"', } actual = cfgutil.convert_list_to_dict( ['FRED', '~MARY', 'JOHN=0x123', 'ALICE="alice"', 'CONFIG_AMY', '~CONFIG_ABE', 'CONFIG_MARK=0x456', 'CONFIG_ANNA="anna"']) self.assertEqual(expect, actual) # Test comma-separated values actual = cfgutil.convert_list_to_dict( ['FRED,~MARY,JOHN=0x123', 'ALICE="alice"', 'CONFIG_AMY,~CONFIG_ABE', 'CONFIG_MARK=0x456,CONFIG_ANNA="anna"']) self.assertEqual(expect, actual) # Test mixed comma-separated and individual values actual = cfgutil.convert_list_to_dict( ['FRED,~MARY', 'JOHN=0x123', 'ALICE="alice",CONFIG_AMY', '~CONFIG_ABE,CONFIG_MARK=0x456', 'CONFIG_ANNA="anna"']) self.assertEqual(expect, actual) def test_adjust_cfg_to_fragment(self): """Test adjust_cfg_to_fragment creates correct fragment content""" # Empty dict returns empty string self.assertEqual('', cfgutil.adjust_cfg_to_fragment({})) # Enable option self.assertEqual('CONFIG_FRED=y\n', cfgutil.adjust_cfg_to_fragment({'FRED': 'FRED'})) # Disable option self.assertEqual('# CONFIG_FRED is not set\n', cfgutil.adjust_cfg_to_fragment({'FRED': '~FRED'})) # Set value self.assertEqual('CONFIG_FRED=0x123\n', cfgutil.adjust_cfg_to_fragment({'FRED': 'FRED=0x123'})) # Set string value self.assertEqual('CONFIG_FRED="fred"\n', cfgutil.adjust_cfg_to_fragment({'FRED': 'FRED="fred"'})) # Multiple options (note: dict order is preserved in Python 3.7+) result = cfgutil.adjust_cfg_to_fragment({ 'FRED': 'FRED', 'MARY': '~MARY', 'JOHN': 'JOHN=42' }) self.assertIn('CONFIG_FRED=y', result) self.assertIn('# CONFIG_MARY is not set', result) self.assertIn('CONFIG_JOHN=42', result) def test_check_cfg_file(self): """Test check_cfg_file detects conflicts as expected""" # Check failure to disable CONFIG result = cfgutil.check_cfg_lines(['CONFIG_FRED=1'], {'FRED':'~FRED'}) self.assertEqual([['~FRED', 'CONFIG_FRED=1']], result) result = cfgutil.check_cfg_lines( ['CONFIG_FRED=1', 'CONFIG_MARY="mary"'], {'FRED':'~FRED'}) self.assertEqual([['~FRED', 'CONFIG_FRED=1']], result) result = cfgutil.check_cfg_lines( ['CONFIG_FRED=1', 'CONFIG_MARY="mary"'], {'MARY':'~MARY'}) self.assertEqual([['~MARY', 'CONFIG_MARY="mary"']], result) # Check failure to enable CONFIG result = cfgutil.check_cfg_lines( ['# CONFIG_FRED is not set'], {'FRED':'FRED'}) self.assertEqual([['FRED', '# CONFIG_FRED is not set']], result) # Check failure to set CONFIG value result = cfgutil.check_cfg_lines( ['# CONFIG_FRED is not set', 'CONFIG_MARY="not"'], {'MARY':'MARY="mary"', 'FRED':'FRED'}) self.assertEqual([ ['FRED', '# CONFIG_FRED is not set'], ['MARY="mary"', 'CONFIG_MARY="not"']], result) # Check failure to add CONFIG value result = cfgutil.check_cfg_lines([], {'MARY':'MARY="mary"'}) self.assertEqual([ ['MARY="mary"', 'Missing expected line: CONFIG_MARY="mary"']], result) class TestRunMergeConfig(unittest.TestCase): """Tests for run_merge_config() function""" def test_merge_script_path(self): """Test that merge_config.sh path is relative to cwd, not absolute""" from unittest import mock from u_boot_pylib import command # Track commands that were run commands_run = [] def mock_run_one(*args, **kwargs): commands_run.append((args, kwargs)) result = command.CommandResult() result.return_code = 0 result.stdout = '' result.stderr = '' return result with mock.patch.object(command, 'run_one', mock_run_one): with mock.patch('os.path.exists', return_value=True): with mock.patch('os.unlink'): # Use a work directory path like buildman does src_dir = '../branch/.bm-work/00' cfgutil.run_merge_config( src_dir, 'build', 'build/.config', {'LOCALVERSION_AUTO': '~LOCALVERSION_AUTO'}, {}) # Find the merge_config.sh command merge_cmd = None for args, kwargs in commands_run: if args and 'merge_config.sh' in args[0]: merge_cmd = args merge_cwd = kwargs.get('cwd') break self.assertIsNotNone(merge_cmd, 'merge_config.sh command not found') # The script path should be relative, not include src_dir script_path = merge_cmd[0] self.assertEqual('scripts/kconfig/merge_config.sh', script_path, f'Script path should be relative, got: {script_path}') # The cwd should be src_dir self.assertEqual(src_dir, merge_cwd, f'cwd should be src_dir, got: {merge_cwd}') class TestProcessConfig(unittest.TestCase): """Tests for process_config() function""" def test_process_config_defconfig(self): """Test process_config() with .config style file""" config_data = '''# This is a comment CONFIG_OPTION_A=y CONFIG_OPTION_B="string" CONFIG_OPTION_C=123 # CONFIG_OPTION_D is not set ''' with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.config') as tmp: tmp.write(config_data) tmp_name = tmp.name try: config = cfgutil.process_config(tmp_name, squash_config_y=False) self.assertEqual('y', config['CONFIG_OPTION_A']) self.assertEqual('"string"', config['CONFIG_OPTION_B']) self.assertEqual('123', config['CONFIG_OPTION_C']) # Comments should be ignored self.assertNotIn('CONFIG_OPTION_D', config) finally: os.unlink(tmp_name) def test_process_config_autoconf_h(self): """Test process_config() with autoconf.h style file""" config_data = '''/* Auto-generated header */ #define CONFIG_OPTION_A 1 #define CONFIG_OPTION_B "value" #define CONFIG_OPTION_C #define NOT_CONFIG 1 ''' with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.h') as tmp: tmp.write(config_data) tmp_name = tmp.name try: config = cfgutil.process_config(tmp_name, squash_config_y=False) self.assertEqual('1', config['CONFIG_OPTION_A']) self.assertEqual('"value"', config['CONFIG_OPTION_B']) # #define without value gets empty string (squash_config_y=False) self.assertEqual('', config['CONFIG_OPTION_C']) # Non-CONFIG_ defines should be ignored self.assertNotIn('NOT_CONFIG', config) finally: os.unlink(tmp_name) def test_process_config_nonexistent(self): """Test process_config() with non-existent file""" config = cfgutil.process_config('/nonexistent/path/config', squash_config_y=False) self.assertEqual({}, config) def test_process_config_squash_y(self): """Test process_config() with squash_config_y enabled""" config_data = '''CONFIG_OPTION_A=y CONFIG_OPTION_B=n #define CONFIG_OPTION_C ''' with tempfile.NamedTemporaryFile(mode='w', delete=False) as tmp: tmp.write(config_data) tmp_name = tmp.name try: config = cfgutil.process_config(tmp_name, squash_config_y=True) # y should be squashed to 1 self.assertEqual('1', config['CONFIG_OPTION_A']) # n should remain n self.assertEqual('n', config['CONFIG_OPTION_B']) # Empty #define should get '1' when squash_config_y is True self.assertEqual('1', config['CONFIG_OPTION_C']) finally: os.unlink(tmp_name) if __name__ == "__main__": unittest.main() |