def test_duplicate_definition_of_label_is_not_compilable(self): with self.assertRaises(DuplicateLabelError): self.program([ RETURN_TRUE, DEF('label'), Noop, RETURN_TRUE, DEF('label'), Noop ])
def test_string_as_call_symbol(self): prog = self.program([ '+1', '+2', RETURN_TRUE, DEF('+2'), '+1', '+1', RETURN_TRUE, DEF('+1'), Add1, RETURN_TRUE ]) self.assertEqual(3, prog.run(0))
def test_branch_on_no(self): prog = self.program([ IF(IsOdd), Add1, Add1, ELSE, 'add1', ENDIF, RETURN_TRUE, DEF('add1'), Add1, RETURN_TRUE ]) self.assertEqual(5, prog.run(4)) self.assertEqual(5, prog.run(3))
def test_macro_return_no(self): prog = self.program([ IF('odd?'), Add1, ENDIF, RETURN_TRUE, DEF('odd?'), IF(IsOdd), RETURN_TRUE, ELSE, RETURN_FALSE, ENDIF ]) self.assertEqual(2, prog.run(2)) self.assertEqual(4, prog.run(4))
def test_backward_reference_is_not_compilable(self): with self.assertRaises(BackwardReferenceError): self.program([RETURN_TRUE, DEF('label'), Noop, 'label'])
def test_label_definition_within_label_def_is_not_compilable(self): with self.assertRaises(FallOverOnDefineError): self.program( [RETURN_TRUE, DEF('label'), DEF('label2'), RETURN_TRUE])
def test_incomplete_before_label_is_not_compilable(self): with self.assertRaises(FallOverOnDefineError): self.program([Noop, DEF('label'), Noop, RETURN_TRUE])
class Test_Program(unittest.TestCase): PROGRAM_CLASS = m.Program def program(self, program_spec): return self.PROGRAM_CLASS(program_spec) def test_instruction_sequence(self): prog = self.program([Add1, Div2, RETURN_TRUE]) self.assertEqual(2, prog.run(3)) def test_duplicate_definition_of_label_is_not_compilable(self): with self.assertRaises(DuplicateLabelError): self.program([ RETURN_TRUE, DEF('label'), Noop, RETURN_TRUE, DEF('label'), Noop ]) def test_incomplete_program_is_not_compilable(self): with self.assertRaises(UndefinedLabelError): self.program(['label', RETURN_TRUE]) def test_incomplete_before_label_is_not_compilable(self): with self.assertRaises(FallOverOnDefineError): self.program([Noop, DEF('label'), Noop, RETURN_TRUE]) def test_label_definition_within_label_def_is_not_compilable(self): with self.assertRaises(FallOverOnDefineError): self.program( [RETURN_TRUE, DEF('label'), DEF('label2'), RETURN_TRUE]) def test_program_without_closing_return_is_not_compilable(self): with self.assertRaises(UnclosedProgramError): self.program([Noop]) def test_backward_reference_is_not_compilable(self): with self.assertRaises(BackwardReferenceError): self.program([RETURN_TRUE, DEF('label'), Noop, 'label']) def test_branch_on_yes(self): prog = self.program([ IF(IsOdd), Add1, ELSE, 'add2', ENDIF, RETURN_TRUE, DEF('add2'), Add1, Add1, RETURN_TRUE ]) self.assertEqual(4, prog.run(3)) self.assertEqual(6, prog.run(4)) def test_branch_on_no(self): prog = self.program([ IF(IsOdd), Add1, Add1, ELSE, 'add1', ENDIF, RETURN_TRUE, DEF('add1'), Add1, RETURN_TRUE ]) self.assertEqual(5, prog.run(4)) self.assertEqual(5, prog.run(3)) def test_string_as_call_symbol(self): prog = self.program([ '+1', '+2', RETURN_TRUE, DEF('+2'), '+1', '+1', RETURN_TRUE, DEF('+1'), Add1, RETURN_TRUE ]) self.assertEqual(3, prog.run(0)) def test_compilation_with_missing_ENDIF_is_not_possible(self): with self.assertRaises(MissingEndIfError): self.program([IF(IsOdd), RETURN_TRUE]) def test_compilation_with_multiple_ELSE_is_not_possible(self): with self.assertRaises(MultipleElseError): self.program([IF(IsOdd), ELSE, ELSE, ENDIF, RETURN_TRUE]) def test_IF(self): prog = self.program([IF(IsOdd), Add1, ENDIF, Add1, RETURN_TRUE]) self.assertEqual(1, prog.run(0)) self.assertEqual(3, prog.run(1)) self.assertEqual(3, prog.run(2)) def test_IF_NOT(self): prog = self.program([ IF_NOT(Eq('value')), Const('IF_NOT'), IF_NOT(Eq('value')), Const('IF_NOT'), # here we have the bug: this path is merged to here, # but outside this path is *ignored*, # its ELSE path is merged ENDIF, ENDIF, Add('.'), RETURN_TRUE ]) self.assertEqual('value.', prog.run('value')) self.assertEqual('IF_NOT.', prog.run('?')) def test_ELSE(self): prog = self.program([IF(IsOdd), ELSE, Add1, ENDIF, Add1, RETURN_TRUE]) self.assertEqual(2, prog.run(0)) self.assertEqual(2, prog.run(1)) self.assertEqual(4, prog.run(2)) def test_IF_ELSE(self): prog = self.program( [IF(IsOdd), Add1, ELSE, Add1, Add1, ENDIF, Add1, RETURN_TRUE]) self.assertEqual(3, prog.run(0)) self.assertEqual(3, prog.run(1)) self.assertEqual(5, prog.run(2)) def test_IF_ELIF_ELSE(self): prog = self.program([ IF(Eq('value')), Const('IF'), ELIF(Eq('variant1')), Const('ELIF1'), ELIF(Eq('variant2')), Const('ELIF2'), ELSE, Const('ELSE'), ENDIF, Add('.'), RETURN_TRUE ]) self.assertEqual('IF.', prog.run('value')) self.assertEqual('ELIF1.', prog.run('variant1')) self.assertEqual('ELIF2.', prog.run('variant2')) self.assertEqual('ELSE.', prog.run('unknown')) def test_IF_ELIF_NOT_ELSE(self): prog = self.program([ IF(Eq('value')), Const('IF'), ELIF_NOT(Eq('variant')), # not variant Const('ELIF_NOT'), ELSE, # variant Const('ELSE'), ENDIF, Add('.'), RETURN_TRUE ]) self.assertEqual('IF.', prog.run('value')) self.assertEqual('ELIF_NOT.', prog.run('not_variant')) self.assertEqual('ELSE.', prog.run('variant')) def test_IF_NOT_ELSE(self): prog = self.program([ IF_NOT(Eq('value')), # not value Const('IF_NOT'), ELSE, # value Const('ELSE'), ENDIF, Add('.'), RETURN_TRUE ]) self.assertEqual('IF_NOT.', prog.run('unkown')) self.assertEqual('ELSE.', prog.run('value')) def test_compilation_with_ELIF_after_ELSE_is_not_possible(self): with self.assertRaises(ElIfAfterElseError): self.program([IF(IsOdd), ELSE, ELIF(IsOdd), ENDIF, RETURN_TRUE]) def test_embedded_IFs(self): prog = self.program([ IF(IsOdd), Add1, Div2, IF(IsOdd), Add1, ENDIF, ELSE, Add1, Add1, ENDIF, Div2, RETURN_TRUE ]) self.assertEqual(1, prog.run(0)) self.assertEqual(1, prog.run(1)) self.assertEqual(2, prog.run(2)) self.assertEqual(1, prog.run(3)) self.assertEqual(3, prog.run(4)) self.assertEqual(2, prog.run(5)) def test_macro_return_yes(self): prog = self.program([ IF('odd?'), Add1, ENDIF, RETURN_TRUE, DEF('odd?'), IF(IsOdd), RETURN_TRUE, ELSE, RETURN_FALSE, ENDIF ]) self.assertEqual(2, prog.run(1)) self.assertEqual(4, prog.run(3)) def test_macro_return_no(self): prog = self.program([ IF('odd?'), Add1, ENDIF, RETURN_TRUE, DEF('odd?'), IF(IsOdd), RETURN_TRUE, ELSE, RETURN_FALSE, ENDIF ]) self.assertEqual(2, prog.run(2)) self.assertEqual(4, prog.run(4)) # used in the next 2 tests complex_prog_spec = [ IF('even?'), RETURN_TRUE, ELSE, Add1, ENDIF, RETURN_TRUE, DEF('even?'), IF(IsOdd), RETURN_FALSE, ELSE, RETURN_TRUE, ENDIF, ] def test_macro_return(self): prog = self.program(self.complex_prog_spec) self.assertEqual(2, prog.run(1)) self.assertEqual(2, prog.run(2)) self.assertEqual(4, prog.run(3)) self.assertEqual(4, prog.run(4)) def test_instruction_index(self): prog = self.program(self.complex_prog_spec) indices = [i.index for i in prog.instructions] self.assertEqual(range(len(prog.instructions)), indices) def test_joining_into_a_closed_path_reopens_it(self): with self.assertRaises(UnclosedProgramError): self.program([ IF(IsOdd), RETURN_TRUE, ENDIF, ]) def test_sub_programs(self): prog = self.program([ Add1, m.RETURN_TRUE, m.DEF('x1'), m.RETURN_TRUE, m.DEF('x2'), m.RETURN_TRUE, m.DEF('x3'), Add1, Add1, m.RETURN_TRUE, ]) sub_programs = iter(prog.sub_programs()) sub_program = sub_programs.next() self.assertEqual(None, sub_program[0]) self.assertEqual(2, len(sub_program[1])) # Add1, RETURN sub_program = sub_programs.next() self.assertEqual('x1', sub_program[0]) self.assertEqual(1, len(sub_program[1])) # RETURN sub_program = sub_programs.next() self.assertEqual('x2', sub_program[0]) self.assertEqual(1, len(sub_program[1])) # RETURN sub_program = sub_programs.next() self.assertEqual('x3', sub_program[0]) self.assertEqual(3, len(sub_program[1])) # Add1, Add1, RETURN with self.assertRaises(StopIteration): sub_programs.next() def program_for_visiting_with_all_features(self): return self.program([ 'x', m.RETURN_TRUE, m.DEF('x'), m.IF(IsOdd), Add1, m.ENDIF, m.RETURN_TRUE ]) def check_visitor(self, visitor): prog = self.program_for_visiting_with_all_features() prog.accept(visitor) def test_remembering_visitor_is_an_accepted_visitor(self): self.check_visitor(RememberingVisitor()) def test_visit(self): prog = self.program_for_visiting_with_all_features() remembering_visitor = RememberingVisitor() prog.accept(remembering_visitor) i = prog.instructions self.assertEqual([('subprogram', None), ('call', i[0]), ('return', i[1]), ('end', None), ('subprogram', 'x'), ('branch', i[2]), ('instruction', i[3]), ('return', i[4]), ('end', 'x')], remembering_visitor.calls)