~ubuntu-branches/ubuntu/quantal/enigmail/quantal-security

« back to all changes in this revision

Viewing changes to mozilla/config/tests/unit-expandlibs.py

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2013-09-13 16:02:15 UTC
  • mfrom: (0.12.16)
  • Revision ID: package-import@ubuntu.com-20130913160215-u3g8nmwa0pdwagwc
Tags: 2:1.5.2-0ubuntu0.12.10.1
* New upstream release v1.5.2 for Thunderbird 24

* Build enigmail using a stripped down Thunderbird 17 build system, as it's
  now quite difficult to build the way we were doing previously, with the
  latest Firefox build system
* Add debian/patches/no_libxpcom.patch - Don't link against libxpcom, as it
  doesn't exist anymore (but exists in the build system)
* Add debian/patches/use_sdk.patch - Use the SDK version of xpt.py and
  friends
* Drop debian/patches/ipc-pipe_rename.diff (not needed anymore)
* Drop debian/patches/makefile_depth.diff (not needed anymore)

Show diffs side-by-side

added added

removed removed

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