зеркало из https://github.com/mozilla/gecko-dev.git
290 строки
9.0 KiB
Python
290 строки
9.0 KiB
Python
|
# This file contains test code for the formatting of parsed statements back to
|
||
|
# make file "source." It essentially verifies to to_source() functions
|
||
|
# scattered across the tree.
|
||
|
|
||
|
import glob
|
||
|
import logging
|
||
|
import os.path
|
||
|
import unittest
|
||
|
|
||
|
from pymake.data import Expansion
|
||
|
from pymake.data import StringExpansion
|
||
|
from pymake.functions import BasenameFunction
|
||
|
from pymake.functions import SubstitutionRef
|
||
|
from pymake.functions import VariableRef
|
||
|
from pymake.functions import WordlistFunction
|
||
|
from pymake.parserdata import Include
|
||
|
from pymake.parserdata import SetVariable
|
||
|
from pymake.parser import parsestring
|
||
|
from pymake.parser import SyntaxError
|
||
|
|
||
|
class TestBase(unittest.TestCase):
|
||
|
pass
|
||
|
|
||
|
class VariableRefTest(TestBase):
|
||
|
def test_string_name(self):
|
||
|
e = StringExpansion('foo', None)
|
||
|
v = VariableRef(None, e)
|
||
|
|
||
|
self.assertEqual(v.to_source(), '$(foo)')
|
||
|
|
||
|
def test_special_variable(self):
|
||
|
e = StringExpansion('<', None)
|
||
|
v = VariableRef(None, e)
|
||
|
|
||
|
self.assertEqual(v.to_source(), '$<')
|
||
|
|
||
|
def test_expansion_simple(self):
|
||
|
e = Expansion()
|
||
|
e.appendstr('foo')
|
||
|
e.appendstr('bar')
|
||
|
|
||
|
v = VariableRef(None, e)
|
||
|
|
||
|
self.assertEqual(v.to_source(), '$(foobar)')
|
||
|
|
||
|
class StandardFunctionTest(TestBase):
|
||
|
def test_basename(self):
|
||
|
e1 = StringExpansion('foo', None)
|
||
|
v = VariableRef(None, e1)
|
||
|
e2 = Expansion(None)
|
||
|
e2.appendfunc(v)
|
||
|
|
||
|
b = BasenameFunction(None)
|
||
|
b.append(e2)
|
||
|
|
||
|
self.assertEqual(b.to_source(), '$(basename $(foo))')
|
||
|
|
||
|
def test_wordlist(self):
|
||
|
e1 = StringExpansion('foo', None)
|
||
|
e2 = StringExpansion('bar ', None)
|
||
|
e3 = StringExpansion(' baz', None)
|
||
|
|
||
|
w = WordlistFunction(None)
|
||
|
w.append(e1)
|
||
|
w.append(e2)
|
||
|
w.append(e3)
|
||
|
|
||
|
self.assertEqual(w.to_source(), '$(wordlist foo,bar , baz)')
|
||
|
|
||
|
def test_curly_brackets(self):
|
||
|
e1 = Expansion(None)
|
||
|
e1.appendstr('foo')
|
||
|
|
||
|
e2 = Expansion(None)
|
||
|
e2.appendstr('foo ( bar')
|
||
|
|
||
|
f = WordlistFunction(None)
|
||
|
f.append(e1)
|
||
|
f.append(e2)
|
||
|
|
||
|
self.assertEqual(f.to_source(), '${wordlist foo,foo ( bar}')
|
||
|
|
||
|
class StringExpansionTest(TestBase):
|
||
|
def test_simple(self):
|
||
|
e = StringExpansion('foobar', None)
|
||
|
self.assertEqual(e.to_source(), 'foobar')
|
||
|
|
||
|
e = StringExpansion('$var', None)
|
||
|
self.assertEqual(e.to_source(), '$var')
|
||
|
|
||
|
def test_escaping(self):
|
||
|
e = StringExpansion('$var', None)
|
||
|
self.assertEqual(e.to_source(escape_variables=True), '$$var')
|
||
|
|
||
|
e = StringExpansion('this is # not a comment', None)
|
||
|
self.assertEqual(e.to_source(escape_comments=True),
|
||
|
'this is \# not a comment')
|
||
|
|
||
|
def test_empty(self):
|
||
|
e = StringExpansion('', None)
|
||
|
self.assertEqual(e.to_source(), '')
|
||
|
|
||
|
e = StringExpansion(' ', None)
|
||
|
self.assertEqual(e.to_source(), ' ')
|
||
|
|
||
|
class ExpansionTest(TestBase):
|
||
|
def test_single_string(self):
|
||
|
e = Expansion()
|
||
|
e.appendstr('foo')
|
||
|
|
||
|
self.assertEqual(e.to_source(), 'foo')
|
||
|
|
||
|
def test_multiple_strings(self):
|
||
|
e = Expansion()
|
||
|
e.appendstr('hello')
|
||
|
e.appendstr('world')
|
||
|
|
||
|
self.assertEqual(e.to_source(), 'helloworld')
|
||
|
|
||
|
def test_string_escape(self):
|
||
|
e = Expansion()
|
||
|
e.appendstr('$var')
|
||
|
self.assertEqual(e.to_source(), '$var')
|
||
|
self.assertEqual(e.to_source(escape_variables=True), '$$var')
|
||
|
|
||
|
e = Expansion()
|
||
|
e.appendstr('foo')
|
||
|
e.appendstr(' $bar')
|
||
|
self.assertEqual(e.to_source(escape_variables=True), 'foo $$bar')
|
||
|
|
||
|
class SubstitutionRefTest(TestBase):
|
||
|
def test_simple(self):
|
||
|
name = StringExpansion('foo', None)
|
||
|
c = StringExpansion('%.c', None)
|
||
|
o = StringExpansion('%.o', None)
|
||
|
s = SubstitutionRef(None, name, c, o)
|
||
|
|
||
|
self.assertEqual(s.to_source(), '$(foo:%.c=%.o)')
|
||
|
|
||
|
class SetVariableTest(TestBase):
|
||
|
def test_simple(self):
|
||
|
v = SetVariable(StringExpansion('foo', None), '=', 'bar', None, None)
|
||
|
self.assertEqual(v.to_source(), 'foo = bar')
|
||
|
|
||
|
def test_multiline(self):
|
||
|
s = 'hello\nworld'
|
||
|
foo = StringExpansion('FOO', None)
|
||
|
|
||
|
v = SetVariable(foo, '=', s, None, None)
|
||
|
|
||
|
self.assertEqual(v.to_source(), 'define FOO\nhello\nworld\nendef')
|
||
|
|
||
|
def test_multiline_immediate(self):
|
||
|
source = 'define FOO :=\nhello\nworld\nendef'
|
||
|
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements.to_source(), source)
|
||
|
|
||
|
def test_target_specific(self):
|
||
|
foo = StringExpansion('FOO', None)
|
||
|
bar = StringExpansion('BAR', None)
|
||
|
|
||
|
v = SetVariable(foo, '+=', 'value', None, bar)
|
||
|
|
||
|
self.assertEqual(v.to_source(), 'BAR: FOO += value')
|
||
|
|
||
|
class IncludeTest(TestBase):
|
||
|
def test_include(self):
|
||
|
e = StringExpansion('rules.mk', None)
|
||
|
i = Include(e, True, False)
|
||
|
self.assertEqual(i.to_source(), 'include rules.mk')
|
||
|
|
||
|
i = Include(e, False, False)
|
||
|
self.assertEqual(i.to_source(), '-include rules.mk')
|
||
|
|
||
|
class IfdefTest(TestBase):
|
||
|
def test_simple(self):
|
||
|
source = 'ifdef FOO\nbar := $(value)\nendif'
|
||
|
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements[0].to_source(), source)
|
||
|
|
||
|
def test_nested(self):
|
||
|
source = 'ifdef FOO\nifdef BAR\nhello = world\nendif\nendif'
|
||
|
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements[0].to_source(), source)
|
||
|
|
||
|
def test_negation(self):
|
||
|
source = 'ifndef FOO\nbar += value\nendif'
|
||
|
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements[0].to_source(), source)
|
||
|
|
||
|
class IfeqTest(TestBase):
|
||
|
def test_simple(self):
|
||
|
source = 'ifeq ($(foo),bar)\nhello = $(world)\nendif'
|
||
|
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements[0].to_source(), source)
|
||
|
|
||
|
def test_negation(self):
|
||
|
source = 'ifneq (foo,bar)\nhello = world\nendif'
|
||
|
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements.to_source(), source)
|
||
|
|
||
|
class ConditionBlocksTest(TestBase):
|
||
|
def test_mixed_conditions(self):
|
||
|
source = 'ifdef FOO\nifeq ($(FOO),bar)\nvar += $(value)\nendif\nendif'
|
||
|
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements.to_source(), source)
|
||
|
|
||
|
def test_extra_statements(self):
|
||
|
source = 'ifdef FOO\nF := 1\nifdef BAR\nB += 1\nendif\nC = 1\nendif'
|
||
|
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements.to_source(), source)
|
||
|
|
||
|
def test_whitespace_preservation(self):
|
||
|
source = "ifeq ' x' 'x '\n$(error stripping)\nendif"
|
||
|
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements.to_source(), source)
|
||
|
|
||
|
source = 'ifneq (x , x)\n$(error stripping)\nendif'
|
||
|
statements = parsestring(source, 'foo.mk')
|
||
|
self.assertEqual(statements.to_source(),
|
||
|
'ifneq (x,x)\n$(error stripping)\nendif')
|
||
|
|
||
|
class MakefileCorupusTest(TestBase):
|
||
|
"""Runs the make files from the pymake corpus through the formatter.
|
||
|
|
||
|
All the above tests are child's play compared to this.
|
||
|
"""
|
||
|
|
||
|
# Our reformatting isn't perfect. We ignore files with known failures until
|
||
|
# we make them work.
|
||
|
# TODO Address these formatting corner cases.
|
||
|
_IGNORE_FILES = [
|
||
|
# We are thrown off by backslashes at end of lines.
|
||
|
'comment-parsing.mk',
|
||
|
'escape-chars.mk',
|
||
|
'include-notfound.mk',
|
||
|
]
|
||
|
|
||
|
def _get_test_files(self):
|
||
|
ourdir = os.path.dirname(os.path.abspath(__file__))
|
||
|
|
||
|
for makefile in glob.glob(os.path.join(ourdir, '*.mk')):
|
||
|
if os.path.basename(makefile) in self._IGNORE_FILES:
|
||
|
continue
|
||
|
|
||
|
source = None
|
||
|
with open(makefile, 'rU') as fh:
|
||
|
source = fh.read()
|
||
|
|
||
|
try:
|
||
|
yield (makefile, source, parsestring(source, makefile))
|
||
|
except SyntaxError:
|
||
|
continue
|
||
|
|
||
|
def test_reparse_consistency(self):
|
||
|
for filename, source, statements in self._get_test_files():
|
||
|
reformatted = statements.to_source()
|
||
|
|
||
|
# We should be able to parse the reformatted source fine.
|
||
|
new_statements = parsestring(reformatted, filename)
|
||
|
|
||
|
# If we do the formatting again, the representation shouldn't
|
||
|
# change. i.e. the only lossy change should be the original
|
||
|
# (whitespace and some semantics aren't preserved).
|
||
|
reformatted_again = new_statements.to_source()
|
||
|
self.assertEqual(reformatted, reformatted_again,
|
||
|
'%s has lossless reformat.' % filename)
|
||
|
|
||
|
self.assertEqual(len(statements), len(new_statements))
|
||
|
|
||
|
for i in xrange(0, len(statements)):
|
||
|
original = statements[i]
|
||
|
formatted = new_statements[i]
|
||
|
|
||
|
self.assertEqual(original, formatted, '%s %d: %s != %s' % (filename,
|
||
|
i, original, formatted))
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
logging.basicConfig(level=logging.DEBUG)
|
||
|
unittest.main()
|