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