2009-03-19 17:19:38 +03:00
|
|
|
import pymake.data, pymake.parser, pymake.parserdata, pymake.functions
|
|
|
|
import unittest
|
|
|
|
import logging
|
|
|
|
|
|
|
|
from cStringIO import StringIO
|
|
|
|
|
|
|
|
def multitest(cls):
|
|
|
|
for name in cls.testdata.iterkeys():
|
|
|
|
def m(self, name=name):
|
|
|
|
return self.runSingle(*self.testdata[name])
|
|
|
|
|
|
|
|
setattr(cls, 'test_%s' % name, m)
|
|
|
|
return cls
|
|
|
|
|
|
|
|
class TestBase(unittest.TestCase):
|
|
|
|
def assertEqual(self, a, b, msg=""):
|
|
|
|
"""Actually print the values which weren't equal, if things don't work out!"""
|
|
|
|
unittest.TestCase.assertEqual(self, a, b, "%s got %r expected %r" % (msg, a, b))
|
|
|
|
|
|
|
|
class DataTest(TestBase):
|
2009-03-26 23:24:51 +03:00
|
|
|
testdata = {
|
|
|
|
'oneline':
|
|
|
|
("He\tllo", "f", 1, 0,
|
|
|
|
((0, "f", 1, 0), (2, "f", 1, 2), (3, "f", 1, 4))),
|
|
|
|
'twoline':
|
|
|
|
("line1 \n\tl\tine2", "f", 1, 4,
|
|
|
|
((0, "f", 1, 4), (5, "f", 1, 9), (6, "f", 1, 10), (7, "f", 2, 0), (8, "f", 2, 4), (10, "f", 2, 8), (13, "f", 2, 11))),
|
|
|
|
}
|
2009-03-19 17:19:38 +03:00
|
|
|
|
2009-03-26 23:24:51 +03:00
|
|
|
def runSingle(self, data, filename, line, col, results):
|
2009-10-23 19:16:27 +04:00
|
|
|
d = pymake.parser.Data(data, 0, len(data), pymake.parserdata.Location(filename, line, col))
|
2009-03-26 23:24:51 +03:00
|
|
|
for pos, file, lineno, col in results:
|
|
|
|
loc = d.getloc(pos)
|
|
|
|
self.assertEqual(loc.path, file, "data file offset %i" % pos)
|
|
|
|
self.assertEqual(loc.line, lineno, "data line offset %i" % pos)
|
|
|
|
self.assertEqual(loc.column, col, "data col offset %i" % pos)
|
|
|
|
multitest(DataTest)
|
2009-03-19 17:19:38 +03:00
|
|
|
|
2009-10-23 19:16:27 +04:00
|
|
|
class LineEnumeratorTest(TestBase):
|
2009-03-19 17:19:38 +03:00
|
|
|
testdata = {
|
2009-10-23 19:16:27 +04:00
|
|
|
'simple': (
|
|
|
|
'Hello, world', [
|
|
|
|
('Hello, world', 1),
|
|
|
|
]
|
|
|
|
),
|
|
|
|
'multi': (
|
|
|
|
'Hello\nhappy \n\nworld\n', [
|
|
|
|
('Hello', 1),
|
|
|
|
('happy ', 2),
|
|
|
|
('', 3),
|
|
|
|
('world', 4),
|
|
|
|
('', 5),
|
|
|
|
]
|
|
|
|
),
|
|
|
|
'continuation': (
|
|
|
|
'Hello, \\\n world\nJellybeans!', [
|
|
|
|
('Hello, \\\n world', 1),
|
|
|
|
('Jellybeans!', 3),
|
|
|
|
]
|
|
|
|
),
|
|
|
|
'multislash': (
|
|
|
|
'Hello, \\\\\n world', [
|
|
|
|
('Hello, \\\\', 1),
|
|
|
|
(' world', 2),
|
|
|
|
]
|
|
|
|
)
|
2009-03-19 17:19:38 +03:00
|
|
|
}
|
|
|
|
|
2009-10-23 19:16:27 +04:00
|
|
|
def runSingle(self, s, lines):
|
|
|
|
gotlines = [(d.s[d.lstart:d.lend], d.loc.line) for d in pymake.parser.enumeratelines(s, 'path')]
|
|
|
|
self.assertEqual(gotlines, lines)
|
|
|
|
|
|
|
|
multitest(LineEnumeratorTest)
|
2009-03-19 17:19:38 +03:00
|
|
|
|
|
|
|
class IterTest(TestBase):
|
|
|
|
testdata = {
|
|
|
|
'plaindata': (
|
|
|
|
pymake.parser.iterdata,
|
|
|
|
"plaindata # test\n",
|
|
|
|
"plaindata # test\n"
|
|
|
|
),
|
|
|
|
'makecomment': (
|
|
|
|
pymake.parser.itermakefilechars,
|
|
|
|
"VAR = val # comment",
|
|
|
|
"VAR = val "
|
|
|
|
),
|
|
|
|
'makeescapedcomment': (
|
|
|
|
pymake.parser.itermakefilechars,
|
2009-10-23 19:16:27 +04:00
|
|
|
"VAR = val \# escaped hash",
|
2009-03-19 17:19:38 +03:00
|
|
|
"VAR = val # escaped hash"
|
|
|
|
),
|
|
|
|
'makeescapedslash': (
|
|
|
|
pymake.parser.itermakefilechars,
|
2009-10-23 19:16:27 +04:00
|
|
|
"VAR = val\\\\",
|
2009-03-19 17:19:38 +03:00
|
|
|
"VAR = val\\\\",
|
|
|
|
),
|
|
|
|
'makecontinuation': (
|
|
|
|
pymake.parser.itermakefilechars,
|
|
|
|
"VAR = VAL \\\n continuation # comment \\\n continuation",
|
|
|
|
"VAR = VAL continuation "
|
|
|
|
),
|
|
|
|
'makecontinuation2': (
|
|
|
|
pymake.parser.itermakefilechars,
|
|
|
|
"VAR = VAL \\ \\\n continuation",
|
|
|
|
"VAR = VAL \\ continuation"
|
|
|
|
),
|
|
|
|
'makeawful': (
|
|
|
|
pymake.parser.itermakefilechars,
|
|
|
|
"VAR = VAL \\\\# comment\n",
|
|
|
|
"VAR = VAL \\"
|
|
|
|
),
|
|
|
|
'command': (
|
|
|
|
pymake.parser.itercommandchars,
|
2009-10-23 19:16:27 +04:00
|
|
|
"echo boo # comment",
|
2009-03-19 17:19:38 +03:00
|
|
|
"echo boo # comment",
|
|
|
|
),
|
|
|
|
'commandcomment': (
|
|
|
|
pymake.parser.itercommandchars,
|
2009-10-23 19:16:27 +04:00
|
|
|
"echo boo \# comment",
|
2009-03-19 17:19:38 +03:00
|
|
|
"echo boo \# comment",
|
|
|
|
),
|
|
|
|
'commandcontinue': (
|
|
|
|
pymake.parser.itercommandchars,
|
2009-10-23 19:16:27 +04:00
|
|
|
"echo boo # \\\n\t command 2",
|
2009-03-19 17:19:38 +03:00
|
|
|
"echo boo # \\\n command 2"
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
def runSingle(self, ifunc, idata, expected):
|
2009-10-23 19:16:27 +04:00
|
|
|
d = pymake.parser.Data.fromstring(idata, 'IterTest data')
|
2009-03-19 17:19:38 +03:00
|
|
|
|
2009-10-23 19:16:27 +04:00
|
|
|
it = pymake.parser._alltokens.finditer(d.s, 0, d.lend)
|
|
|
|
actual = ''.join( [c for c, t, o, oo in ifunc(d, 0, ('dummy-token',), it)] )
|
2009-03-19 17:19:38 +03:00
|
|
|
self.assertEqual(actual, expected)
|
|
|
|
|
2009-10-23 19:16:27 +04:00
|
|
|
if ifunc == pymake.parser.itermakefilechars:
|
|
|
|
print "testing %r" % expected
|
|
|
|
self.assertEqual(pymake.parser.flattenmakesyntax(d, 0), expected)
|
|
|
|
|
2009-03-19 17:19:38 +03:00
|
|
|
multitest(IterTest)
|
|
|
|
|
2009-10-23 19:16:27 +04:00
|
|
|
|
|
|
|
# 'define': (
|
|
|
|
# pymake.parser.iterdefinechars,
|
|
|
|
# "endef",
|
|
|
|
# ""
|
|
|
|
# ),
|
|
|
|
# 'definenesting': (
|
|
|
|
# pymake.parser.iterdefinechars,
|
|
|
|
# """define BAR # comment
|
|
|
|
#random text
|
|
|
|
#endef not what you think!
|
|
|
|
#endef # comment is ok\n""",
|
|
|
|
# """define BAR # comment
|
|
|
|
#random text
|
|
|
|
#endef not what you think!"""
|
|
|
|
# ),
|
|
|
|
# 'defineescaped': (
|
|
|
|
# pymake.parser.iterdefinechars,
|
|
|
|
# """value \\
|
|
|
|
#endef
|
|
|
|
#endef\n""",
|
|
|
|
# "value endef"
|
|
|
|
# ),
|
|
|
|
|
2009-03-19 17:19:38 +03:00
|
|
|
class MakeSyntaxTest(TestBase):
|
|
|
|
# (string, startat, stopat, stopoffset, expansion
|
|
|
|
testdata = {
|
|
|
|
'text': ('hello world', 0, (), None, ['hello world']),
|
|
|
|
'singlechar': ('hello $W', 0, (), None,
|
|
|
|
['hello ',
|
|
|
|
{'type': 'VariableRef',
|
|
|
|
'.vname': ['W']}
|
|
|
|
]),
|
|
|
|
'stopat': ('hello: world', 0, (':', '='), 6, ['hello']),
|
|
|
|
'funccall': ('h $(flavor FOO)', 0, (), None,
|
|
|
|
['h ',
|
|
|
|
{'type': 'FlavorFunction',
|
|
|
|
'[0]': ['FOO']}
|
|
|
|
]),
|
|
|
|
'escapedollar': ('hello$$world', 0, (), None, ['hello$world']),
|
|
|
|
'varref': ('echo $(VAR)', 0, (), None,
|
|
|
|
['echo ',
|
|
|
|
{'type': 'VariableRef',
|
|
|
|
'.vname': ['VAR']}
|
|
|
|
]),
|
|
|
|
'dynamicvarname': ('echo $($(VARNAME):.c=.o)', 0, (':',), None,
|
|
|
|
['echo ',
|
|
|
|
{'type': 'SubstitutionRef',
|
|
|
|
'.vname': [{'type': 'VariableRef',
|
|
|
|
'.vname': ['VARNAME']}
|
|
|
|
],
|
|
|
|
'.substfrom': ['.c'],
|
|
|
|
'.substto': ['.o']}
|
|
|
|
]),
|
|
|
|
'substref': (' $(VAR:VAL) := $(VAL)', 0, (':=', '+=', '=', ':'), 15,
|
|
|
|
[' ',
|
|
|
|
{'type': 'VariableRef',
|
|
|
|
'.vname': ['VAR:VAL']},
|
|
|
|
' ']),
|
|
|
|
'vadsubstref': (' $(VAR:VAL) = $(VAL)', 15, (), None,
|
|
|
|
[{'type': 'VariableRef',
|
|
|
|
'.vname': ['VAL']},
|
|
|
|
]),
|
|
|
|
}
|
|
|
|
|
|
|
|
def compareRecursive(self, actual, expected, path):
|
|
|
|
self.assertEqual(len(actual), len(expected),
|
2009-10-23 19:16:27 +04:00
|
|
|
"compareRecursive: %s %r" % (path, actual))
|
2009-03-19 17:19:38 +03:00
|
|
|
for i in xrange(0, len(actual)):
|
|
|
|
ipath = path + [i]
|
|
|
|
|
|
|
|
a, isfunc = actual[i]
|
|
|
|
e = expected[i]
|
|
|
|
if isinstance(e, str):
|
|
|
|
self.assertEqual(a, e, "compareRecursive: %s" % (ipath,))
|
|
|
|
else:
|
|
|
|
self.assertEqual(type(a), getattr(pymake.functions, e['type']),
|
|
|
|
"compareRecursive: %s" % (ipath,))
|
|
|
|
for k, v in e.iteritems():
|
|
|
|
if k == 'type':
|
|
|
|
pass
|
|
|
|
elif k[0] == '[':
|
|
|
|
item = int(k[1:-1])
|
|
|
|
proppath = ipath + [item]
|
|
|
|
self.compareRecursive(a[item], v, proppath)
|
|
|
|
elif k[0] == '.':
|
|
|
|
item = k[1:]
|
|
|
|
proppath = ipath + [item]
|
|
|
|
self.compareRecursive(getattr(a, item), v, proppath)
|
|
|
|
else:
|
|
|
|
raise Exception("Unexpected property at %s: %s" % (ipath, k))
|
|
|
|
|
|
|
|
def runSingle(self, s, startat, stopat, stopoffset, expansion):
|
|
|
|
d = pymake.parser.Data.fromstring(s, pymake.parserdata.Location('testdata', 1, 0))
|
|
|
|
|
|
|
|
a, t, offset = pymake.parser.parsemakesyntax(d, startat, stopat, pymake.parser.itermakefilechars)
|
|
|
|
self.compareRecursive(a, expansion, [])
|
|
|
|
self.assertEqual(offset, stopoffset)
|
|
|
|
|
|
|
|
multitest(MakeSyntaxTest)
|
|
|
|
|
|
|
|
class VariableTest(TestBase):
|
|
|
|
testdata = """
|
|
|
|
VAR = value
|
|
|
|
VARNAME = TESTVAR
|
|
|
|
$(VARNAME) = testvalue
|
|
|
|
$(VARNAME:VAR=VAL) = moretesting
|
|
|
|
IMM := $(VARNAME) # this is a comment
|
|
|
|
MULTIVAR = val1 \\
|
|
|
|
val2
|
|
|
|
VARNAME = newname
|
|
|
|
"""
|
|
|
|
expected = {'VAR': 'value',
|
|
|
|
'VARNAME': 'newname',
|
|
|
|
'TESTVAR': 'testvalue',
|
|
|
|
'TESTVAL': 'moretesting',
|
|
|
|
'IMM': 'TESTVAR ',
|
|
|
|
'MULTIVAR': 'val1 val2',
|
|
|
|
'UNDEF': None}
|
|
|
|
|
|
|
|
def runTest(self):
|
2009-10-23 19:16:27 +04:00
|
|
|
stmts = pymake.parser.parsestring(self.testdata, 'VariableTest')
|
2009-03-19 17:19:38 +03:00
|
|
|
|
|
|
|
m = pymake.data.Makefile()
|
|
|
|
stmts.execute(m)
|
|
|
|
for k, v in self.expected.iteritems():
|
|
|
|
flavor, source, val = m.variables.get(k)
|
|
|
|
if val is None:
|
|
|
|
self.assertEqual(val, v, 'variable named %s' % k)
|
|
|
|
else:
|
|
|
|
self.assertEqual(val.resolvestr(m, m.variables), v, 'variable named %s' % k)
|
|
|
|
|
|
|
|
class SimpleRuleTest(TestBase):
|
|
|
|
testdata = """
|
|
|
|
VAR = value
|
|
|
|
TSPEC = dummy
|
|
|
|
all: TSPEC = myrule
|
|
|
|
all:: test test2 $(VAR)
|
|
|
|
echo "Hello, $(TSPEC)"
|
|
|
|
|
|
|
|
%.o: %.c
|
|
|
|
$(CC) -o $@ $<
|
|
|
|
"""
|
|
|
|
|
|
|
|
def runTest(self):
|
2009-10-23 19:16:27 +04:00
|
|
|
stmts = pymake.parser.parsestring(self.testdata, 'SimpleRuleTest')
|
2009-03-19 17:19:38 +03:00
|
|
|
|
|
|
|
m = pymake.data.Makefile()
|
|
|
|
stmts.execute(m)
|
|
|
|
self.assertEqual(m.defaulttarget, 'all', "Default target")
|
|
|
|
|
|
|
|
self.assertTrue(m.hastarget('all'), "Has 'all' target")
|
|
|
|
target = m.gettarget('all')
|
|
|
|
rules = target.rules
|
|
|
|
self.assertEqual(len(rules), 1, "Number of rules")
|
|
|
|
prereqs = rules[0].prerequisites
|
|
|
|
self.assertEqual(prereqs, ['test', 'test2', 'value'], "Prerequisites")
|
|
|
|
commands = rules[0].commands
|
|
|
|
self.assertEqual(len(commands), 1, "Number of commands")
|
|
|
|
expanded = commands[0].resolvestr(m, target.variables)
|
|
|
|
self.assertEqual(expanded, 'echo "Hello, myrule"')
|
|
|
|
|
|
|
|
irules = m.implicitrules
|
|
|
|
self.assertEqual(len(irules), 1, "Number of implicit rules")
|
|
|
|
|
|
|
|
irule = irules[0]
|
|
|
|
self.assertEqual(len(irule.targetpatterns), 1, "%.o target pattern count")
|
|
|
|
self.assertEqual(len(irule.prerequisites), 1, "%.o prerequisite count")
|
|
|
|
self.assertEqual(irule.targetpatterns[0].match('foo.o'), 'foo', "%.o stem")
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
unittest.main()
|