diff --git a/.gitignore b/.gitignore index 95c8dc9..e0a9bb9 100644 --- a/.gitignore +++ b/.gitignore @@ -101,6 +101,7 @@ pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports +test_output/ htmlcov/ .tox/ .nox/ diff --git a/.travis.yml b/.travis.yml index bdc2fd0..ce11076 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,4 +11,4 @@ python: install: - pip install -r test_requirements.txt script: - - pytest --cov=erika tests/ --cov-report=html -m 'not hardware' + - pytest --cov=erika tests/ --cov-report=html --html=test_output/report.html -m 'not hardware' diff --git a/erika/cli.py b/erika/cli.py index 205902b..6982437 100644 --- a/erika/cli.py +++ b/erika/cli.py @@ -117,11 +117,12 @@ def print_ascii_art(args): renderer = ErikaImageRenderer(erika, strategy_string) renderer.render_file(file_path) finally: - erika.wait_for_user_if_simulated() + if erika: + erika.wait_for_user_if_simulated() - # Do a proper shutdown even in case of exception - or curses settings may make the current terminal unusable. - # I googled - it's okay to call __exit__ directly ( https://stackoverflow.com/a/26635947/1143126 ) - erika.__exit__() + # Do a proper shutdown even in case of exception - or curses settings may make the current terminal unusable. + # I googled - it's okay to call __exit__ directly ( https://stackoverflow.com/a/26635947/1143126 ) + erika.__exit__() def run_tic_tac_toe(args): @@ -137,18 +138,15 @@ def get_erika_for_given_args(args, is_character_based=False): if is_dry_run: if is_character_based or not 'file' in args: # using low size just so it fits on the screen well - does not reflect the paper dimensions that Erika supports - erika = CharacterBasedErikaMock(DRY_RUN_WIDTH, DRY_RUN_HEIGHT, delay_after_each_step=DRY_RUN_DELAY, - exception_if_overprinted=False) + erika = CharacterBasedErikaMock(DRY_RUN_WIDTH, DRY_RUN_HEIGHT, delay_after_each_step=DRY_RUN_DELAY) else: # a bit hacky, as I'm mirroring behavior from ErikaImageRenderer - this kindof goes against the now-beautiful architecture :( try: # hacky: use exception to determine image type image_for_provoking_exception = WrappedImage(args.file) - erika = MicrostepBasedErikaMock(DRY_RUN_WIDTH, DRY_RUN_HEIGHT, output_after_each_step=True, - delay_after_each_step=DRY_RUN_DELAY, exception_if_overprinted=False) + erika = MicrostepBasedErikaMock(DRY_RUN_WIDTH, DRY_RUN_HEIGHT, delay_after_each_step=DRY_RUN_DELAY) except NotAnImageException: - erika = CharacterBasedErikaMock(DRY_RUN_WIDTH, DRY_RUN_HEIGHT, delay_after_each_step=DRY_RUN_DELAY, - exception_if_overprinted=False) + erika = CharacterBasedErikaMock(DRY_RUN_WIDTH, DRY_RUN_HEIGHT, delay_after_each_step=DRY_RUN_DELAY) else: erika = Erika(com_port) @@ -193,7 +191,7 @@ def main(): # with argcomplete used now, this shoudl be the very first call - no side-effects should happen before argument_parser = create_argument_parser() args = argument_parser.parse_args() - if ('func' in args): + if 'func' in args: args.func(args) else: argument_parser.parse_args('-h') diff --git a/erika/erika_mock.py b/erika/erika_mock.py index 4fc7e56..14b4372 100644 --- a/erika/erika_mock.py +++ b/erika/erika_mock.py @@ -32,98 +32,16 @@ class AbstractErikaMock(AbstractErika): - # TODO are all these methods used? - # To keep things testable: If the methods make sense for the AbstractErikaMock implementations, - # add useful test behavior so Erika and AbstractErikaMock are always close! - - def _decode_character(self, char): - pass - - def _cursor_next_line(self, n=1): - pass - - def _cursor_previous_line(self, n=1): - pass - - def _cursor_horizontal_absolute(self, n=1): - pass - - def _cursor_position(self, n=1, m=1): - pass - - def _erase_in_display(self, n=0): - pass - - def _erase_in_line(self, n=0): - pass - - def _scroll_up(self, n=1): - pass - - def _scroll_down(self, n=1): - pass - - def _select_graphic_rendition(self, *n): - pass - - def _aux_port_on(self): - pass - - def _aux_port_off(self): - pass - - def _device_status_report(self): - pass - - def _save_cursor_position(self): - pass - - def _restore_cursor_position(self): - pass - - def __enter__(self): - return self - - def __exit__(self, *args): - pass - - def alarm(self, duration): - pass - - def read(self): - # reading not needed for current tests - pass - - def _print_raw(self, data): - raise Exception('User is not supposed to call this function directly') - - def _advance_paper(self): - raise Exception('User is not supposed to call this function directly') - - def _write_byte(self, data, delay=0.5): - raise Exception('User is not supposed to call this function directly') - - def set_keyboard_echo(self, value): - raise Exception('Not supported yet') - - def decode(self, value): - raise Exception('Not supported yet') - - -# to get exception-safe behavior, make sure __exit__ is always called (by using with-statements) -class CharacterBasedErikaMock(AbstractErikaMock): - - def __init__(self, - width=ERIKA_PAGE_WIDTH_CHARACTERS_SOFT_LIMIT_AT_12_CHARS_PER_INCH, - height=ERIKA_PAGE_HEIGHT_CHARACTERS, - exception_if_overprinted=True, - delay_after_each_step=0, - inside_unit_test=False): + def __init__(self, width, height, exception_if_overprinted, delay_after_each_step, inside_unit_test): + super().__init__() self.inside_unit_test = inside_unit_test # if your program fails here, add environment variable TERM=linux self.stdscr = curses.initscr() + if inside_unit_test: + self.stdscr.clear() + self._resize_if_more_space_is_needed(height, width) # no enter key needed to post input; @@ -168,18 +86,67 @@ def _resize_if_more_space_is_needed(self, height, width): if window_max_x <= (width + 2) or window_max_y <= (height + 2): self.stdscr.resize(max(window_max_y, height + 2), max(window_max_x, width + 2)) + def _cursor_up(self, n=1): + y, x = self.stdscr.getyx() + self.stdscr.move(y - n, x) + self.canvas_y -= n + + def _cursor_down(self, n=1): + y, x = self.stdscr.getyx() + self.stdscr.move(y + n, x) + self.canvas_y += n + + def _cursor_back(self, n=1): + y, x = self.stdscr.getyx() + self.stdscr.move(y, x - n) + self.canvas_x -= n + + def _cursor_forward(self, n=1): + y, x = self.stdscr.getyx() + self.stdscr.move(y, x + n) + self.canvas_x += n + def set_keyboard_echo(self, value): if value: curses.echo() else: curses.noecho() + def wait_for_user_if_simulated(self): + self.stdscr.getch() + + def alarm(self, duration): + # curses supports beep(), but this does not seem to work everywhere + pass + def read(self): c = chr(self.stdscr.getch()) return c - def wait_for_user_if_simulated(self): - self.stdscr.getch() + def _print_raw(self, data): + raise Exception('User is not supposed to call this function directly') + + def _advance_paper(self): + raise Exception('User is not supposed to call this function directly') + + def _write_byte(self, data, delay=0.5): + raise Exception('User is not supposed to call this function directly') + + def decode(self, value): + raise Exception('Not supported yet') + + +# to get exception-safe behavior, make sure __exit__ is always called (by using with-statements) +class CharacterBasedErikaMock(AbstractErikaMock): + + def __init__(self, + width=ERIKA_PAGE_WIDTH_CHARACTERS_SOFT_LIMIT_AT_12_CHARS_PER_INCH, + height=ERIKA_PAGE_HEIGHT_CHARACTERS, + exception_if_overprinted=False, + delay_after_each_step=0, + inside_unit_test=False): + super(CharacterBasedErikaMock, self).__init__(width, height, exception_if_overprinted, delay_after_each_step, + inside_unit_test) # microstep-based @@ -204,40 +171,16 @@ def delete_pixel(self): # character-based def move_up(self): - if not self.inside_unit_test: - self._cursor_up() - self.canvas_y -= 1 + self._cursor_up() def move_down(self): - if not self.inside_unit_test: - self._cursor_down() - self.canvas_y += 1 + self._cursor_down() def move_left(self): - if not self.inside_unit_test: - self._cursor_back() - self.canvas_x -= 1 + self._cursor_back() def move_right(self): - if not self.inside_unit_test: - self._cursor_forward() - self.canvas_x += 1 - - def _cursor_up(self, n=1): - y, x = self.stdscr.getyx() - self.stdscr.move(y - n, x) - - def _cursor_down(self, n=1): - y, x = self.stdscr.getyx() - self.stdscr.move(y + n, x) - - def _cursor_forward(self, n=1): - y, x = self.stdscr.getyx() - self.stdscr.move(y, x + n) - - def _cursor_back(self, n=1): - y, x = self.stdscr.getyx() - self.stdscr.move(y, x - n) + self._cursor_forward() def demo(self): for i in range(0, 10): @@ -253,9 +196,9 @@ def crlf(self): self.stdscr.move(y + 1, 0) def print_ascii(self, text): + y, x = self.stdscr.getyx() for c in text: try: - # print('Trying to print letter "{}" at ({}, {}).'.format(c, self.canvas_x, self.canvas_y)) if not self.canvas[self.canvas_y][self.canvas_x] == " ": if self.exception_if_overprinted: raise Exception( @@ -267,15 +210,22 @@ def print_ascii(self, text): "cli.DRY_RUN_WIDTH and cli.DRY_RUN_HEIGHT " "if you need more space".format(self.canvas_x, self.canvas_y, self.width, self.height)) sys.exit(1) - self.canvas_x += 1 + self.stdscr.addstr(text) + self.stdscr.move(y, x + len(text)) + if self.delay_after_each_step > 0: sleep(self.delay_after_each_step) self.stdscr.refresh() def delete_ascii(self, reversed_text): + text_length = len(reversed_text) + if text_length == 0: + return + self.canvas_x -= 1 + y, x = self.stdscr.getyx() for c in reversed_text: try: if self.canvas[self.canvas_y][self.canvas_x] == c: @@ -291,65 +241,46 @@ def delete_ascii(self, reversed_text): self.canvas_x -= 1 self.canvas_x += 1 - self._cursor_back(n=len(reversed_text)) - self.stdscr.addstr(" " * len(reversed_text)) - self._cursor_back(n=len(reversed_text)) + self.stdscr.move(y, x - text_length) + self.stdscr.addstr((" " * text_length)) + self.stdscr.move(y, x - text_length) + if self.delay_after_each_step > 0: sleep(self.delay_after_each_step) self.stdscr.refresh() - def _test_debug_helper_print_canvas(self): - """for debugging: print the current canvas to stdout""" - print(' ' + ''.zfill(self.width).replace('0', '#')) - for line in self.canvas: - print('#' + ''.join(line) + '#') - print(' ' + ''.zfill(self.width).replace('0', '#')) - print() - -# TODO in another ticket: switch MicrostepBasedErikaMock over to using curses class MicrostepBasedErikaMock(AbstractErikaMock): def __init__(self, - width=ERIKA_PAGE_WIDTH_MICROSTEPS_HARD_LIMIT_AT_12_CHARS_PER_INCH, - height=ERIKA_PAGE_HEIGHT_MICROSTEPS, - exception_if_overprinted=True, - output_after_each_step=False, - delay_after_each_step=0): - self.width = width - self.height = height - self.canvas = [] - for y in range(height): - new_list = [] - for x in range(width): - new_list.append(False) - self.canvas.append(new_list) - self.canvas_x = 0 - self.canvas_y = 0 - self.exception_if_overprinted = exception_if_overprinted - self.delay_after_each_step = delay_after_each_step - self.output_after_each_step = output_after_each_step + width=ERIKA_PAGE_WIDTH_CHARACTERS_SOFT_LIMIT_AT_12_CHARS_PER_INCH, + height=ERIKA_PAGE_HEIGHT_CHARACTERS, + exception_if_overprinted=False, + delay_after_each_step=0, + inside_unit_test=False): + super(MicrostepBasedErikaMock, self).__init__(width, height, exception_if_overprinted, delay_after_each_step, + inside_unit_test) # microstep-based def move_down_microstep(self): - self.canvas_y += 1 + self._cursor_down() def move_up_microstep(self): - self.canvas_y -= 1 + self._cursor_up() def move_right_microsteps(self, num_steps=1): - self.canvas_x += num_steps + self._cursor_forward(num_steps) def move_left_microsteps(self, num_steps=1): - self.canvas_x -= num_steps + self._cursor_back(num_steps) def print_pixel(self): try: - if self.canvas[self.canvas_y][self.canvas_x]: + if self.canvas[self.canvas_y][self.canvas_x] == "X": if self.exception_if_overprinted: raise Exception( "Not supposed to print a pixel twice: at ({}, {}).".format(self.canvas_x, self.canvas_y)) - self.canvas[self.canvas_y][self.canvas_x] = True + self.canvas[self.canvas_y][self.canvas_x] = "X" except IndexError as e: print("IndexError at ({}, {}) of ({}, {}) - increase values of " "cli.DRY_RUN_WIDTH and cli.DRY_RUN_HEIGHT " @@ -357,40 +288,30 @@ def print_pixel(self): sys.exit(1) self.canvas_x += 1 - if self.output_after_each_step: - self._test_debug_helper_print_canvas() + self.stdscr.addstr("X") + if self.delay_after_each_step > 0: sleep(self.delay_after_each_step) + self.stdscr.refresh() def delete_pixel(self): + y, x = self.stdscr.getyx() self.canvas_x -= 1 try: - if self.canvas[self.canvas_y][self.canvas_x]: - self.canvas[self.canvas_y][self.canvas_x] = False + if self.canvas[self.canvas_y][self.canvas_x] == "X": + self.canvas[self.canvas_y][self.canvas_x] = " " except IndexError as e: print("IndexError at ({}, {}) of ({}, {}) - increase values of " "cli.DRY_RUN_WIDTH and cli.DRY_RUN_HEIGHT " "if you need more space".format(self.canvas_x, self.canvas_y, self.width, self.height)) sys.exit(1) - if self.output_after_each_step: - self._test_debug_helper_print_canvas() + self.stdscr.move(y, x - 1) + self.stdscr.addstr(" ") + if self.delay_after_each_step > 0: sleep(self.delay_after_each_step) - - def wait_for_user_if_simulated(self): - pass - - def _test_debug_helper_print_canvas(self): - """for debugging: print the current canvas to stdout""" - print(' ' + ''.zfill(self.width).replace('0', '#')) - for line in self.canvas: - print('#' + ''.join(self._transform_for_output(line)) + '#') - print(' ' + ''.zfill(self.width).replace('0', '#')) - print() - - def _transform_for_output(self, line): - return ["X" if x else " " for x in line] + self.stdscr.refresh() # character-based diff --git a/run_manual_tests.sh b/run_manual_tests.sh index 2b52691..a053333 100755 --- a/run_manual_tests.sh +++ b/run_manual_tests.sh @@ -39,6 +39,8 @@ set -x ./erika.sh render_ascii_art -h ./erika.sh render_ascii_art -d -f ./tests/test_resources/test_ascii_art.txt +# FIXME +#cat tests/test_resources/test_ascii_art.txt | ./erika.sh render_ascii_art -d ./erika.sh render_ascii_art -d -f ./tests/test_resources/test_ascii_art.txt -s LineByLine ./erika.sh render_ascii_art -d -f ./tests/test_resources/test_ascii_art.txt -s Interlaced ./erika.sh render_ascii_art -d -f ./tests/test_resources/test_ascii_art.txt -s RandomDotFill diff --git a/run_unittests.sh b/run_unittests.sh index 8700676..8da7102 100755 --- a/run_unittests.sh +++ b/run_unittests.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash -pytest --cov=erika tests/ --cov-report=html -m 'not hardware' +pytest --cov=erika tests/ --cov-report=html --html=test_output/report.html -m 'not hardware' diff --git a/test_requirements.txt b/test_requirements.txt index 00186cd..25d4512 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,4 +1,5 @@ -r requirements.txt pytest==5.2.1 pytest-cov==2.8.1 -pytest-mock==1.13.0 \ No newline at end of file +pytest-mock==1.13.0 +pytest-html==2.0.1 \ No newline at end of file diff --git a/tests/erika_image_render_unittest.py b/tests/erika_image_render_unittest.py index 96000d8..c108fef 100644 --- a/tests/erika_image_render_unittest.py +++ b/tests/erika_image_render_unittest.py @@ -1,11 +1,8 @@ -# coding=utf-8 - import unittest from erika.erika_image_renderer import * from erika.erika_mock import * from tests.erika_mock_unittest import assert_print_output -from tests.erika_mock_unittest import assert_print_output_pixels # noinspection SpellCheckingInspection @@ -13,14 +10,14 @@ class RendererTest(unittest.TestCase): def helper_test_ErikaImageRenderingStrategy_square(self, strategy): """test helper to verify rendering with the given strategy works""" - with CharacterBasedErikaMock(6, 6, inside_unit_test=True) as my_erika: + with CharacterBasedErikaMock(6, 6, inside_unit_test=True, exception_if_overprinted=True) as my_erika: renderer = ErikaImageRenderer(my_erika, "test: strategy will be set explicitly") renderer.render_file_for_fixed_strategy('tests/test_resources/test_ascii_art_small.txt', strategy) assert_print_output(self, my_erika, ["abcdef", "ghijkl", "mnopqr", "stuvwx", "yzäöüß", "!?#'\"/"]) def helper_test_ErikaImageRenderingStrategy_high(self, strategy): """test helper to verify rendering with the given strategy works""" - with CharacterBasedErikaMock(3, 12, inside_unit_test=True) as my_erika: + with CharacterBasedErikaMock(3, 12, inside_unit_test=True, exception_if_overprinted=True) as my_erika: renderer = ErikaImageRenderer(my_erika, "test: strategy will be set explicitly") renderer.render_file_for_fixed_strategy('tests/test_resources/test_ascii_art_small_high.txt', strategy) assert_print_output(self, my_erika, @@ -28,17 +25,17 @@ def helper_test_ErikaImageRenderingStrategy_high(self, strategy): def helper_test_ErikaImageRenderingStrategy_wide(self, strategy): """test helper to verify rendering with the given strategy works""" - with CharacterBasedErikaMock(9, 4, inside_unit_test=True) as my_erika: + with CharacterBasedErikaMock(9, 4, inside_unit_test=True, exception_if_overprinted=True) as my_erika: renderer = ErikaImageRenderer(my_erika, "test: strategy will be set explicitly") renderer.render_file_for_fixed_strategy('tests/test_resources/test_ascii_art_small_wide.txt', strategy) assert_print_output(self, my_erika, ["abcdefghi", "jklmnopqr", "stuvwxyzä"]) def helper_test_ErikaImageRenderingStrategy_real_image(self, strategy): """test helper to verify rendering with the given strategy works""" - with MicrostepBasedErikaMock(20, 30) as my_erika: + with MicrostepBasedErikaMock(20, 30, inside_unit_test=True, exception_if_overprinted=True) as my_erika: renderer = ErikaImageRenderer(my_erika, "test: strategy will be set explicitly") renderer.render_file_for_fixed_strategy('tests/test_resources/test_image_grayscale_1.bmp', strategy) - assert_print_output_pixels(self, my_erika, [ + assert_print_output(self, my_erika, [ "XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXX", @@ -113,7 +110,7 @@ def testArchimedeanSpiralOutwardErikaImageRenderingStrategy(self): def testArchimedeanSpiralOutwardErikaImageRenderingStrategy2(self): """test with a bigger file + two spirals""" - with CharacterBasedErikaMock(60, 30, False, inside_unit_test=True) as my_erika: + with CharacterBasedErikaMock(60, 30, inside_unit_test=True, exception_if_overprinted=False) as my_erika: strategy = ArchimedeanSpiralOutwardErikaImageRenderingStrategy(spiral_param_a=1, render_remaining_characters=False) renderer = ErikaImageRenderer(my_erika, "test: strategy will be set explicitly") diff --git a/tests/erika_mock_unittest.py b/tests/erika_mock_unittest.py index d83025d..b198dbc 100644 --- a/tests/erika_mock_unittest.py +++ b/tests/erika_mock_unittest.py @@ -11,23 +11,23 @@ def assert_print_output(test_case, my_erika, expected_array_of_joined_lines): actual_line = my_erika.canvas[line] test_case.assertEqual(expected_line, actual_line) - -def assert_print_output_pixels(test_case, my_erika, expected_array_of_joined_transformed_lines): - for line in range(len(expected_array_of_joined_transformed_lines)): - expected_line_joined = expected_array_of_joined_transformed_lines[line] - expected_line = list(expected_line_joined) - actual_line = transform_to_printable(my_erika.canvas[line]) - test_case.assertEqual(expected_line, actual_line) - - -def transform_to_printable(line): - return ["X" if x else " " for x in line] + # validate curses output as well + y, x = my_erika.stdscr.getyx() + my_erika.stdscr.move(0, 0) + temp_y = 0 + for line in range(len(expected_array_of_joined_lines)): + expected_line_joined = expected_array_of_joined_lines[line] + expected_line_encoded = expected_line_joined.encode() + actual_line_encoded = my_erika.stdscr.instr(temp_y, 0, len(expected_line_encoded)) + test_case.assertEqual(expected_line_encoded, actual_line_encoded) + temp_y += 1 + my_erika.stdscr.move(y, x) class ErikaMockTest(unittest.TestCase): def test_write_and_read_back_characters(self): """simple test that the CharacterBasedErikaMock records what is written to it""" - my_erika = CharacterBasedErikaMock(width=5, height=3, inside_unit_test=True) + my_erika = CharacterBasedErikaMock(width=5, height=3, inside_unit_test=True, exception_if_overprinted=True) my_erika.print_ascii("Hello") my_erika.move_down() my_erika.move_down() @@ -44,13 +44,14 @@ def test_write_and_read_back_characters(self): assert_print_output(self, my_erika, ["Hello", "World", " ! "]) def test_write_and_read_back_microsteps(self): - my_erika = MicrostepBasedErikaMock(width=5, height=3) + my_erika = MicrostepBasedErikaMock(width=5, height=3, inside_unit_test=True) my_erika.print_pixel() my_erika.move_right_microsteps(1) my_erika.print_pixel() my_erika.move_right_microsteps(1) my_erika.print_pixel() my_erika.move_left_microsteps(1) + assert_print_output(self, my_erika, ["X X X", " ", " "]) my_erika.move_down_microstep() my_erika.move_left_microsteps(3) @@ -58,6 +59,7 @@ def test_write_and_read_back_microsteps(self): my_erika.move_right_microsteps(1) my_erika.print_pixel() my_erika.move_left_microsteps(1) + assert_print_output(self, my_erika, ["X X X", " X X ", " "]) my_erika.move_down_microstep() my_erika.move_right_microsteps(1) @@ -67,13 +69,13 @@ def test_write_and_read_back_microsteps(self): my_erika.move_left_microsteps(3) my_erika.print_pixel() my_erika.move_left_microsteps(1) + assert_print_output(self, my_erika, ["X X X", " X X ", "X X X"]) my_erika.move_up_microstep() my_erika.move_right_microsteps(2) my_erika.print_pixel() my_erika.move_left_microsteps(1) - - assert_print_output_pixels(self, my_erika, ["X X X", " XXX ", "X X X"]) + assert_print_output(self, my_erika, ["X X X", " XXX ", "X X X"]) def test_delete_ascii(self): my_erika = CharacterBasedErikaMock(width=5, height=1, inside_unit_test=True, exception_if_overprinted=False) @@ -83,37 +85,41 @@ def test_delete_ascii(self): # test that deletion of 1 character works my_erika.delete_ascii("o") assert_print_output(self, my_erika, ["Hell "]) - y, x = my_erika.stdscr.getyx() - self.assertEqual("Hell ".encode(), my_erika.stdscr.instr(0, 0, 5)) - my_erika.stdscr.move(y, x) # test that deletion of a reversed string of characters works my_erika.delete_ascii("lle") assert_print_output(self, my_erika, ["H "]) - y, x = my_erika.stdscr.getyx() - self.assertEqual("H ".encode(), my_erika.stdscr.instr(0, 0, 5)) - my_erika.stdscr.move(y, x) - # test that the cursor rests above the "H" now my_erika.print_ascii("elp") assert_print_output(self, my_erika, ["Help "]) - y, x = my_erika.stdscr.getyx() - self.assertEqual("Help ".encode(), my_erika.stdscr.instr(0, 0, 5)) - my_erika.stdscr.move(y, x) + + def test_delete_ascii2(self): + my_erika = CharacterBasedErikaMock(width=5, height=1, inside_unit_test=True, exception_if_overprinted=False) + my_erika.print_ascii("Hello") + assert_print_output(self, my_erika, ["Hello"]) + + # test that deletion of 1 character works + my_erika.move_left() + my_erika.delete_ascii("lle") + assert_print_output(self, my_erika, ["H o"]) + + my_erika.move_right() + my_erika.print_ascii("x") + assert_print_output(self, my_erika, ["H x o"]) def test_delete_pixel(self): - my_erika = MicrostepBasedErikaMock(width=5, height=1, exception_if_overprinted=False) + my_erika = MicrostepBasedErikaMock(width=5, height=1, inside_unit_test=True, exception_if_overprinted=False) my_erika.print_pixel() my_erika.print_pixel() my_erika.print_pixel() my_erika.print_pixel() my_erika.print_pixel() - assert_print_output_pixels(self, my_erika, ["XXXXX"]) + assert_print_output(self, my_erika, ["XXXXX"]) my_erika.move_left_microsteps(1) my_erika.delete_pixel() - assert_print_output_pixels(self, my_erika, ["XXX X"]) + assert_print_output(self, my_erika, ["XXX X"]) def main():