def test_text_ellipsing(self): """Test the text gets ellipsed if it's too long """ text = 'This is a text that it is too long. In fact, it exceeds the eighty column standard ' \ 'terminal width, which forces the text frame renderer to add an ellipse at the end of the ' \ 'text. ' * 6 spinner = HaloNotebook(text=text, spinner='dots') spinner.start() time.sleep(1) output = self._get_test_output(spinner)['text'] terminal_width = get_terminal_columns() # -6 of the ' (...)' ellipsis, -2 of the spinner and space self.assertEqual(output[0], '{} {} (...)'.format(frames[0], text[:terminal_width - 6 - 2])) self.assertEqual(output[1], '{} {} (...)'.format(frames[1], text[:terminal_width - 6 - 2])) self.assertEqual(output[2], '{} {} (...)'.format(frames[2], text[:terminal_width - 6 - 2])) spinner.succeed('End!') output = self._get_test_output(spinner)['text'] pattern = re.compile(r'(✔|v) End!', re.UNICODE) self.assertRegexpMatches(output[-1], pattern)
def test_text_animation(self): """Test the text gets animated when it is too long """ text = 'This is a text that it is too long. In fact, it exceeds the eighty column standard ' \ 'terminal width, which forces the text frame renderer to add an ellipse at the end of the ' \ 'text. ' * 6 spinner = Halo(text=text, spinner='dots', stream=self._stream, animation='marquee') spinner.start() time.sleep(1) spinner.succeed('End!') output = self._get_test_output()['text'] terminal_width = get_terminal_columns() self.assertEqual( output[0], '{0} {1}'.format(frames[0], text[:terminal_width - 2])) self.assertEqual( output[1], '{0} {1}'.format(frames[1], text[1:terminal_width - 1])) self.assertEqual(output[2], '{0} {1}'.format(frames[2], text[2:terminal_width])) pattern = re.compile(r'(✔|v) End!', re.UNICODE) self.assertRegexpMatches(output[-1], pattern)
def _get_text(self, text): """Creates frames based on the selected animation Returns ------- self """ animation = self._animation stripped_text = text.strip() # Check which frame of the animation is the widest max_spinner_length = max([len(i) for i in self._spinner['frames']]) # Subtract to the current terminal size the max spinner length # (-1 to leave room for the extra space between spinner and text) terminal_width = get_terminal_columns() - max_spinner_length - 1 text_length = len(stripped_text) frames = [] if terminal_width < text_length and animation: if animation == 'bounce': """ Make the text bounce back and forth """ for x in range(0, text_length - terminal_width + 1): frames.append(stripped_text[x:terminal_width + x]) frames.extend(list(reversed(frames))) elif 'marquee': """ Make the text scroll like a marquee """ stripped_text = stripped_text + ' ' + stripped_text[:terminal_width] for x in range(0, text_length + 1): frames.append(stripped_text[x:terminal_width + x]) elif terminal_width < text_length and not animation: # Add ellipsis if text is larger than terminal width and no animation was specified frames = [stripped_text[:terminal_width - 6] + ' (...)'] else: frames = [stripped_text] return { 'original': text, 'frames': frames }
def test_bounce_animation(self): def filler_text(n_chars): return "_" * n_chars terminal_width = get_terminal_columns() text = "{}abc".format(filler_text(terminal_width)) expected_frames_without_appended_spinner = [ "{}".format(filler_text(terminal_width - 2)), "{}".format(filler_text(terminal_width - 2)), "{}".format(filler_text(terminal_width - 2)), "{}a".format(filler_text(terminal_width - 3)), "{}ab".format(filler_text(terminal_width - 4)), "{}abc".format(filler_text(terminal_width - 5)), "{}abc".format(filler_text(terminal_width - 5)), "{}ab".format(filler_text(terminal_width - 4)), "{}a".format(filler_text(terminal_width - 3)), "{}".format(filler_text(terminal_width - 2)), "{}".format(filler_text(terminal_width - 2)), "{}".format(filler_text(terminal_width - 2)), ] # Prepend the actual spinner expected_frames = [ "{} {}".format(frames[idx % frames.__len__()], frame) for idx, frame in enumerate(expected_frames_without_appended_spinner) ] spinner = Halo(text, animation="bounce", stream=self._stream) spinner.start() # Sleep a full bounce cycle time.sleep(1.2) spinner.stop() output = self._get_test_output()['text'] zipped_expected_and_actual_frame = zip(expected_frames, output) for multiple_frames in zipped_expected_and_actual_frame: expected_frame, actual_frame = multiple_frames self.assertEquals(expected_frame, actual_frame)