Fri, 16 Jan 2015 18:13:44 +0100
Integrate suggestion from review to improve consistency with existing code.
michael@0 | 1 | import subprocess |
michael@0 | 2 | import unittest |
michael@0 | 3 | import sys |
michael@0 | 4 | import os |
michael@0 | 5 | import imp |
michael@0 | 6 | from tempfile import mkdtemp |
michael@0 | 7 | from shutil import rmtree |
michael@0 | 8 | import mozunit |
michael@0 | 9 | |
michael@0 | 10 | from UserString import UserString |
michael@0 | 11 | # Create a controlled configuration for use by expandlibs |
michael@0 | 12 | config_win = { |
michael@0 | 13 | 'AR': 'lib', |
michael@0 | 14 | 'AR_EXTRACT': '', |
michael@0 | 15 | 'DLL_PREFIX': '', |
michael@0 | 16 | 'LIB_PREFIX': '', |
michael@0 | 17 | 'OBJ_SUFFIX': '.obj', |
michael@0 | 18 | 'LIB_SUFFIX': '.lib', |
michael@0 | 19 | 'DLL_SUFFIX': '.dll', |
michael@0 | 20 | 'IMPORT_LIB_SUFFIX': '.lib', |
michael@0 | 21 | 'LIBS_DESC_SUFFIX': '.desc', |
michael@0 | 22 | 'EXPAND_LIBS_LIST_STYLE': 'list', |
michael@0 | 23 | } |
michael@0 | 24 | config_unix = { |
michael@0 | 25 | 'AR': 'ar', |
michael@0 | 26 | 'AR_EXTRACT': 'ar -x', |
michael@0 | 27 | 'DLL_PREFIX': 'lib', |
michael@0 | 28 | 'LIB_PREFIX': 'lib', |
michael@0 | 29 | 'OBJ_SUFFIX': '.o', |
michael@0 | 30 | 'LIB_SUFFIX': '.a', |
michael@0 | 31 | 'DLL_SUFFIX': '.so', |
michael@0 | 32 | 'IMPORT_LIB_SUFFIX': '', |
michael@0 | 33 | 'LIBS_DESC_SUFFIX': '.desc', |
michael@0 | 34 | 'EXPAND_LIBS_LIST_STYLE': 'linkerscript', |
michael@0 | 35 | } |
michael@0 | 36 | |
michael@0 | 37 | config = sys.modules['expandlibs_config'] = imp.new_module('expandlibs_config') |
michael@0 | 38 | |
michael@0 | 39 | from expandlibs import LibDescriptor, ExpandArgs, relativize, ExpandLibsDeps |
michael@0 | 40 | from expandlibs_gen import generate |
michael@0 | 41 | from expandlibs_exec import ExpandArgsMore, SectionFinder |
michael@0 | 42 | |
michael@0 | 43 | def Lib(name): |
michael@0 | 44 | return config.LIB_PREFIX + name + config.LIB_SUFFIX |
michael@0 | 45 | |
michael@0 | 46 | def Obj(name): |
michael@0 | 47 | return name + config.OBJ_SUFFIX |
michael@0 | 48 | |
michael@0 | 49 | def Dll(name): |
michael@0 | 50 | return config.DLL_PREFIX + name + config.DLL_SUFFIX |
michael@0 | 51 | |
michael@0 | 52 | def ImportLib(name): |
michael@0 | 53 | if not len(config.IMPORT_LIB_SUFFIX): return Dll(name) |
michael@0 | 54 | return config.LIB_PREFIX + name + config.IMPORT_LIB_SUFFIX |
michael@0 | 55 | |
michael@0 | 56 | class TestRelativize(unittest.TestCase): |
michael@0 | 57 | def test_relativize(self): |
michael@0 | 58 | '''Test relativize()''' |
michael@0 | 59 | os_path_exists = os.path.exists |
michael@0 | 60 | def exists(path): |
michael@0 | 61 | return True |
michael@0 | 62 | os.path.exists = exists |
michael@0 | 63 | self.assertEqual(relativize(os.path.abspath(os.curdir)), os.curdir) |
michael@0 | 64 | self.assertEqual(relativize(os.path.abspath(os.pardir)), os.pardir) |
michael@0 | 65 | self.assertEqual(relativize(os.path.join(os.curdir, 'a')), 'a') |
michael@0 | 66 | self.assertEqual(relativize(os.path.join(os.path.abspath(os.curdir), 'a')), 'a') |
michael@0 | 67 | # relativize is expected to return the absolute path if it is shorter |
michael@0 | 68 | self.assertEqual(relativize(os.sep), os.sep) |
michael@0 | 69 | os.path.exists = os.path.exists |
michael@0 | 70 | |
michael@0 | 71 | class TestLibDescriptor(unittest.TestCase): |
michael@0 | 72 | def test_serialize(self): |
michael@0 | 73 | '''Test LibDescriptor's serialization''' |
michael@0 | 74 | desc = LibDescriptor() |
michael@0 | 75 | desc[LibDescriptor.KEYS[0]] = ['a', 'b'] |
michael@0 | 76 | self.assertEqual(str(desc), "{0} = a b".format(LibDescriptor.KEYS[0])) |
michael@0 | 77 | desc['unsupported-key'] = ['a'] |
michael@0 | 78 | self.assertEqual(str(desc), "{0} = a b".format(LibDescriptor.KEYS[0])) |
michael@0 | 79 | desc[LibDescriptor.KEYS[1]] = ['c', 'd', 'e'] |
michael@0 | 80 | self.assertEqual(str(desc), |
michael@0 | 81 | "{0} = a b\n{1} = c d e" |
michael@0 | 82 | .format(LibDescriptor.KEYS[0], LibDescriptor.KEYS[1])) |
michael@0 | 83 | desc[LibDescriptor.KEYS[0]] = [] |
michael@0 | 84 | self.assertEqual(str(desc), "{0} = c d e".format(LibDescriptor.KEYS[1])) |
michael@0 | 85 | |
michael@0 | 86 | def test_read(self): |
michael@0 | 87 | '''Test LibDescriptor's initialization''' |
michael@0 | 88 | desc_list = ["# Comment", |
michael@0 | 89 | "{0} = a b".format(LibDescriptor.KEYS[1]), |
michael@0 | 90 | "", # Empty line |
michael@0 | 91 | "foo = bar", # Should be discarded |
michael@0 | 92 | "{0} = c d e".format(LibDescriptor.KEYS[0])] |
michael@0 | 93 | desc = LibDescriptor(desc_list) |
michael@0 | 94 | self.assertEqual(desc[LibDescriptor.KEYS[1]], ['a', 'b']) |
michael@0 | 95 | self.assertEqual(desc[LibDescriptor.KEYS[0]], ['c', 'd', 'e']) |
michael@0 | 96 | self.assertEqual(False, 'foo' in desc) |
michael@0 | 97 | |
michael@0 | 98 | def wrap_method(conf, wrapped_method): |
michael@0 | 99 | '''Wrapper used to call a test with a specific configuration''' |
michael@0 | 100 | def _method(self): |
michael@0 | 101 | for key in conf: |
michael@0 | 102 | setattr(config, key, conf[key]) |
michael@0 | 103 | self.init() |
michael@0 | 104 | try: |
michael@0 | 105 | wrapped_method(self) |
michael@0 | 106 | except: |
michael@0 | 107 | raise |
michael@0 | 108 | finally: |
michael@0 | 109 | self.cleanup() |
michael@0 | 110 | return _method |
michael@0 | 111 | |
michael@0 | 112 | class ReplicateTests(type): |
michael@0 | 113 | '''Replicates tests for unix and windows variants''' |
michael@0 | 114 | def __new__(cls, clsName, bases, dict): |
michael@0 | 115 | for name in [key for key in dict if key.startswith('test_')]: |
michael@0 | 116 | dict[name + '_unix'] = wrap_method(config_unix, dict[name]) |
michael@0 | 117 | dict[name + '_unix'].__doc__ = dict[name].__doc__ + ' (unix)' |
michael@0 | 118 | dict[name + '_win'] = wrap_method(config_win, dict[name]) |
michael@0 | 119 | dict[name + '_win'].__doc__ = dict[name].__doc__ + ' (win)' |
michael@0 | 120 | del dict[name] |
michael@0 | 121 | return type.__new__(cls, clsName, bases, dict) |
michael@0 | 122 | |
michael@0 | 123 | class TestCaseWithTmpDir(unittest.TestCase): |
michael@0 | 124 | __metaclass__ = ReplicateTests |
michael@0 | 125 | def init(self): |
michael@0 | 126 | self.tmpdir = os.path.abspath(mkdtemp(dir=os.curdir)) |
michael@0 | 127 | |
michael@0 | 128 | def cleanup(self): |
michael@0 | 129 | rmtree(self.tmpdir) |
michael@0 | 130 | |
michael@0 | 131 | def touch(self, files): |
michael@0 | 132 | for f in files: |
michael@0 | 133 | open(f, 'w').close() |
michael@0 | 134 | |
michael@0 | 135 | def tmpfile(self, *args): |
michael@0 | 136 | return os.path.join(self.tmpdir, *args) |
michael@0 | 137 | |
michael@0 | 138 | class TestExpandLibsGen(TestCaseWithTmpDir): |
michael@0 | 139 | def test_generate(self): |
michael@0 | 140 | '''Test library descriptor generation''' |
michael@0 | 141 | files = [self.tmpfile(f) for f in |
michael@0 | 142 | [Lib('a'), Obj('b'), Lib('c'), Obj('d'), Obj('e'), Lib('f')]] |
michael@0 | 143 | self.touch(files[:-1]) |
michael@0 | 144 | self.touch([files[-1] + config.LIBS_DESC_SUFFIX]) |
michael@0 | 145 | |
michael@0 | 146 | desc = generate(files) |
michael@0 | 147 | self.assertEqual(desc['OBJS'], [self.tmpfile(Obj(s)) for s in ['b', 'd', 'e']]) |
michael@0 | 148 | self.assertEqual(desc['LIBS'], [self.tmpfile(Lib(s)) for s in ['a', 'c', 'f']]) |
michael@0 | 149 | |
michael@0 | 150 | self.assertRaises(Exception, generate, files + [self.tmpfile(Obj('z'))]) |
michael@0 | 151 | self.assertRaises(Exception, generate, files + [self.tmpfile(Lib('y'))]) |
michael@0 | 152 | |
michael@0 | 153 | class TestExpandInit(TestCaseWithTmpDir): |
michael@0 | 154 | def init(self): |
michael@0 | 155 | ''' Initializes test environment for library expansion tests''' |
michael@0 | 156 | super(TestExpandInit, self).init() |
michael@0 | 157 | # Create 2 fake libraries, each containing 3 objects, and the second |
michael@0 | 158 | # including the first one and another library. |
michael@0 | 159 | os.mkdir(self.tmpfile('libx')) |
michael@0 | 160 | os.mkdir(self.tmpfile('liby')) |
michael@0 | 161 | self.libx_files = [self.tmpfile('libx', Obj(f)) for f in ['g', 'h', 'i']] |
michael@0 | 162 | self.liby_files = [self.tmpfile('liby', Obj(f)) for f in ['j', 'k', 'l']] + [self.tmpfile('liby', Lib('z'))] |
michael@0 | 163 | self.touch(self.libx_files + self.liby_files) |
michael@0 | 164 | with open(self.tmpfile('libx', Lib('x') + config.LIBS_DESC_SUFFIX), 'w') as f: |
michael@0 | 165 | f.write(str(generate(self.libx_files))) |
michael@0 | 166 | with open(self.tmpfile('liby', Lib('y') + config.LIBS_DESC_SUFFIX), 'w') as f: |
michael@0 | 167 | f.write(str(generate(self.liby_files + [self.tmpfile('libx', Lib('x'))]))) |
michael@0 | 168 | |
michael@0 | 169 | # Create various objects and libraries |
michael@0 | 170 | self.arg_files = [self.tmpfile(f) for f in [Lib('a'), Obj('b'), Obj('c'), Lib('d'), Obj('e')]] |
michael@0 | 171 | # We always give library names (LIB_PREFIX/SUFFIX), even for |
michael@0 | 172 | # dynamic/import libraries |
michael@0 | 173 | self.files = self.arg_files + [self.tmpfile(ImportLib('f'))] |
michael@0 | 174 | self.arg_files += [self.tmpfile(Lib('f'))] |
michael@0 | 175 | self.touch(self.files) |
michael@0 | 176 | |
michael@0 | 177 | def assertRelEqual(self, args1, args2): |
michael@0 | 178 | self.assertEqual(args1, [relativize(a) for a in args2]) |
michael@0 | 179 | |
michael@0 | 180 | class TestExpandArgs(TestExpandInit): |
michael@0 | 181 | def test_expand(self): |
michael@0 | 182 | '''Test library expansion''' |
michael@0 | 183 | # Expanding arguments means libraries with a descriptor are expanded |
michael@0 | 184 | # with the descriptor content, and import libraries are used when |
michael@0 | 185 | # a library doesn't exist |
michael@0 | 186 | args = ExpandArgs(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) |
michael@0 | 187 | self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files) |
michael@0 | 188 | |
michael@0 | 189 | # When a library exists at the same time as a descriptor, we just use |
michael@0 | 190 | # the library |
michael@0 | 191 | self.touch([self.tmpfile('libx', Lib('x'))]) |
michael@0 | 192 | args = ExpandArgs(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) |
michael@0 | 193 | self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + [self.tmpfile('libx', Lib('x'))]) |
michael@0 | 194 | |
michael@0 | 195 | self.touch([self.tmpfile('liby', Lib('y'))]) |
michael@0 | 196 | args = ExpandArgs(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) |
michael@0 | 197 | self.assertRelEqual(args, ['foo', '-bar'] + self.files + [self.tmpfile('liby', Lib('y'))]) |
michael@0 | 198 | |
michael@0 | 199 | class TestExpandLibsDeps(TestExpandInit): |
michael@0 | 200 | def test_expandlibsdeps(self): |
michael@0 | 201 | '''Test library expansion for dependencies''' |
michael@0 | 202 | # Dependency list for a library with a descriptor is equivalent to |
michael@0 | 203 | # the arguments expansion, to which we add each descriptor |
michael@0 | 204 | args = self.arg_files + [self.tmpfile('liby', Lib('y'))] |
michael@0 | 205 | self.assertRelEqual(ExpandLibsDeps(args), ExpandArgs(args) + [self.tmpfile('libx', Lib('x') + config.LIBS_DESC_SUFFIX), self.tmpfile('liby', Lib('y') + config.LIBS_DESC_SUFFIX)]) |
michael@0 | 206 | |
michael@0 | 207 | # When a library exists at the same time as a descriptor, the |
michael@0 | 208 | # descriptor is not a dependency |
michael@0 | 209 | self.touch([self.tmpfile('libx', Lib('x'))]) |
michael@0 | 210 | args = self.arg_files + [self.tmpfile('liby', Lib('y'))] |
michael@0 | 211 | self.assertRelEqual(ExpandLibsDeps(args), ExpandArgs(args) + [self.tmpfile('liby', Lib('y') + config.LIBS_DESC_SUFFIX)]) |
michael@0 | 212 | |
michael@0 | 213 | self.touch([self.tmpfile('liby', Lib('y'))]) |
michael@0 | 214 | args = self.arg_files + [self.tmpfile('liby', Lib('y'))] |
michael@0 | 215 | self.assertRelEqual(ExpandLibsDeps(args), ExpandArgs(args)) |
michael@0 | 216 | |
michael@0 | 217 | class TestExpandArgsMore(TestExpandInit): |
michael@0 | 218 | def test_makelist(self): |
michael@0 | 219 | '''Test grouping object files in lists''' |
michael@0 | 220 | # ExpandArgsMore does the same as ExpandArgs |
michael@0 | 221 | with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args: |
michael@0 | 222 | self.assertRelEqual(args, ['foo', '-bar'] + self.files + self.liby_files + self.libx_files) |
michael@0 | 223 | |
michael@0 | 224 | # But also has an extra method replacing object files with a list |
michael@0 | 225 | args.makelist() |
michael@0 | 226 | # self.files has objects at #1, #2, #4 |
michael@0 | 227 | self.assertRelEqual(args[:3], ['foo', '-bar'] + self.files[:1]) |
michael@0 | 228 | self.assertRelEqual(args[4:], [self.files[3]] + self.files[5:] + [self.tmpfile('liby', Lib('z'))]) |
michael@0 | 229 | |
michael@0 | 230 | # Check the list file content |
michael@0 | 231 | objs = [f for f in self.files + self.liby_files + self.libx_files if f.endswith(config.OBJ_SUFFIX)] |
michael@0 | 232 | if config.EXPAND_LIBS_LIST_STYLE == "linkerscript": |
michael@0 | 233 | self.assertNotEqual(args[3][0], '@') |
michael@0 | 234 | filename = args[3] |
michael@0 | 235 | content = ['INPUT("{0}")'.format(relativize(f)) for f in objs] |
michael@0 | 236 | with open(filename, 'r') as f: |
michael@0 | 237 | self.assertEqual([l.strip() for l in f.readlines() if len(l.strip())], content) |
michael@0 | 238 | elif config.EXPAND_LIBS_LIST_STYLE == "list": |
michael@0 | 239 | self.assertEqual(args[3][0], '@') |
michael@0 | 240 | filename = args[3][1:] |
michael@0 | 241 | content = objs |
michael@0 | 242 | with open(filename, 'r') as f: |
michael@0 | 243 | self.assertRelEqual([l.strip() for l in f.readlines() if len(l.strip())], content) |
michael@0 | 244 | |
michael@0 | 245 | tmp = args.tmp |
michael@0 | 246 | # Check that all temporary files are properly removed |
michael@0 | 247 | self.assertEqual(True, all([not os.path.exists(f) for f in tmp])) |
michael@0 | 248 | |
michael@0 | 249 | def test_extract(self): |
michael@0 | 250 | '''Test library extraction''' |
michael@0 | 251 | # Divert subprocess.call |
michael@0 | 252 | subprocess_call = subprocess.call |
michael@0 | 253 | extracted = {} |
michael@0 | 254 | def call(args, **kargs): |
michael@0 | 255 | if config.AR == 'lib': |
michael@0 | 256 | self.assertEqual(args[:2], [config.AR, '-NOLOGO']) |
michael@0 | 257 | self.assertTrue(args[2].startswith('-EXTRACT:')) |
michael@0 | 258 | extract = [args[2][len('-EXTRACT:'):]] |
michael@0 | 259 | self.assertTrue(extract) |
michael@0 | 260 | args = args[3:] |
michael@0 | 261 | else: |
michael@0 | 262 | # The command called is always AR_EXTRACT |
michael@0 | 263 | ar_extract = config.AR_EXTRACT.split() |
michael@0 | 264 | self.assertEqual(args[:len(ar_extract)], ar_extract) |
michael@0 | 265 | args = args[len(ar_extract):] |
michael@0 | 266 | # Remaining argument is always one library |
michael@0 | 267 | self.assertEqual(len(args), 1) |
michael@0 | 268 | arg = args[0] |
michael@0 | 269 | self.assertEqual(os.path.splitext(arg)[1], config.LIB_SUFFIX) |
michael@0 | 270 | # Simulate file extraction |
michael@0 | 271 | lib = os.path.splitext(os.path.basename(arg))[0] |
michael@0 | 272 | if config.AR != 'lib': |
michael@0 | 273 | extract = [lib, lib + '2'] |
michael@0 | 274 | extract = [os.path.join(kargs['cwd'], f) for f in extract] |
michael@0 | 275 | if config.AR != 'lib': |
michael@0 | 276 | extract = [Obj(f) for f in extract] |
michael@0 | 277 | if not lib in extracted: |
michael@0 | 278 | extracted[lib] = [] |
michael@0 | 279 | extracted[lib].extend(extract) |
michael@0 | 280 | self.touch(extract) |
michael@0 | 281 | subprocess.call = call |
michael@0 | 282 | |
michael@0 | 283 | def check_output(args, **kargs): |
michael@0 | 284 | # The command called is always AR |
michael@0 | 285 | ar = config.AR |
michael@0 | 286 | self.assertEqual(args[0:3], [ar, '-NOLOGO', '-LIST']) |
michael@0 | 287 | # Remaining argument is always one library |
michael@0 | 288 | self.assertRelEqual([os.path.splitext(arg)[1] for arg in args[3:]], |
michael@0 | 289 | [config.LIB_SUFFIX]) |
michael@0 | 290 | # Simulate LIB -NOLOGO -LIST |
michael@0 | 291 | lib = os.path.splitext(os.path.basename(args[3]))[0] |
michael@0 | 292 | return '%s\n%s\n' % (Obj(lib), Obj(lib + '2')) |
michael@0 | 293 | subprocess.check_output = check_output |
michael@0 | 294 | |
michael@0 | 295 | # ExpandArgsMore does the same as ExpandArgs |
michael@0 | 296 | self.touch([self.tmpfile('liby', Lib('y'))]) |
michael@0 | 297 | with ExpandArgsMore(['foo', '-bar'] + self.arg_files + [self.tmpfile('liby', Lib('y'))]) as args: |
michael@0 | 298 | self.assertRelEqual(args, ['foo', '-bar'] + self.files + [self.tmpfile('liby', Lib('y'))]) |
michael@0 | 299 | |
michael@0 | 300 | # ExpandArgsMore also has an extra method extracting static libraries |
michael@0 | 301 | # when possible |
michael@0 | 302 | args.extract() |
michael@0 | 303 | |
michael@0 | 304 | files = self.files + self.liby_files + self.libx_files |
michael@0 | 305 | # With AR_EXTRACT, it uses the descriptors when there are, and |
michael@0 | 306 | # actually |
michael@0 | 307 | # extracts the remaining libraries |
michael@0 | 308 | extracted_args = [] |
michael@0 | 309 | for f in files: |
michael@0 | 310 | if f.endswith(config.LIB_SUFFIX): |
michael@0 | 311 | extracted_args.extend(sorted(extracted[os.path.splitext(os.path.basename(f))[0]])) |
michael@0 | 312 | else: |
michael@0 | 313 | extracted_args.append(f) |
michael@0 | 314 | self.assertRelEqual(args, ['foo', '-bar'] + extracted_args) |
michael@0 | 315 | |
michael@0 | 316 | tmp = args.tmp |
michael@0 | 317 | # Check that all temporary files are properly removed |
michael@0 | 318 | self.assertEqual(True, all([not os.path.exists(f) for f in tmp])) |
michael@0 | 319 | |
michael@0 | 320 | # Restore subprocess.call |
michael@0 | 321 | subprocess.call = subprocess_call |
michael@0 | 322 | |
michael@0 | 323 | class FakeProcess(object): |
michael@0 | 324 | def __init__(self, out, err = ''): |
michael@0 | 325 | self.out = out |
michael@0 | 326 | self.err = err |
michael@0 | 327 | |
michael@0 | 328 | def communicate(self): |
michael@0 | 329 | return (self.out, self.err) |
michael@0 | 330 | |
michael@0 | 331 | OBJDUMPS = { |
michael@0 | 332 | 'foo.o': ''' |
michael@0 | 333 | 00000000 g F .text\t00000001 foo |
michael@0 | 334 | 00000000 g F .text._Z6foobarv\t00000001 _Z6foobarv |
michael@0 | 335 | 00000000 g F .text.hello\t00000001 hello |
michael@0 | 336 | 00000000 g F .text._ZThn4_6foobarv\t00000001 _ZThn4_6foobarv |
michael@0 | 337 | ''', |
michael@0 | 338 | 'bar.o': ''' |
michael@0 | 339 | 00000000 g F .text.hi\t00000001 hi |
michael@0 | 340 | 00000000 g F .text.hot._Z6barbazv\t00000001 .hidden _Z6barbazv |
michael@0 | 341 | ''', |
michael@0 | 342 | } |
michael@0 | 343 | |
michael@0 | 344 | PRINT_ICF = ''' |
michael@0 | 345 | ld: ICF folding section '.text.hello' in file 'foo.o'into '.text.hi' in file 'bar.o' |
michael@0 | 346 | ld: ICF folding section '.foo' in file 'foo.o'into '.foo' in file 'bar.o' |
michael@0 | 347 | ''' |
michael@0 | 348 | |
michael@0 | 349 | class SubprocessPopen(object): |
michael@0 | 350 | def __init__(self, test): |
michael@0 | 351 | self.test = test |
michael@0 | 352 | |
michael@0 | 353 | def __call__(self, args, stdout = None, stderr = None): |
michael@0 | 354 | self.test.assertEqual(stdout, subprocess.PIPE) |
michael@0 | 355 | self.test.assertEqual(stderr, subprocess.PIPE) |
michael@0 | 356 | if args[0] == 'objdump': |
michael@0 | 357 | self.test.assertEqual(args[1], '-t') |
michael@0 | 358 | self.test.assertTrue(args[2] in OBJDUMPS) |
michael@0 | 359 | return FakeProcess(OBJDUMPS[args[2]]) |
michael@0 | 360 | else: |
michael@0 | 361 | return FakeProcess('', PRINT_ICF) |
michael@0 | 362 | |
michael@0 | 363 | class TestSectionFinder(unittest.TestCase): |
michael@0 | 364 | def test_getSections(self): |
michael@0 | 365 | '''Test SectionFinder''' |
michael@0 | 366 | # Divert subprocess.Popen |
michael@0 | 367 | subprocess_popen = subprocess.Popen |
michael@0 | 368 | subprocess.Popen = SubprocessPopen(self) |
michael@0 | 369 | config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript' |
michael@0 | 370 | config.OBJ_SUFFIX = '.o' |
michael@0 | 371 | config.LIB_SUFFIX = '.a' |
michael@0 | 372 | finder = SectionFinder(['foo.o', 'bar.o']) |
michael@0 | 373 | self.assertEqual(finder.getSections('foobar'), []) |
michael@0 | 374 | self.assertEqual(finder.getSections('_Z6barbazv'), ['.text.hot._Z6barbazv']) |
michael@0 | 375 | self.assertEqual(finder.getSections('_Z6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv']) |
michael@0 | 376 | self.assertEqual(finder.getSections('_ZThn4_6foobarv'), ['.text._Z6foobarv', '.text._ZThn4_6foobarv']) |
michael@0 | 377 | subprocess.Popen = subprocess_popen |
michael@0 | 378 | |
michael@0 | 379 | class TestSymbolOrder(unittest.TestCase): |
michael@0 | 380 | def test_getOrderedSections(self): |
michael@0 | 381 | '''Test ExpandMoreArgs' _getOrderedSections''' |
michael@0 | 382 | # Divert subprocess.Popen |
michael@0 | 383 | subprocess_popen = subprocess.Popen |
michael@0 | 384 | subprocess.Popen = SubprocessPopen(self) |
michael@0 | 385 | config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript' |
michael@0 | 386 | config.OBJ_SUFFIX = '.o' |
michael@0 | 387 | config.LIB_SUFFIX = '.a' |
michael@0 | 388 | config.LD_PRINT_ICF_SECTIONS = '' |
michael@0 | 389 | args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o']) |
michael@0 | 390 | self.assertEqual(args._getOrderedSections(['_Z6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv']) |
michael@0 | 391 | self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hot._Z6barbazv']) |
michael@0 | 392 | subprocess.Popen = subprocess_popen |
michael@0 | 393 | |
michael@0 | 394 | def test_getFoldedSections(self): |
michael@0 | 395 | '''Test ExpandMoreArgs' _getFoldedSections''' |
michael@0 | 396 | # Divert subprocess.Popen |
michael@0 | 397 | subprocess_popen = subprocess.Popen |
michael@0 | 398 | subprocess.Popen = SubprocessPopen(self) |
michael@0 | 399 | config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections' |
michael@0 | 400 | args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o']) |
michael@0 | 401 | self.assertEqual(args._getFoldedSections(), {'.text.hello': ['.text.hi'], '.text.hi': ['.text.hello']}) |
michael@0 | 402 | subprocess.Popen = subprocess_popen |
michael@0 | 403 | |
michael@0 | 404 | def test_getOrderedSectionsWithICF(self): |
michael@0 | 405 | '''Test ExpandMoreArgs' _getOrderedSections, with ICF''' |
michael@0 | 406 | # Divert subprocess.Popen |
michael@0 | 407 | subprocess_popen = subprocess.Popen |
michael@0 | 408 | subprocess.Popen = SubprocessPopen(self) |
michael@0 | 409 | config.EXPAND_LIBS_ORDER_STYLE = 'linkerscript' |
michael@0 | 410 | config.OBJ_SUFFIX = '.o' |
michael@0 | 411 | config.LIB_SUFFIX = '.a' |
michael@0 | 412 | config.LD_PRINT_ICF_SECTIONS = '-Wl,--print-icf-sections' |
michael@0 | 413 | args = ExpandArgsMore(['foo', '-bar', 'bar.o', 'foo.o']) |
michael@0 | 414 | self.assertEqual(args._getOrderedSections(['hello', '_Z6barbazv']), ['.text.hello', '.text.hi', '.text.hot._Z6barbazv']) |
michael@0 | 415 | self.assertEqual(args._getOrderedSections(['_ZThn4_6foobarv', 'hi', '_Z6barbazv']), ['.text._Z6foobarv', '.text._ZThn4_6foobarv', '.text.hi', '.text.hello', '.text.hot._Z6barbazv']) |
michael@0 | 416 | subprocess.Popen = subprocess_popen |
michael@0 | 417 | |
michael@0 | 418 | |
michael@0 | 419 | if __name__ == '__main__': |
michael@0 | 420 | mozunit.main() |