314 | 314 |
if pattern_prefixes == [u'->']:
|
315 | 315 |
return Pragma(line_num=self.line_num, filename=self.filename, lines=pattern[0][1])
|
316 | 316 |
elif pattern_prefixes[-1] in [u'= ', u'? ']:
|
317 | |
# TODO: several things
|
318 | |
|
319 | 317 |
if state.current_functionality is None:
|
320 | 318 |
raise FalderalSyntaxError(
|
321 | 319 |
("line %d: " % self.line_num) +
|
|
325 | 323 |
input_block = make_block_from_pattern(TestInput, pattern, u'+ ') or state.last_test_input_block
|
326 | 324 |
|
327 | 325 |
if pattern_prefixes[-1] == u'= ':
|
328 | |
expectation_block = make_block_from_pattern(ExpectedResult, pattern, u'= ')
|
|
326 |
expectation_block = make_block_from_pattern(Block, pattern, u'= ')
|
329 | 327 |
expectation = OutputOutcome(expectation_block.text())
|
330 | 328 |
elif pattern_prefixes[-1] == u'? ':
|
331 | |
expectation_block = make_block_from_pattern(ExpectedError, pattern, u'? ')
|
|
329 |
expectation_block = make_block_from_pattern(Block, pattern, u'? ')
|
332 | 330 |
expectation = ErrorOutcome(expectation_block.text())
|
333 | 331 |
else:
|
334 | 332 |
raise NotImplementedError
|
|
379 | 377 |
pass
|
380 | 378 |
|
381 | 379 |
|
382 | |
class ExpectedError(Block):
|
383 | |
pass
|
384 | |
|
385 | |
|
386 | |
class ExpectedResult(Block):
|
387 | |
pass
|
388 | |
|
389 | |
|
390 | 380 |
class InterveningText(Block):
|
391 | 381 |
pass
|
392 | 382 |
|
|
429 | 419 |
line = line.rstrip(u'\r\n')
|
430 | 420 |
self.lines.append(line)
|
431 | 421 |
|
432 | |
def parse_lines_to_tests(self, functionalities):
|
433 | |
r"""Parse the lines of the Document into Tests.
|
434 | |
|
435 | |
| >>> d = Document()
|
436 | |
| >>> d.append(u'This is a test file.')
|
437 | |
| >>> d.append(u' -> This is a pragma.')
|
438 | |
| >>> d.append(u'')
|
439 | |
| >>> d.append(u" | This is some test input.\n")
|
440 | |
| >>> d.append(u" | It extends over two lines.")
|
441 | |
| >>> d.append(u' ? Expected Error')
|
442 | |
| >>> d.append(u'')
|
443 | |
| >>> d.append(u' | Test with input')
|
444 | |
| >>> d.append(u' + input-for-test')
|
445 | |
| >>> d.append(u' = Expected result on output')
|
446 | |
| >>> d.parse_lines_to_blocks()
|
447 | |
| >>> [block.lines for block in d.blocks if isinstance(block, InterveningText)]
|
448 | |
| [[u'This is a test file.']]
|
449 | |
| >>> [b.__class__.__name__ for b in d.blocks]
|
450 | |
| ['InterveningText', 'Pragma', 'TestBody', 'ExpectedError',
|
451 | |
| 'TestBody', 'TestInput', 'ExpectedResult']
|
452 | |
| >>> [b.line_num for b in d.blocks]
|
453 | |
| [1, 2, 4, 4, 8, 8, 8]
|
|
422 |
def parse_lines_to_blocks(self):
|
|
423 |
r"""Parse the lines of the Document into Blocks.
|
|
424 |
|
|
425 |
>>> d = Document()
|
|
426 |
>>> d.append(u'This is a test file.')
|
|
427 |
>>> d.append(u' -> This is a pragma.')
|
|
428 |
>>> d.append(u'')
|
|
429 |
>>> d.append(u" | This is some test input.\n")
|
|
430 |
>>> d.append(u" | It extends over two lines.")
|
|
431 |
>>> d.append(u' ? Expected Error')
|
|
432 |
>>> d.append(u'')
|
|
433 |
>>> d.append(u' | Test with input')
|
|
434 |
>>> d.append(u' + input-for-test')
|
|
435 |
>>> d.append(u' = Expected result on output')
|
|
436 |
>>> blocks = d.parse_lines_to_blocks()
|
|
437 |
>>> [block.lines for block in blocks if isinstance(block, InterveningText)]
|
|
438 |
[[u'This is a test file.'], [u''], [u'']]
|
|
439 |
>>> [b.__class__.__name__ for b in blocks]
|
|
440 |
['InterveningText', 'Block', 'InterveningText', 'Block', 'InterveningText', 'Block']
|
|
441 |
>>> [b.line_num for b in blocks]
|
|
442 |
[1, 2, 3, 4, 7, 8]
|
|
443 |
|
|
444 |
"""
|
|
445 |
indent = None
|
|
446 |
blocks = []
|
|
447 |
line_num = 1
|
|
448 |
block = None
|
|
449 |
|
|
450 |
for line in self.lines:
|
|
451 |
# make sure we get a Block to start with
|
|
452 |
if indent is None:
|
|
453 |
if line.startswith(u' '):
|
|
454 |
indent = u''
|
|
455 |
else:
|
|
456 |
indent = u' '
|
|
457 |
|
|
458 |
if indent == u'':
|
|
459 |
if line.startswith(u' '):
|
|
460 |
indent = u' '
|
|
461 |
if block is not None:
|
|
462 |
blocks.append(block)
|
|
463 |
block = Block(
|
|
464 |
line_num=line_num,
|
|
465 |
filename=self.filename
|
|
466 |
)
|
|
467 |
elif indent == u' ':
|
|
468 |
if not line.startswith(u' '):
|
|
469 |
indent = u''
|
|
470 |
if block is not None:
|
|
471 |
blocks.append(block)
|
|
472 |
block = InterveningText(
|
|
473 |
line_num=line_num,
|
|
474 |
filename=self.filename
|
|
475 |
)
|
|
476 |
|
|
477 |
line = line[len(indent):]
|
|
478 |
|
|
479 |
block.append(line)
|
|
480 |
line_num += 1
|
|
481 |
|
|
482 |
if block is not None:
|
|
483 |
blocks.append(block)
|
|
484 |
|
|
485 |
return blocks
|
|
486 |
|
|
487 |
def parse_blocks_to_tests(self, blocks, functionalities):
|
|
488 |
state = ParseState()
|
|
489 |
state.functionalities = functionalities
|
|
490 |
|
|
491 |
tests = []
|
|
492 |
for block in blocks:
|
|
493 |
if isinstance(block, InterveningText):
|
|
494 |
if block.is_empty():
|
|
495 |
continue
|
|
496 |
state.last_desc_block = block
|
|
497 |
continue
|
|
498 |
|
|
499 |
test_or_pragma = block.classify(state)
|
|
500 |
|
|
501 |
if test_or_pragma is None:
|
|
502 |
# It was just some indented text which doesn't concern us
|
|
503 |
pass
|
|
504 |
elif isinstance(test_or_pragma, Test):
|
|
505 |
tests.append(test_or_pragma)
|
|
506 |
elif isinstance(test_or_pragma, Pragma):
|
|
507 |
test_or_pragma.execute(state)
|
|
508 |
else:
|
|
509 |
raise NotImplementedError('need Pragma or Test, not ' + repr(test_or_pragma))
|
|
510 |
|
|
511 |
return tests
|
|
512 |
|
|
513 |
def extract_tests(self, functionalities):
|
|
514 |
r"""Extract all Tests from this Document.
|
454 | 515 |
|
455 | 516 |
>>> functionalities = {}
|
456 | 517 |
>>> d = Document()
|
457 | 518 |
>>> d.append(u"This is a text file.")
|
458 | 519 |
>>> d.append(u'It contains NO tests.')
|
459 | |
>>> d.parse_lines_to_tests(functionalities)
|
|
520 |
>>> d.extract_tests(functionalities)
|
460 | 521 |
[]
|
461 | 522 |
|
462 | 523 |
>>> d = Document()
|
|
465 | 526 |
>>> d.append(u'')
|
466 | 527 |
>>> d.append(u" | This is some test body.")
|
467 | 528 |
>>> d.append(u' = Expected result')
|
468 | |
>>> d.parse_lines_to_tests(functionalities)
|
|
529 |
>>> d.extract_tests(functionalities)
|
469 | 530 |
[Test(body_block=TestBody(line_num=4), input_block=None,
|
470 | 531 |
expectation=OutputOutcome(u'Expected result'),
|
471 | 532 |
functionality=Functionality(u'Parse Thing'),
|
|
491 | 552 |
>>> d.append(u'')
|
492 | 553 |
>>> d.append(u" | Thing")
|
493 | 554 |
>>> d.append(u' ? Oops')
|
494 | |
>>> tests = d.parse_lines_to_tests(functionalities)
|
|
555 |
>>> tests = d.extract_tests(functionalities)
|
495 | 556 |
>>> [t.body for t in tests]
|
496 | 557 |
[u'This is some test body.\nIt extends over two lines.',
|
497 | 558 |
u'Test with input', u'Test with input', u'Thing']
|
|
514 | 575 |
>>> d = Document()
|
515 | 576 |
>>> d.append(u" | This is some test body.")
|
516 | 577 |
>>> d.append(u' = Expected')
|
517 | |
>>> d.parse_lines_to_tests({})
|
|
578 |
>>> d.extract_tests({})
|
518 | 579 |
Traceback (most recent call last):
|
519 | 580 |
...
|
520 | 581 |
FalderalSyntaxError: line 1: functionality under test not specified
|
|
522 | 583 |
>>> d = Document()
|
523 | 584 |
>>> d.append(u'This is a test file.')
|
524 | 585 |
>>> d.append(u' ? Expected Error')
|
525 | |
>>> d.parse_lines_to_tests({})
|
|
586 |
>>> d.extract_tests({})
|
526 | 587 |
Traceback (most recent call last):
|
527 | 588 |
...
|
528 | 589 |
FalderalSyntaxError: line 2: expectation must be preceded by test body or test input
|
|
530 | 591 |
>>> d = Document()
|
531 | 592 |
>>> d.append(u' -> Hello, this is pragma')
|
532 | 593 |
>>> d.append(u' = Expected')
|
533 | |
>>> d.parse_lines_to_tests({})
|
|
594 |
>>> d.extract_tests({})
|
534 | 595 |
Traceback (most recent call last):
|
535 | 596 |
...
|
536 | 597 |
FalderalSyntaxError: line 1: incorrectly formatted test block
|
|
538 | 599 |
>>> d = Document()
|
539 | 600 |
>>> d.append(u' | This is test')
|
540 | 601 |
>>> d.append(u'This is text')
|
541 | |
>>> d.parse_lines_to_tests({})
|
|
602 |
>>> d.extract_tests({})
|
542 | 603 |
Traceback (most recent call last):
|
543 | 604 |
...
|
544 | 605 |
FalderalSyntaxError: line 1: test body must be followed by expectation or test input
|
|
546 | 607 |
>>> d = Document()
|
547 | 608 |
>>> d.append(u' -> Hello, this is pragma')
|
548 | 609 |
>>> d.append(u' + Input to where exactly?')
|
549 | |
>>> d.parse_lines_to_tests({})
|
|
610 |
>>> d.extract_tests({})
|
550 | 611 |
Traceback (most recent call last):
|
551 | 612 |
...
|
552 | 613 |
FalderalSyntaxError: line 1: incorrectly formatted test block
|
|
558 | 619 |
>>> d.append(u'')
|
559 | 620 |
>>> d.append(u' -> Functionality "Parse Stuff" is')
|
560 | 621 |
>>> d.append(u' -> implemented by shell command "pxxxy"')
|
561 | |
>>> tests = d.parse_lines_to_tests(funs)
|
|
622 |
>>> tests = d.extract_tests(funs)
|
562 | 623 |
>>> len(funs.keys())
|
563 | 624 |
1
|
564 | 625 |
>>> [i for i in funs["Parse Stuff"].implementations]
|
565 | 626 |
[ShellImplementation(u'parse'), ShellImplementation(u'pxxxy')]
|
566 | 627 |
|
567 | 628 |
"""
|
568 | |
indent = None
|
569 | |
blocks = []
|
570 | |
line_num = 1
|
571 | |
block = None
|
572 | |
|
573 | |
for line in self.lines:
|
574 | |
# make sure we get a Block to start with
|
575 | |
if indent is None:
|
576 | |
if line.startswith(u' '):
|
577 | |
indent = u''
|
578 | |
else:
|
579 | |
indent = u' '
|
580 | |
|
581 | |
if indent == u'':
|
582 | |
if line.startswith(u' '):
|
583 | |
indent = u' '
|
584 | |
if block is not None:
|
585 | |
blocks.append(block)
|
586 | |
block = Block(
|
587 | |
line_num=line_num,
|
588 | |
filename=self.filename
|
589 | |
)
|
590 | |
elif indent == u' ':
|
591 | |
if not line.startswith(u' '):
|
592 | |
indent = u''
|
593 | |
if block is not None:
|
594 | |
blocks.append(block)
|
595 | |
block = InterveningText(
|
596 | |
line_num=line_num,
|
597 | |
filename=self.filename
|
598 | |
)
|
599 | |
|
600 | |
line = line[len(indent):]
|
601 | |
|
602 | |
block.append(line)
|
603 | |
line_num += 1
|
604 | |
|
605 | |
if block is not None:
|
606 | |
blocks.append(block)
|
607 | |
|
608 | |
# now process Blocks into Tests
|
609 | |
|
610 | |
state = ParseState()
|
611 | |
state.functionalities = functionalities
|
612 | |
|
613 | |
tests = []
|
614 | |
for block in blocks:
|
615 | |
if isinstance(block, InterveningText):
|
616 | |
if block.is_empty():
|
617 | |
continue
|
618 | |
state.last_desc_block = block
|
619 | |
continue
|
620 | |
|
621 | |
test_or_pragma = block.classify(state)
|
622 | |
|
623 | |
if test_or_pragma is None:
|
624 | |
# It was just some indented text which doesn't concern us
|
625 | |
pass
|
626 | |
elif isinstance(test_or_pragma, Test):
|
627 | |
tests.append(test_or_pragma)
|
628 | |
elif isinstance(test_or_pragma, Pragma):
|
629 | |
test_or_pragma.execute(state)
|
630 | |
else:
|
631 | |
raise NotImplementedError('need Pragma or Test, not ' + repr(test_or_pragma))
|
632 | |
|
|
629 |
blocks = self.parse_lines_to_blocks()
|
|
630 |
tests = self.parse_blocks_to_tests(blocks, functionalities)
|
633 | 631 |
return tests
|
634 | 632 |
|
635 | 633 |
|