1#!/usr/bin/env python3
2
3import ninja
4
5import os
6import unittest
7
8
9TEST_DIR = os.path.abspath(os.path.dirname(__file__))
10TEST_DATA_DIR = os.path.join(TEST_DIR, 'testdata')
11
12ENCODING = 'utf-8'
13
14
15class MockedParser(ninja.Parser):
16    def __init__(self, *args, **kwargs):
17        super(MockedParser, self).__init__(*args, **kwargs)
18        self.mocked_env = []
19
20    def _push_context(self, lexer, env):
21        super(MockedParser, self)._push_context(lexer, env)
22        self.mocked_env.append(env)
23
24
25class EvalStringTest(unittest.TestCase):
26    def test_empty(self):
27        s = ninja.EvalStringBuilder().getvalue()
28        self.assertFalse(s)
29        self.assertEqual('', ninja.eval_string(s, ninja.EvalEnv()))
30
31    def test_append_raw(self):
32        s = ninja.EvalStringBuilder().append_raw('a').getvalue()
33        self.assertTrue(s)
34        self.assertEqual('a', ninja.eval_string(s, ninja.EvalEnv()))
35
36    def test_append_raw_concat(self):
37        sb = ninja.EvalStringBuilder()
38        sb.append_raw('a')
39        sb.append_raw('b')
40        s = sb.getvalue()
41
42        self.assertTrue(s)
43        self.assertEqual('ab', ninja.eval_string(s, ninja.EvalEnv()))
44
45    def test_append_var(self):
46        s = ninja.EvalStringBuilder().append_var('key').getvalue()
47        self.assertTrue(s)
48
49    def test_var_eval(self):
50        env = ninja.EvalEnv()
51        env['key'] = ninja.EvalStringBuilder().append_raw('value').getvalue()
52
53        s = ninja.EvalStringBuilder().append_var('key').getvalue()
54        self.assertEqual('value', ninja.eval_string(s, env))
55
56    def test_var_concat_eval(self):
57        env = ninja.EvalEnv()
58        env['key1'] = ninja.EvalStringBuilder().append_raw('a').getvalue()
59        env['key2'] = ninja.EvalStringBuilder().append_raw('b').getvalue()
60
61        sb = ninja.EvalStringBuilder()
62        sb.append_var('key1')
63        sb.append_var('key2')
64        s = sb.getvalue()
65
66        self.assertEqual('ab', ninja.eval_string(s, env))
67
68    def test_var_repeat_eval(self):
69        env = ninja.EvalEnv()
70        env['key1'] = ninja.EvalStringBuilder().append_raw('a').getvalue()
71        env['key2'] = ninja.EvalStringBuilder().append_raw('b').getvalue()
72
73        sb = ninja.EvalStringBuilder()
74        sb.append_var('key1')
75        sb.append_var('key1')
76        sb.append_var('key2')
77        sb.append_var('key1')
78        sb.append_var('key2')
79        s = sb.getvalue()
80
81        self.assertEqual('aabab', ninja.eval_string(s, env))
82
83    def test_var_recursive_eval(self):
84        env = ninja.EvalEnv()
85        env['a'] = ninja.EvalStringBuilder().append_var('b').getvalue()
86        env['c'] = ninja.EvalStringBuilder().append_raw('d').getvalue()
87
88        sb = ninja.EvalStringBuilder()
89        sb.append_var('c')
90        sb.append_var('c')
91        env['b'] = sb.getvalue()
92
93        sb = ninja.EvalStringBuilder()
94        sb.append_var('a')
95        sb.append_var('a')
96        s = sb.getvalue()
97
98        self.assertEqual('dddd', ninja.eval_string(s, env))
99
100    def test_unknown_variable_eval_error(self):
101        s = ninja.EvalStringBuilder().append_var('a').getvalue()
102        self.assertEqual('', ninja.eval_string(s, ninja.EvalEnv()))
103
104    def test_circular_eval_eval_error(self):
105        env = ninja.EvalEnv()
106        env['a'] = ninja.EvalStringBuilder().append_var('b').getvalue()
107        env['b'] = ninja.EvalStringBuilder().append_var('b').getvalue()
108
109        s = ninja.EvalStringBuilder().append_var('a').getvalue()
110        with self.assertRaises(ninja.EvalCircularError):
111            ninja.eval_string(s, env)
112
113    def test_raw_and_var_eval(self):
114        env = ninja.EvalEnv()
115        env['b'] = ninja.EvalStringBuilder().append_raw('d').getvalue()
116
117        sb = ninja.EvalStringBuilder()
118        sb.append_raw('a')
119        sb.append_var('b')
120        sb.append_raw('c')
121        s = sb.getvalue()
122
123        self.assertEqual('adc', ninja.eval_string(s, env))
124
125
126class ParseErrorTest(unittest.TestCase):
127    def test_repr(self):
128        ex = ninja.ParseError('build.ninja', 5, 1)
129        self.assertEqual('ParseError: build.ninja:5:1', repr(ex))
130
131        ex = ninja.ParseError('build.ninja', 5, 1, 'invalid char')
132        self.assertEqual('ParseError: build.ninja:5:1: invalid char', repr(ex))
133
134
135class LexerTest(unittest.TestCase):
136    def test_peek_skip_comment(self):
137        lexer = ninja.Lexer(['#comment'])
138        tok = lexer.peek()
139        self.assertEqual(ninja.TK.EOF, tok.kind)
140
141    def test_peek_skip_comment_line(self):
142        lexer = ninja.Lexer(['#comment\n'])
143        tok = lexer.peek()
144        self.assertEqual(ninja.TK.NEWLINE, tok.kind)
145
146        lexer = ninja.Lexer([' #comment\n'])
147        tok = lexer.peek()
148        self.assertEqual(ninja.TK.NEWLINE, tok.kind)
149
150        lexer = ninja.Lexer(['\t#comment\n'])
151        tok = lexer.peek()
152        self.assertEqual(ninja.TK.NEWLINE, tok.kind)
153
154        lexer = ninja.Lexer([' \t#comment\n'])
155        tok = lexer.peek()
156        self.assertEqual(ninja.TK.NEWLINE, tok.kind)
157
158    def test_peek_skip_empty_line(self):
159        lexer = ninja.Lexer([' \n'])
160        tok = lexer.peek()
161        self.assertEqual(ninja.TK.NEWLINE, tok.kind)
162
163        lexer = ninja.Lexer(['\t\n'])
164        tok = lexer.peek()
165        self.assertEqual(ninja.TK.NEWLINE, tok.kind)
166
167        lexer = ninja.Lexer([' \t\n'])
168        tok = lexer.peek()
169        self.assertEqual(ninja.TK.NEWLINE, tok.kind)
170
171    def test_peek_newline(self):
172        lexer = ninja.Lexer(['\n'])
173        tok = lexer.peek()
174        self.assertEqual(ninja.TK.NEWLINE, tok.kind)
175
176    def test_peek_space(self):
177        lexer = ninja.Lexer([' a'])
178
179        tok = lexer.peek()
180        self.assertEqual(ninja.TK.SPACE, tok.kind)
181        tok = lexer.peek()  # Again
182        self.assertEqual(ninja.TK.SPACE, tok.kind)  # Not changed
183
184        tok = lexer.lex()  # Consume
185        self.assertEqual(ninja.TK.SPACE, tok.kind)  # Not changed
186        tok = lexer.lex()
187        self.assertEqual(ninja.TK.IDENT, tok.kind)
188
189    def test_lex_space(self):
190        lexer = ninja.Lexer([' '])
191        tok = lexer.lex()
192        self.assertEqual(ninja.TK.SPACE, tok.kind)
193
194        lexer = ninja.Lexer(['\t'])
195        tok = lexer.lex()
196        self.assertEqual(ninja.TK.SPACE, tok.kind)
197
198        lexer = ninja.Lexer(['\t '])
199        tok = lexer.lex()
200        self.assertEqual(ninja.TK.SPACE, tok.kind)
201
202        lexer = ninja.Lexer([' \t'])
203        tok = lexer.lex()
204        self.assertEqual(ninja.TK.SPACE, tok.kind)
205
206        lexer = ninja.Lexer([' a'])
207        tok = lexer.lex()
208        self.assertEqual(ninja.TK.SPACE, tok.kind)
209        tok = lexer.lex()
210        self.assertEqual(ninja.TK.IDENT, tok.kind)
211
212    def test_lex_skip_space(self):
213        lexer = ninja.Lexer(['a b'])
214
215        tok = lexer.lex()
216        self.assertEqual(ninja.TK.IDENT, tok.kind)
217        self.assertEqual(1, tok.line)
218        self.assertEqual(1, tok.column)
219
220        tok = lexer.lex()
221        self.assertEqual(ninja.TK.IDENT, tok.kind)
222        self.assertEqual(1, tok.line)
223        self.assertEqual(3, tok.column)
224
225    def test_lex_skip_space_newline_escape(self):
226        lexer = ninja.Lexer(['build $\n', ' \texample'])
227        tok = lexer.lex()
228        self.assertEqual(ninja.TK.IDENT, tok.kind)
229        self.assertEqual(1, tok.line)
230        self.assertEqual(1, tok.column)
231        tok = lexer.lex()
232        self.assertEqual(ninja.TK.IDENT, tok.kind)
233        self.assertEqual(2, tok.line)
234        self.assertEqual(3, tok.column)
235
236        lexer = ninja.Lexer(['build $\n', 'example'])
237        tok = lexer.lex()
238        self.assertEqual(ninja.TK.IDENT, tok.kind)
239        self.assertEqual(1, tok.line)
240        self.assertEqual(1, tok.column)
241        tok = lexer.lex()
242        self.assertEqual(ninja.TK.IDENT, tok.kind)
243        self.assertEqual(2, tok.line)
244        self.assertEqual(1, tok.column)
245
246        lexer = ninja.Lexer(['build a:$\n', 'example'])
247        tok = lexer.lex()
248        self.assertEqual(ninja.TK.IDENT, tok.kind)
249        self.assertEqual(1, tok.line)
250        self.assertEqual(1, tok.column)
251        tok = lexer.lex()
252        self.assertEqual(ninja.TK.IDENT, tok.kind)
253        self.assertEqual(1, tok.line)
254        self.assertEqual(7, tok.column)
255        tok = lexer.lex()
256        self.assertEqual(ninja.TK.COLON, tok.kind)
257        self.assertEqual(1, tok.line)
258        self.assertEqual(8, tok.column)
259        tok = lexer.lex()
260        self.assertEqual(ninja.TK.IDENT, tok.kind)
261        self.assertEqual(2, tok.line)
262        self.assertEqual(1, tok.column)
263
264        # Multiple newline escapes.
265        lexer = ninja.Lexer(['build $\n', '$\n', '$\n', 'example'])
266        tok = lexer.lex()
267        self.assertEqual(ninja.TK.IDENT, tok.kind)
268        self.assertEqual(1, tok.line)
269        self.assertEqual(1, tok.column)
270        tok = lexer.lex()
271        self.assertEqual(ninja.TK.IDENT, tok.kind)
272        self.assertEqual(4, tok.line)
273        self.assertEqual(1, tok.column)
274
275    def test_peek_space_after_newline(self):
276        lexer = ninja.Lexer(['a b\n', ' c'])
277
278        tok = lexer.lex()
279        self.assertEqual(ninja.TK.IDENT, tok.kind)
280        self.assertEqual(1, tok.line)
281        self.assertEqual(1, tok.column)
282
283        tok = lexer.lex()
284        self.assertEqual(ninja.TK.IDENT, tok.kind)
285        self.assertEqual(1, tok.line)
286        self.assertEqual(3, tok.column)
287
288        tok = lexer.lex()
289        self.assertEqual(ninja.TK.NEWLINE, tok.kind)
290        self.assertEqual(1, tok.line)
291        self.assertEqual(4, tok.column)
292
293        # A space token must be emitted.
294        tok = lexer.lex()
295        self.assertEqual(ninja.TK.SPACE, tok.kind)
296        self.assertEqual(2, tok.line)
297        self.assertEqual(1, tok.column)
298
299        tok = lexer.lex()
300        self.assertEqual(ninja.TK.IDENT, tok.kind)
301        self.assertEqual(2, tok.line)
302        self.assertEqual(2, tok.column)
303
304    def test_lex_ident(self):
305        lexer = ninja.Lexer(['abcdefghijklmnopqrstuvwxyz'])
306        tok = lexer.lex()
307        self.assertEqual(ninja.TK.IDENT, tok.kind)
308
309        lexer = ninja.Lexer(['ABCDEFGHIJKLMNOPQRSTUVWXYZ'])
310        tok = lexer.lex()
311        self.assertEqual(ninja.TK.IDENT, tok.kind)
312
313        lexer = ninja.Lexer(['0123456789'])
314        tok = lexer.lex()
315        self.assertEqual(ninja.TK.IDENT, tok.kind)
316
317        lexer = ninja.Lexer(['.'])
318        tok = lexer.lex()
319        self.assertEqual(ninja.TK.IDENT, tok.kind)
320
321        lexer = ninja.Lexer(['-'])
322        tok = lexer.lex()
323        self.assertEqual(ninja.TK.IDENT, tok.kind)
324
325        lexer = ninja.Lexer(['_'])
326        tok = lexer.lex()
327        self.assertEqual(ninja.TK.IDENT, tok.kind)
328
329    def test_lex_assign(self):
330        lexer = ninja.Lexer(['='])
331        tok = lexer.lex()
332        self.assertEqual(ninja.TK.ASSIGN, tok.kind)
333
334    def test_lex_colon(self):
335        lexer = ninja.Lexer([':'])
336        tok = lexer.lex()
337        self.assertEqual(ninja.TK.COLON, tok.kind)
338
339    def test_lex_pipe(self):
340        lexer = ninja.Lexer(['|'])
341        tok = lexer.lex()
342        self.assertEqual(ninja.TK.PIPE, tok.kind)
343
344    def test_lex_pipe2(self):
345        lexer = ninja.Lexer(['||'])
346        tok = lexer.lex()
347        self.assertEqual(ninja.TK.PIPE2, tok.kind)
348
349    def test_lex_non_trivial(self):
350        lexer = ninja.Lexer(['$name'])
351        with self.assertRaises(ninja.ParseError):
352            lexer.lex()
353        lexer = ninja.Lexer(['${name}'])
354        with self.assertRaises(ninja.ParseError):
355            lexer.lex()
356
357    def test_lex_match(self):
358        lexer = ninja.Lexer(['ident'])
359        with self.assertRaises(ninja.ParseError):
360            lexer.lex_match({ninja.TK.PIPE})
361
362    def test_lex_path_char(self):
363        lexer = ninja.Lexer(['path1 path2'])
364
365        tok = lexer.lex_path()
366        self.assertEqual(ninja.TK.PATH, tok.kind)
367        self.assertEqual(1, tok.line)
368        self.assertEqual(1, tok.column)
369        self.assertEqual(('t', 'path1'), tok.value)
370
371        tok = lexer.lex_path()
372        self.assertEqual(ninja.TK.PATH, tok.kind)
373        self.assertEqual(1, tok.line)
374        self.assertEqual(7, tok.column)
375        self.assertEqual(('t', 'path2'), tok.value)
376
377    def test_lex_str_char(self):
378        lexer = ninja.Lexer(['string with spaces'])
379        tok = lexer.lex_string()
380        self.assertEqual(ninja.TK.STRING, tok.kind)
381        self.assertEqual(1, tok.line)
382        self.assertEqual(1, tok.column)
383        self.assertEqual(('t', 'string with spaces'), tok.value)
384
385    def test_lex_path_escape_char(self):
386        for char in ' \t$:':
387            lexer = ninja.Lexer(['$' + char])
388            tok = lexer.lex_path()
389            self.assertEqual(ninja.TK.PATH, tok.kind)
390            self.assertEqual(1, tok.line)
391            self.assertEqual(1, tok.column)
392            self.assertEqual(('t', char), tok.value)
393
394    def test_lex_str_escape_char(self):
395        for char in ' \t$:':
396            lexer = ninja.Lexer(['$' + char])
397            tok = lexer.lex_string()
398            self.assertEqual(ninja.TK.STRING, tok.kind)
399            self.assertEqual(1, tok.line)
400            self.assertEqual(1, tok.column)
401            self.assertEqual(('t', char), tok.value)
402
403    def test_lex_path_escape_char_bad(self):
404        lexer = ninja.Lexer(['$'])
405        with self.assertRaises(ninja.ParseError):
406            lexer.lex_path()
407
408        lexer = ninja.Lexer(['$%'])
409        with self.assertRaises(ninja.ParseError):
410            lexer.lex_path()
411
412    def test_lex_str_escape_char_bad(self):
413        lexer = ninja.Lexer(['$'])
414        with self.assertRaises(ninja.ParseError):
415            lexer.lex_string()
416
417        lexer = ninja.Lexer(['$%'])
418        with self.assertRaises(ninja.ParseError):
419            lexer.lex_string()
420
421    def test_lex_path_end_char(self):
422        for char in ' \t\n:|':
423            lexer = ninja.Lexer(['path' + char])
424            tok = lexer.lex_path()
425            self.assertEqual(ninja.TK.PATH, tok.kind)
426            self.assertEqual(1, tok.line)
427            self.assertEqual(1, tok.column)
428            self.assertEqual(('t', 'path'), tok.value)
429
430    def test_lex_path_var(self):
431        lexer = ninja.Lexer(['$a'])
432        tok = lexer.lex_path()
433        self.assertIs(type(tok.value), ninja.EvalString)
434        self.assertEqual(('v', 'a',), tok.value)
435
436        lexer = ninja.Lexer(['${a}'])
437        tok = lexer.lex_path()
438        self.assertIs(type(tok.value), ninja.EvalString)
439        self.assertEqual(('v', 'a',), tok.value)
440
441        lexer = ninja.Lexer(['path/${a}'])
442        tok = lexer.lex_path()
443        self.assertIs(type(tok.value), ninja.EvalString)
444        self.assertEqual(('tv' ,'path/', 'a'), tok.value)
445
446    def test_lex_str_var(self):
447        lexer = ninja.Lexer(['$a'])
448        tok = lexer.lex_string()
449        self.assertIs(type(tok.value), ninja.EvalString)
450        self.assertEqual(('v', 'a'), tok.value)
451
452        lexer = ninja.Lexer(['${a}'])
453        tok = lexer.lex_string()
454        self.assertIs(type(tok.value), ninja.EvalString)
455        self.assertEqual(('v', 'a'), tok.value)
456
457        lexer = ninja.Lexer(['path/${a}'])
458        tok = lexer.lex_string()
459        self.assertIs(type(tok.value), ninja.EvalString)
460        self.assertEqual(('tv', 'path/', 'a'), tok.value)
461
462        lexer = ninja.Lexer(['path/${a} with space'])
463        tok = lexer.lex_string()
464        self.assertIs(type(tok.value), ninja.EvalString)
465        self.assertEqual(('tvt', 'path/', 'a', ' with space'), tok.value)
466
467
468class ParserTest(unittest.TestCase):
469    def test_init_base_dir(self):
470        parser = ninja.Parser()
471        self.assertEqual(os.getcwd(), parser._base_dir)
472        parser = ninja.Parser('/path/to/a/dir')
473        self.assertEqual('/path/to/a/dir', parser._base_dir)
474
475    def test_global_binding_stmt(self):
476        input_path = os.path.join(TEST_DATA_DIR, 'global_binding.ninja')
477
478        parser = MockedParser()
479        parser.parse(input_path, ENCODING)
480
481        env = parser.mocked_env[0]
482        self.assertEqual('1', env['a'])
483        self.assertEqual('2', env['b'])
484        self.assertEqual('3', env['c'])
485        self.assertEqual('1 2 3', env['d'])
486        self.assertEqual('mixed 1 and 2', env['e'])
487
488    def test_rule_stmt(self):
489        input_path = os.path.join(TEST_DATA_DIR, 'rule.ninja')
490
491        parser = ninja.Parser()
492        manifest = parser.parse(input_path, ENCODING)
493
494        self.assertEqual(2, len(manifest.rules))
495
496        rule_cc = manifest.rules[0]
497        self.assertEqual('cc', rule_cc.name)
498        self.assertEqual(1, len(rule_cc.bindings))
499
500        sb = ninja.EvalStringBuilder()
501        sb.append_raw('gcc -c -o ')
502        sb.append_var('outs')
503        sb.append_raw(' ')
504        sb.append_var('ins')
505
506        self.assertEqual(sb.getvalue(), rule_cc.bindings['command'])
507
508        rule_ld = manifest.rules[1]
509        self.assertEqual('ld', rule_ld.name)
510        self.assertEqual(1, len(rule_ld.bindings))
511
512        sb = ninja.EvalStringBuilder()
513        sb.append_raw('gcc -o ')
514        sb.append_var('outs')
515        sb.append_raw(' ')
516        sb.append_var('ins')
517
518        self.assertEqual(sb.getvalue(), rule_ld.bindings['command'])
519
520    def test_build_stmt(self):
521        input_path = os.path.join(TEST_DATA_DIR, 'build.ninja')
522
523        parser = ninja.Parser()
524        manifest = parser.parse(input_path, ENCODING)
525
526        self.assertEqual(1, len(manifest.builds))
527
528        build = manifest.builds[0]
529        self.assertEqual('explicit_out1', build.explicit_outs[0])
530        self.assertEqual('explicit_out2', build.explicit_outs[1])
531        self.assertEqual('implicit_out1', build.implicit_outs[0])
532        self.assertEqual('implicit_out2', build.implicit_outs[1])
533        self.assertEqual('phony', build.rule)
534        self.assertEqual('explicit_in1', build.explicit_ins[0])
535        self.assertEqual('explicit_in2', build.explicit_ins[1])
536        self.assertEqual('implicit_in1', build.implicit_ins[0])
537        self.assertEqual('implicit_in2', build.implicit_ins[1])
538        self.assertEqual('order_only1', build.prerequisites[0])
539        self.assertEqual('order_only2', build.prerequisites[1])
540
541        self.assertEqual(('t', '1',), build.bindings['a'])
542        self.assertEqual(('t', '2',), build.bindings['b'])
543
544    def test_default_stmt(self):
545        input_path = os.path.join(TEST_DATA_DIR, 'default.ninja')
546
547        parser = ninja.Parser()
548        manifest = parser.parse(input_path, ENCODING)
549
550        self.assertEqual(1, len(manifest.defaults))
551
552        default = manifest.defaults[0]
553        self.assertEqual('foo.o', default.outs[0])
554        self.assertEqual('bar.o', default.outs[1])
555
556    def test_pool_stmt(self):
557        input_path = os.path.join(TEST_DATA_DIR, 'pool.ninja')
558
559        parser = ninja.Parser()
560        manifest = parser.parse(input_path, ENCODING)
561
562        self.assertEqual(1, len(manifest.pools))
563
564        pool = manifest.pools[0]
565        self.assertEqual('example', pool.name)
566        self.assertEqual(('t', '5',), pool.bindings['depth'])
567
568    def test_subninja_stmt(self):
569        input_path = os.path.join(TEST_DATA_DIR, 'subninja.ninja')
570
571        parser = MockedParser(TEST_DATA_DIR)
572        manifest = parser.parse(input_path, ENCODING)
573
574        env = parser.mocked_env[0]
575        self.assertEqual('original', env['a'])
576        self.assertEqual(2, len(manifest.builds))
577
578        env = parser.mocked_env[1]
579        self.assertEqual('changed', env['a'])
580
581    def test_include_stmt(self):
582        input_path = os.path.join(TEST_DATA_DIR, 'include.ninja')
583
584        parser = MockedParser(TEST_DATA_DIR)
585        manifest = parser.parse(input_path, ENCODING)
586
587        env = parser.mocked_env[0]
588        self.assertEqual('changed', env['a'])
589        self.assertEqual(2, len(manifest.builds))
590
591
592class ParserTestWithBadInput(unittest.TestCase):
593    def test_unexpected_trivial_token(self):
594        input_path = os.path.join(TEST_DATA_DIR, 'bad_trivial.ninja')
595        with self.assertRaises(ninja.ParseError) as ctx:
596            MockedParser().parse(input_path, ENCODING)
597
598        self.assertEqual(input_path, ctx.exception.path)
599        self.assertEqual(1, ctx.exception.line)
600        self.assertEqual(1, ctx.exception.column)
601
602    def test_unexpected_non_trivial_token(self):
603        input_path = os.path.join(TEST_DATA_DIR, 'bad_non_trivial.ninja')
604        with self.assertRaises(ninja.ParseError) as ctx:
605            MockedParser().parse(input_path, ENCODING)
606
607        self.assertEqual(input_path, ctx.exception.path)
608        self.assertEqual(1, ctx.exception.line)
609        self.assertEqual(1, ctx.exception.column)
610
611    def test_bad_after_good(self):
612        input_path = os.path.join(TEST_DATA_DIR, 'bad_after_good.ninja')
613        with self.assertRaises(ninja.ParseError) as ctx:
614            MockedParser().parse(input_path, ENCODING)
615
616        self.assertEqual(input_path, ctx.exception.path)
617        self.assertEqual(4, ctx.exception.line)
618        self.assertEqual(1, ctx.exception.column)
619
620    def test_bad_path(self):
621        input_path = os.path.join(TEST_DATA_DIR, 'bad_path.ninja')
622        with self.assertRaises(ninja.ParseError) as ctx:
623            MockedParser().parse(input_path, ENCODING)
624
625        self.assertEqual(input_path, ctx.exception.path)
626        self.assertEqual(1, ctx.exception.line)
627        self.assertEqual(9, ctx.exception.column)
628
629
630if __name__ == '__main__':
631    unittest.main()
632