build/pymake/tests/formattingtests.py

branch
TOR_BUG_9701
changeset 3
141e0f1194b1
equal deleted inserted replaced
-1:000000000000 0:368c7196c692
1 # This file contains test code for the formatting of parsed statements back to
2 # make file "source." It essentially verifies to to_source() functions
3 # scattered across the tree.
4
5 import glob
6 import logging
7 import os.path
8 import unittest
9
10 from pymake.data import Expansion
11 from pymake.data import StringExpansion
12 from pymake.functions import BasenameFunction
13 from pymake.functions import SubstitutionRef
14 from pymake.functions import VariableRef
15 from pymake.functions import WordlistFunction
16 from pymake.parserdata import Include
17 from pymake.parserdata import SetVariable
18 from pymake.parser import parsestring
19 from pymake.parser import SyntaxError
20
21 class TestBase(unittest.TestCase):
22 pass
23
24 class VariableRefTest(TestBase):
25 def test_string_name(self):
26 e = StringExpansion('foo', None)
27 v = VariableRef(None, e)
28
29 self.assertEqual(v.to_source(), '$(foo)')
30
31 def test_special_variable(self):
32 e = StringExpansion('<', None)
33 v = VariableRef(None, e)
34
35 self.assertEqual(v.to_source(), '$<')
36
37 def test_expansion_simple(self):
38 e = Expansion()
39 e.appendstr('foo')
40 e.appendstr('bar')
41
42 v = VariableRef(None, e)
43
44 self.assertEqual(v.to_source(), '$(foobar)')
45
46 class StandardFunctionTest(TestBase):
47 def test_basename(self):
48 e1 = StringExpansion('foo', None)
49 v = VariableRef(None, e1)
50 e2 = Expansion(None)
51 e2.appendfunc(v)
52
53 b = BasenameFunction(None)
54 b.append(e2)
55
56 self.assertEqual(b.to_source(), '$(basename $(foo))')
57
58 def test_wordlist(self):
59 e1 = StringExpansion('foo', None)
60 e2 = StringExpansion('bar ', None)
61 e3 = StringExpansion(' baz', None)
62
63 w = WordlistFunction(None)
64 w.append(e1)
65 w.append(e2)
66 w.append(e3)
67
68 self.assertEqual(w.to_source(), '$(wordlist foo,bar , baz)')
69
70 def test_curly_brackets(self):
71 e1 = Expansion(None)
72 e1.appendstr('foo')
73
74 e2 = Expansion(None)
75 e2.appendstr('foo ( bar')
76
77 f = WordlistFunction(None)
78 f.append(e1)
79 f.append(e2)
80
81 self.assertEqual(f.to_source(), '${wordlist foo,foo ( bar}')
82
83 class StringExpansionTest(TestBase):
84 def test_simple(self):
85 e = StringExpansion('foobar', None)
86 self.assertEqual(e.to_source(), 'foobar')
87
88 e = StringExpansion('$var', None)
89 self.assertEqual(e.to_source(), '$var')
90
91 def test_escaping(self):
92 e = StringExpansion('$var', None)
93 self.assertEqual(e.to_source(escape_variables=True), '$$var')
94
95 e = StringExpansion('this is # not a comment', None)
96 self.assertEqual(e.to_source(escape_comments=True),
97 'this is \# not a comment')
98
99 def test_empty(self):
100 e = StringExpansion('', None)
101 self.assertEqual(e.to_source(), '')
102
103 e = StringExpansion(' ', None)
104 self.assertEqual(e.to_source(), ' ')
105
106 class ExpansionTest(TestBase):
107 def test_single_string(self):
108 e = Expansion()
109 e.appendstr('foo')
110
111 self.assertEqual(e.to_source(), 'foo')
112
113 def test_multiple_strings(self):
114 e = Expansion()
115 e.appendstr('hello')
116 e.appendstr('world')
117
118 self.assertEqual(e.to_source(), 'helloworld')
119
120 def test_string_escape(self):
121 e = Expansion()
122 e.appendstr('$var')
123 self.assertEqual(e.to_source(), '$var')
124 self.assertEqual(e.to_source(escape_variables=True), '$$var')
125
126 e = Expansion()
127 e.appendstr('foo')
128 e.appendstr(' $bar')
129 self.assertEqual(e.to_source(escape_variables=True), 'foo $$bar')
130
131 class SubstitutionRefTest(TestBase):
132 def test_simple(self):
133 name = StringExpansion('foo', None)
134 c = StringExpansion('%.c', None)
135 o = StringExpansion('%.o', None)
136 s = SubstitutionRef(None, name, c, o)
137
138 self.assertEqual(s.to_source(), '$(foo:%.c=%.o)')
139
140 class SetVariableTest(TestBase):
141 def test_simple(self):
142 v = SetVariable(StringExpansion('foo', None), '=', 'bar', None, None)
143 self.assertEqual(v.to_source(), 'foo = bar')
144
145 def test_multiline(self):
146 s = 'hello\nworld'
147 foo = StringExpansion('FOO', None)
148
149 v = SetVariable(foo, '=', s, None, None)
150
151 self.assertEqual(v.to_source(), 'define FOO\nhello\nworld\nendef')
152
153 def test_multiline_immediate(self):
154 source = 'define FOO :=\nhello\nworld\nendef'
155
156 statements = parsestring(source, 'foo.mk')
157 self.assertEqual(statements.to_source(), source)
158
159 def test_target_specific(self):
160 foo = StringExpansion('FOO', None)
161 bar = StringExpansion('BAR', None)
162
163 v = SetVariable(foo, '+=', 'value', None, bar)
164
165 self.assertEqual(v.to_source(), 'BAR: FOO += value')
166
167 class IncludeTest(TestBase):
168 def test_include(self):
169 e = StringExpansion('rules.mk', None)
170 i = Include(e, True, False)
171 self.assertEqual(i.to_source(), 'include rules.mk')
172
173 i = Include(e, False, False)
174 self.assertEqual(i.to_source(), '-include rules.mk')
175
176 class IfdefTest(TestBase):
177 def test_simple(self):
178 source = 'ifdef FOO\nbar := $(value)\nendif'
179
180 statements = parsestring(source, 'foo.mk')
181 self.assertEqual(statements[0].to_source(), source)
182
183 def test_nested(self):
184 source = 'ifdef FOO\nifdef BAR\nhello = world\nendif\nendif'
185
186 statements = parsestring(source, 'foo.mk')
187 self.assertEqual(statements[0].to_source(), source)
188
189 def test_negation(self):
190 source = 'ifndef FOO\nbar += value\nendif'
191
192 statements = parsestring(source, 'foo.mk')
193 self.assertEqual(statements[0].to_source(), source)
194
195 class IfeqTest(TestBase):
196 def test_simple(self):
197 source = 'ifeq ($(foo),bar)\nhello = $(world)\nendif'
198
199 statements = parsestring(source, 'foo.mk')
200 self.assertEqual(statements[0].to_source(), source)
201
202 def test_negation(self):
203 source = 'ifneq (foo,bar)\nhello = world\nendif'
204
205 statements = parsestring(source, 'foo.mk')
206 self.assertEqual(statements.to_source(), source)
207
208 class ConditionBlocksTest(TestBase):
209 def test_mixed_conditions(self):
210 source = 'ifdef FOO\nifeq ($(FOO),bar)\nvar += $(value)\nendif\nendif'
211
212 statements = parsestring(source, 'foo.mk')
213 self.assertEqual(statements.to_source(), source)
214
215 def test_extra_statements(self):
216 source = 'ifdef FOO\nF := 1\nifdef BAR\nB += 1\nendif\nC = 1\nendif'
217
218 statements = parsestring(source, 'foo.mk')
219 self.assertEqual(statements.to_source(), source)
220
221 def test_whitespace_preservation(self):
222 source = "ifeq ' x' 'x '\n$(error stripping)\nendif"
223
224 statements = parsestring(source, 'foo.mk')
225 self.assertEqual(statements.to_source(), source)
226
227 source = 'ifneq (x , x)\n$(error stripping)\nendif'
228 statements = parsestring(source, 'foo.mk')
229 self.assertEqual(statements.to_source(),
230 'ifneq (x,x)\n$(error stripping)\nendif')
231
232 class MakefileCorupusTest(TestBase):
233 """Runs the make files from the pymake corpus through the formatter.
234
235 All the above tests are child's play compared to this.
236 """
237
238 # Our reformatting isn't perfect. We ignore files with known failures until
239 # we make them work.
240 # TODO Address these formatting corner cases.
241 _IGNORE_FILES = [
242 # We are thrown off by backslashes at end of lines.
243 'comment-parsing.mk',
244 'escape-chars.mk',
245 'include-notfound.mk',
246 ]
247
248 def _get_test_files(self):
249 ourdir = os.path.dirname(os.path.abspath(__file__))
250
251 for makefile in glob.glob(os.path.join(ourdir, '*.mk')):
252 if os.path.basename(makefile) in self._IGNORE_FILES:
253 continue
254
255 source = None
256 with open(makefile, 'rU') as fh:
257 source = fh.read()
258
259 try:
260 yield (makefile, source, parsestring(source, makefile))
261 except SyntaxError:
262 continue
263
264 def test_reparse_consistency(self):
265 for filename, source, statements in self._get_test_files():
266 reformatted = statements.to_source()
267
268 # We should be able to parse the reformatted source fine.
269 new_statements = parsestring(reformatted, filename)
270
271 # If we do the formatting again, the representation shouldn't
272 # change. i.e. the only lossy change should be the original
273 # (whitespace and some semantics aren't preserved).
274 reformatted_again = new_statements.to_source()
275 self.assertEqual(reformatted, reformatted_again,
276 '%s has lossless reformat.' % filename)
277
278 self.assertEqual(len(statements), len(new_statements))
279
280 for i in xrange(0, len(statements)):
281 original = statements[i]
282 formatted = new_statements[i]
283
284 self.assertEqual(original, formatted, '%s %d: %s != %s' % (filename,
285 i, original, formatted))
286
287 if __name__ == '__main__':
288 logging.basicConfig(level=logging.DEBUG)
289 unittest.main()

mercurial