blob: a87f5164ba4be09a79ae0c4b7d75745b1b5b2c2e [file] [log] [blame]
#!/usr/bin/python
#
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unittest for generate_gn.py.
It's tough to test the lower-level GetSourceFiles() and GetObjectFiles()
functions, so this focuses on the higher-level functions assuming those two
functions are working as intended (i.e., producing lists of files).
"""
import generate_gn as gg
from generate_gn import SourceSet, SourceListCondition
import string
import unittest
from os import path
class ModuleUnittest(unittest.TestCase):
def testGetObjectToSourceMapping(self):
srcs = [
'a.c',
'b.asm',
'c.cc',
]
expected = {
'a.o': 'a.c',
'b.o': 'b.asm',
'c.o': 'c.cc',
}
self.assertEqual(expected, gg.GetObjectToSourceMapping(srcs))
def testGetSourceFileSet(self):
objs_to_srcs = {
'a.o': 'a.c',
'b.o': 'b.asm',
'c.o': 'c.cc',
}
objs = [
'a.o',
'c.o',
]
expected = set(['a.c', 'c.cc'])
self.assertEqual(expected, gg.GetSourceFileSet(objs_to_srcs, objs))
def testGetSourceFileSet_NotFound(self):
objs_to_srcs = {
'a.o': 'a.c',
'b.o': 'b.asm',
'c.o': 'c.cc',
}
objs = [
'd.o',
]
self.assertRaises(KeyError, gg.GetSourceFileSet, objs_to_srcs, objs)
class SourceSetUnittest(unittest.TestCase):
def testEquals(self):
a = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '3')]))
b = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '3')]))
c = SourceSet(set(['c', 'd']), set([SourceListCondition('1', '2', '3')]))
d = SourceSet(set(['a', 'b']), set([SourceListCondition('0', '2', '3')]))
e = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '0', '3')]))
f = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '0')]))
self.assertEqual(a, b)
self.assertNotEqual(a, c)
self.assertNotEqual(a, d)
self.assertNotEqual(a, e)
self.assertNotEqual(a, f)
def testIntersect_Exact(self):
a = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '3')]))
b = SourceSet(set(['a', 'b']), set([SourceListCondition('3', '4', '6')]))
c = a.Intersect(b)
self.assertEqual(c.sources, set(['a', 'b']))
self.assertEqual(
c.conditions,
set([
SourceListCondition('1', '2', '3'),
SourceListCondition('3', '4', '6')
]))
self.assertFalse(c.IsEmpty())
def testIntersect_Disjoint(self):
a = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '3')]))
b = SourceSet(set(['c', 'd']), set([SourceListCondition('3', '4', '6')]))
c = a.Intersect(b)
self.assertEqual(c.sources, set())
self.assertEqual(
c.conditions,
set([
SourceListCondition('1', '2', '3'),
SourceListCondition('3', '4', '6')
]))
self.assertTrue(c.IsEmpty())
def testIntersect_Overlap(self):
a = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '3')]))
b = SourceSet(set(['b', 'c']), set([SourceListCondition('3', '4', '6')]))
c = a.Intersect(b)
self.assertEqual(c.sources, set(['b']))
self.assertEqual(
c.conditions,
set([
SourceListCondition('1', '2', '3'),
SourceListCondition('3', '4', '6')
]))
self.assertFalse(c.IsEmpty())
def testDifference_Exact(self):
a = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '3')]))
b = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '3')]))
c = a.Difference(b)
self.assertEqual(c.sources, set())
self.assertEqual(c.conditions, set([SourceListCondition('1', '2', '3')]))
self.assertTrue(c.IsEmpty())
def testDifference_Disjoint(self):
a = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '3')]))
b = SourceSet(set(['c', 'd']), set([SourceListCondition('3', '4', '6')]))
c = a.Difference(b)
self.assertEqual(c.sources, set(['a', 'b']))
self.assertEqual(c.conditions, set())
self.assertTrue(c.IsEmpty())
def testDifference_Overlap(self):
a = SourceSet(set(['a', 'b']), set([SourceListCondition('1', '2', '5')]))
b = SourceSet(
set(['b', 'c', 'd']),
set([
SourceListCondition('1', '2', '5'),
SourceListCondition('3', '4', '6')
]))
c = a.Difference(b)
self.assertEqual(c.sources, set(['a']))
self.assertEqual(c.conditions, set([SourceListCondition('1', '2', '5')]))
self.assertFalse(c.IsEmpty())
def testGenerateGnStanza(self):
# ia32 should be x86. Win should appear as an OS restriction.
a = SourceSet(
set(['a', 'b']), set([SourceListCondition('ia32', 'Chromium', 'win')]))
a_stanza = a.GenerateGnStanza()
string.index(a_stanza, 'current_cpu == "x86"')
string.index(a_stanza, 'is_win')
# x64 should just be x64. Linux should appear as an OS restriction.
b = SourceSet(
set(['a', 'b']), set([SourceListCondition('x64', 'Chromium', 'linux')]))
b_stanza = b.GenerateGnStanza()
string.index(b_stanza, 'current_cpu == "x64"')
string.index(b_stanza, 'use_linux_config')
# arm should just be arm.
c = SourceSet(
set(['a', 'b']), set([SourceListCondition('arm', 'Chromium', 'linux')]))
c_stanza = c.GenerateGnStanza()
string.index(c_stanza, 'current_cpu == "arm"')
# arm-neon should be arm and flip the arm_neon switch.
d = SourceSet(
set(['a', 'b']),
set([SourceListCondition('arm-neon', 'Chromium', 'linux')]))
d_stanza = d.GenerateGnStanza()
string.index(d_stanza, 'current_cpu == "arm" && arm_use_neon')
# Multiple conditions
e = SourceSet(
set(['a', 'b']),
set([
SourceListCondition('arm', 'Chrome', 'win'),
SourceListCondition('x64', 'Chromium', 'linux')
]))
e_stanza = e.GenerateGnStanza()
string.index(e_stanza, ('is_win && current_cpu == "arm"'
' && ffmpeg_branding == "Chrome"'))
string.index(e_stanza, ('use_linux_config && current_cpu == "x64"'
' && ffmpeg_branding == "Chromium"'))
def testComplexSourceListConditions(self):
# Create 2 sets with intersecting source 'a', but setup such that 'a'
# is only valid for combinations (x86 && windows) || (x64 && linux). The
# generated gn stanza should then not allow for inclusion of the 'a' file
# for combinations like x86 && linux.
a = SourceSet(set(['a']), set([SourceListCondition('x86', 'c', 'win')]))
b = SourceSet(set(['a']), set([SourceListCondition('x64', 'c', 'linux')]))
disjoint_sets = gg.CreatePairwiseDisjointSets([a, b])
# This condition is bad because x86 && linux would pass. Admittedly a very
# fragile way to test this, but evaulating gn stanzas is hard, and it at
# least serves to document the motivation for the associated changes to
# our generate_gn.py
bad_condition = ('(current_cpu == "x86" || current_cpu == "x64")'
' && (ffmpeg_branding == "c")'
' && (is_win || is_linux || is_chromeos)')
# Expect only a single set since the two original sets have the same source
# list.
self.assertEqual(1, len(disjoint_sets))
stanza = disjoint_sets[0].GenerateGnStanza()
self.assertEqual(string.find(stanza, bad_condition), -1)
def assertEqualSourceSets(self, expected, actual):
assert all(isinstance(a, SourceSet) for a in expected)
assert all(isinstance(a, SourceSet) for a in actual)
def SourceSetToString(source_set):
sources = [str(e) for e in source_set.sources]
conditions = [str(e) for e in source_set.conditions]
sources_str = ','.join(sources)
conditions_str = '\n\t'.join(conditions)
return ' sources:%s\n cs:\t%s' % (sources_str, conditions_str)
missing_elements = expected.difference(actual)
extra_elements = actual.difference(expected)
msg = ''
if len(missing_elements):
msg += 'Missing expected elements:\n'
for e in missing_elements:
msg += SourceSetToString(e) + '\n'
if len(extra_elements):
msg += 'Found extra elements:\n'
for e in extra_elements:
msg += SourceSetToString(e) + '\n'
self.assertTrue(expected == actual, msg=msg)
def testCreatePairwiseDisjointSets_Pair(self):
a = SourceSet(
set(['common', 'intel']),
set([SourceListCondition('ia32', 'Chromium', 'win')]))
b = SourceSet(
set(['common', 'intel', 'chrome']),
set([SourceListCondition('ia32', 'Chrome', 'win')]))
expected = set()
expected.add(
SourceSet(
set(['common', 'intel']),
set([
SourceListCondition('ia32', 'Chromium', 'win'),
SourceListCondition('ia32', 'Chrome', 'win')
])))
expected.add(
SourceSet(
set(['chrome']), set([SourceListCondition('ia32', 'Chrome',
'win')])))
source_sets = gg.CreatePairwiseDisjointSets([a, b])
self.assertEqualSourceSets(expected, set(source_sets))
def testCreatePairwiseDisjointSets_Triplet(self):
a = SourceSet(
set(['common', 'intel']),
set([SourceListCondition('ia32', 'Chromium', 'win')]))
b = SourceSet(
set(['common', 'intel', 'chrome']),
set([SourceListCondition('x64', 'Chrome', 'win')]))
c = SourceSet(
set(['common', 'arm']),
set([SourceListCondition('arm', 'Chromium', 'win')]))
expected = set()
expected.add(
SourceSet(
set(['common']),
set([
SourceListCondition('ia32', 'Chromium', 'win'),
SourceListCondition('x64', 'Chrome', 'win'),
SourceListCondition('arm', 'Chromium', 'win')
])))
expected.add(
SourceSet(
set(['intel']),
set([
SourceListCondition('ia32', 'Chromium', 'win'),
SourceListCondition('x64', 'Chrome', 'win')
])))
expected.add(
SourceSet(
set(['chrome']), set([SourceListCondition('x64', 'Chrome',
'win')])))
expected.add(
SourceSet(
set(['arm']), set([SourceListCondition('arm', 'Chromium', 'win')])))
source_sets = gg.CreatePairwiseDisjointSets([a, b, c])
self.assertEqualSourceSets(expected, set(source_sets))
def testCreatePairwiseDisjointSets_Multiple(self):
a = SourceSet(
set(['common', 'intel']),
set([SourceListCondition('ia32', 'Chromium', 'linux')]))
b = SourceSet(
set(['common', 'intel', 'chrome']),
set([SourceListCondition('ia32', 'Chrome', 'linux')]))
c = SourceSet(
set(['common', 'intel']),
set([SourceListCondition('x64', 'Chromium', 'linux')]))
d = SourceSet(
set(['common', 'intel', 'chrome']),
set([SourceListCondition('x64', 'Chrome', 'linux')]))
e = SourceSet(
set(['common', 'arm']),
set([SourceListCondition('arm', 'Chromium', 'linux')]))
f = SourceSet(
set(['common', 'arm-neon', 'chrome', 'chromeos']),
set([SourceListCondition('arm-neon', 'ChromeOS', 'linux')]))
expected = set()
expected.add(
SourceSet(
set(['common']),
set([
SourceListCondition('ia32', 'Chromium', 'linux'),
SourceListCondition('ia32', 'Chrome', 'linux'),
SourceListCondition('x64', 'Chromium', 'linux'),
SourceListCondition('x64', 'Chrome', 'linux'),
SourceListCondition('arm', 'Chromium', 'linux'),
SourceListCondition('arm-neon', 'ChromeOS', 'linux')
])))
expected.add(
SourceSet(
set(['intel']),
set([
SourceListCondition('ia32', 'Chromium', 'linux'),
SourceListCondition('ia32', 'Chrome', 'linux'),
SourceListCondition('x64', 'Chromium', 'linux'),
SourceListCondition('x64', 'Chrome', 'linux')
])))
expected.add(
SourceSet(
set(['arm']), set([SourceListCondition('arm', 'Chromium',
'linux')])))
expected.add(
SourceSet(
set(['chrome']),
set([
SourceListCondition('ia32', 'Chrome', 'linux'),
SourceListCondition('x64', 'Chrome', 'linux'),
SourceListCondition('arm-neon', 'ChromeOS', 'linux')
])))
expected.add(
SourceSet(
set(['arm-neon', 'chromeos']),
set([SourceListCondition('arm-neon', 'ChromeOS', 'linux')])))
source_sets = gg.CreatePairwiseDisjointSets([a, b, c, d, e, f])
self.assertEqualSourceSets(expected, set(source_sets))
def testReduceConditions(self):
# Set conditions span all of the supported architectures for linux.
a = SourceSet(
set(['foo.c']),
set([
SourceListCondition('ia32', 'Chromium', 'linux'),
SourceListCondition('x64', 'Chromium', 'linux'),
SourceListCondition('arm', 'Chromium', 'linux'),
SourceListCondition('arm64', 'Chromium', 'linux'),
SourceListCondition('arm-neon', 'Chromium', 'linux'),
SourceListCondition('mipsel', 'Chromium', 'linux'),
SourceListCondition('mips64el', 'Chromium', 'linux'),
]))
gg.ReduceConditionalLogic(a)
# Conditions should reduce to a single condition with wild-card for arch.
expected = set([SourceListCondition('*', 'Chromium', 'linux')])
self.assertEqual(expected, a.conditions)
# Set conditions span all of the supported architectures for windows.
b = SourceSet(
set(['foo.c']),
set([
SourceListCondition('ia32', 'Chromium', 'win'),
SourceListCondition('x64', 'Chromium', 'win'),
SourceListCondition('arm64', 'Chromium', 'win'),
]))
gg.ReduceConditionalLogic(b)
# Conditions should reduce to a single condition with wild-card for
expected = set([SourceListCondition('*', 'Chromium', 'win')])
self.assertEqual(expected, b.conditions)
# Set conditions span all supported architectures and brandings for windows.
b = SourceSet(
set(['foo.c']),
set([
SourceListCondition('ia32', 'Chromium', 'win'),
SourceListCondition('x64', 'Chromium', 'win'),
SourceListCondition('arm64', 'Chromium', 'win'),
SourceListCondition('ia32', 'Chrome', 'win'),
SourceListCondition('x64', 'Chrome', 'win'),
SourceListCondition('arm64', 'Chrome', 'win'),
]))
gg.ReduceConditionalLogic(b)
expected = set([SourceListCondition('*', '*', 'win')])
self.assertEqual(expected, b.conditions)
# Set conditions span all supported platforms.
c = SourceSet(
set(['foo.c']),
set([
SourceListCondition('x64', 'Chromium', 'win'),
SourceListCondition('x64', 'Chromium', 'mac'),
SourceListCondition('x64', 'Chromium', 'linux'),
SourceListCondition('x64', 'Chromium', 'android'),
]))
gg.ReduceConditionalLogic(c)
expected = set([SourceListCondition('x64', 'Chromium', '*')])
self.assertEqual(expected, c.conditions)
# Spans all architectures for Chromium, but also all targets for ia32 & win.
d = SourceSet(
set(['foo.c']),
set([
SourceListCondition('arm64', 'Chromium', 'win'),
SourceListCondition('x64', 'Chromium', 'win'),
SourceListCondition('ia32', 'Chromium', 'win'),
SourceListCondition('ia32', 'Chrome', 'win'),
]))
gg.ReduceConditionalLogic(d)
expected = set([
SourceListCondition('*', 'Chromium', 'win'),
SourceListCondition('ia32', '*', 'win'),
])
self.assertEqual(expected, d.conditions)
def testReduceConditions_fullSpan(self):
# Build SourceSet with conditions spanning every combination of attributes.
ss = SourceSet(set(['foo.c']), set())
for arch in gg.SUPPORT_MATRIX[gg.Attr.ARCHITECTURE]:
for target in gg.SUPPORT_MATRIX[gg.Attr.TARGET]:
for platform in gg.SUPPORT_MATRIX[gg.Attr.PLATFORM]:
ss.conditions.add(SourceListCondition(arch, target, platform))
gg.ReduceConditionalLogic(ss)
expected = set([SourceListCondition('*', '*', '*')])
self.assertEqual(expected, ss.conditions)
def testGenerateStanzaWildCard(self):
a = SourceSet(
set(['foo.c']), set([SourceListCondition('x64', 'Chromium', '*')]))
stanza = a.GenerateGnStanza()
string.index(stanza, '== "x64"')
string.index(stanza, 'ffmpeg_branding == "Chromium"')
# OS is wild-card, so it should not be mentioned in the stanza.
self.assertEqual(-1, string.find(stanza, 'OS =='))
def testFixObjectBasenameCollisions(self):
# Use callback to capture executed renames.
observed_renames = set()
def do_rename_cb(old_path, new_path, content):
observed_renames.add((old_path, new_path))
# Verify basic rename case - same basename in different directories.
a = SourceSet(set(['foo.c']), set([SourceListCondition('*', '*', '*')]))
b = SourceSet(
set([path.join('a','foo.c'), path.join('b', 'foo.c')]),
set([SourceListCondition('*', '*', '*')]))
expected_renames = set([(path.join('a', 'foo.c'),
path.join('a', 'autorename_a_foo.c')),
(path.join('b', 'foo.c'),
path.join('b', 'autorename_b_foo.c'))])
gg.FixObjectBasenameCollisions([a, b], [], do_rename_cb, log_renames=False)
self.assertEqual(expected_renames, observed_renames)
# Verify renames file extensions in same and different directory.
observed_renames = set()
a = SourceSet(set(['foo.c']), set([SourceListCondition('*', '*', '*')]))
b = SourceSet(set(['foo.asm']), set([SourceListCondition('*', '*', '*')]))
c = SourceSet(set([path.join('a', 'foo.S'), path.join('b', 'foo.asm')]),
set([SourceListCondition('*', '*', '*')]))
expected_renames = set([('foo.asm', 'autorename_foo.asm'),
(path.join('a', 'foo.S'),
path.join('a', 'autorename_a_foo.S')),
(path.join('b', 'foo.asm'),
path.join('b', 'autorename_b_foo.asm'))])
gg.FixObjectBasenameCollisions(
[a, b, c], [], do_rename_cb, log_renames=False)
self.assertEqual(expected_renames, observed_renames)
if __name__ == '__main__':
unittest.main()