def test_it_does_an_unconditional_jump(self): vm = VM() vm.instructions = [Label('loop'), noop, noop] vm.pc = 2 Ujmp('loop').execute(vm) self.assertEqual(vm.pc, 1)
def test_it_retrieves_the_value_from_the_given_address(self): vm = VM() vm.memory[1000] = 5 vm.vstack.push(1000) Retrieve().execute(vm) self.assertEqual(len(vm.vstack), 1) self.assertEqual(vm.vstack.top(), 5)
def test_it_executes_each_instruction_one_by_one_until_an_end_instruction_is_reached( self): vm = VM() vm.instructions = [Push(3), Dup(), Mul(), End(), Dup()] vm.run() self.assertEqual(len(vm.vstack), 1) self.assertEqual(vm.vstack.top(), 9)
def test_it_jumps_if_zero(self): vm = VM() vm.instructions = [Label('loop'), noop, noop] vm.vstack.push(0) vm.pc = 2 Zjmp('loop').execute(vm) self.assertEqual(len(vm.vstack), 0) self.assertEqual(vm.pc, 1)
def test_it_calls_a_subroutine(self): vm = VM() vm.instructions = [noop, Label('f'), noop, noop, noop] vm.pc = 4 Call('f').execute(vm) self.assertEqual(len(vm.cstack), 1) self.assertEqual(vm.cstack.top(), 4) self.assertEqual(vm.pc, 2)
def test_it_does_not_jump_if_non_negative(self): vm = VM() vm.instructions = [Label('loop'), noop, noop] vm.vstack.push(0) vm.pc = 2 Njmp('loop').execute(vm) self.assertEqual(len(vm.vstack), 0) self.assertEqual(vm.pc, 2)
def test_it_outputs_the_character_at_the_top_of_the_value_stack(self): screen = TestScreen() vm = VM() vm.screen = screen vm.vstack.push(97) Putc().execute(vm) self.assertEqual(len(vm.vstack), 0) self.assertEqual(screen.contents, 'a') screen.turnOff()
def test_it_reads_a_number_and_places_it_at_the_address_on_the_top_of_the_value_stack( self): keyboard = TestKeyboard('1234') vm = VM() vm.keyboard = keyboard vm.vstack.push(100) Getn().execute(vm) self.assertEqual(len(vm.vstack), 0) self.assertEqual(vm.memory[100], 1234) keyboard.detach()
def test_when_divisor_is_zero(self): vm = VM() vm.vstack.push(1) vm.vstack.push(0) with self.assertRaisesRegex(ZeroDivisionError, 'modulo by zero'): Mod().execute(vm)
def test_it_pushes_a_number_onto_the_value_stack(self): vm = VM() Push(1).execute(vm) self.assertEqual(len(vm.vstack), 1) self.assertEqual(vm.vstack.top(), 1)
def test_it_discards_the_top_item_on_the_value_stack(self): vm = VM() vm.vstack.push(1) Discard().execute(vm) self.assertEqual(len(vm.vstack), 0)
def test_it_duplicates_the_top_item_on_the_value_stack(self): vm = VM() vm.vstack.push(1) Dup().execute(vm) self.assertEqual(len(vm.vstack), 2) self.assertEqual(vm.vstack.pop(), 1) self.assertEqual(vm.vstack.pop(), 1)
def test_it_adds(self): vm = VM() vm.vstack.push(3) vm.vstack.push(2) Add().execute(vm) self.assertEqual(len(vm.vstack), 1) self.assertEqual(vm.vstack.top(), 5)
def test_it_mods(self): vm = VM() vm.vstack.push(7) vm.vstack.push(2) Mod().execute(vm) self.assertEqual(len(vm.vstack), 1) self.assertEqual(vm.vstack.top(), 1)
def test_it_multiplies(self): vm = VM() vm.vstack.push(3) vm.vstack.push(2) Mul().execute(vm) self.assertEqual(len(vm.vstack), 1) self.assertEqual(vm.vstack.top(), 6)
def test_it_divides(self): vm = VM() vm.vstack.push(7) vm.vstack.push(2) Div().execute(vm) self.assertEqual(len(vm.vstack), 1) self.assertEqual(vm.vstack.top(), 3)
def test_it_subtracts(self): vm = VM() vm.vstack.push(3) vm.vstack.push(2) Sub().execute(vm) self.assertEqual(len(vm.vstack), 1) self.assertEqual(vm.vstack.top(), 1)
def test_it_stores_the_value_at_the_given_address(self): vm = VM() vm.vstack.push(1000) vm.vstack.push(1) Store().execute(vm) self.assertEqual(len(vm.vstack), 0) self.assertEqual(vm.memory[1000], 1)
def test_it_returns(self): vm = VM() vm.cstack.push(5) self.assertEqual(vm.pc, 0) Ret().execute(vm) self.assertEqual(len(vm.cstack), 0) self.assertEqual(vm.pc, 5)
def test_it_swaps_the_two_top_items_on_the_value_stack(self): vm = VM() vm.vstack.push(1) vm.vstack.push(2) vm.vstack.push(3) Swap().execute(vm) self.assertEqual(len(vm.vstack), 3) self.assertEqual(vm.vstack.pop(), 2) self.assertEqual(vm.vstack.pop(), 3) self.assertEqual(vm.vstack.pop(), 1)
def test_it_counts_from_1_to_10(self): screen = TestScreen() vm = VM() vm.screen = screen vm.instructions = [ Push(1), # Put a 1 on the stack Label(' '), # Set a Label at this point Dup(), # Duplicate the top stack item Putn(), # Output the current value Push(10), # Put 10 (newline) on the stack... Putc(), # ...and output the newline Push(1), # Put a 1 on the stack Add(), # Increment our current value Dup(), # Duplicate the value to test it Push(11), # Push 11 onto the stack Sub(), # Subtraction Zjmp('\t'), # If we have a 0, jump to the end Ujmp(' '), # Jump to the start Label('\t'), # Set the end label Discard(), # Discard our accumulator, to be tidy End() # Finish ] vm.run() self.assertEqual(screen.contents, '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n') screen.turnOff()
def test_find_label(self): vm = VM() vm.instructions = [Push(1), Label('a'), Push(2), Label('b'), Add()] self.assertEqual(vm.find_label('a'), 1) self.assertEqual(vm.find_label('b'), 3) with self.assertRaisesRegex(LabelMissingError, 'c'): vm.find_label('c')
def test_it_raises_an_error_when_no_end_instruction_is_reached(self): vm = VM() vm.instructions = [Push(3), Dup(), Mul()] with self.assertRaisesRegex(OutOfBoundsError, 'program counter: 3'): vm.run()
def test_it_raises_halt(self): vm = VM() with self.assertRaises(Halt): End().execute(vm)