text: import sys
  import unittest
  
  from flaky import flaky
  import pytest
  from qtpy import QtCore, QtGui, QtWidgets
  from qtpy.QtTest import QTest
  
  from qtconsole.console_widget import ConsoleWidget
  from qtconsole.qtconsoleapp import JupyterQtConsoleApp
  from . import no_display
  
  if sys.version[0] == '2':  # Python 2
      from IPython.core.inputsplitter import InputSplitter as TransformerManager
  else:
      from IPython.core.inputtransformer2 import TransformerManager
  
  
  SHELL_TIMEOUT = 20000
  
  
  @pytest.fixture
  def qtconsole(qtbot):
      """Qtconsole fixture."""
      # Create a console
      console = JupyterQtConsoleApp()
      console.initialize(argv=[])
  
      qtbot.addWidget(console.window)
      console.window.confirm_exit = False
      console.window.show()
      return console
  
  
  @flaky(max_runs=3)
  @pytest.mark.parametrize(
      "debug", [True, False])
  def test_scroll(qtconsole, qtbot, debug):
      """
      Make sure the scrolling works.
      """
      window = qtconsole.window
      shell = window.active_frontend
      control = shell._control
      scroll_bar = control.verticalScrollBar()
  
      # Wait until the console is fully up
      qtbot.waitUntil(lambda: shell._prompt_html is not None,
                      timeout=SHELL_TIMEOUT)
  
      assert scroll_bar.value() == 0
  
      # Define a function with loads of output
      # Check the outputs are working as well
      code = ["import time",
              "def print_numbers():",
              "    for i in range(1000):",
              "       print(i)",
              "       time.sleep(.01)"]
      for line in code:
          qtbot.keyClicks(control, line)
          qtbot.keyClick(control, QtCore.Qt.Key_Enter)
  
      with qtbot.waitSignal(shell.executed):
          qtbot.keyClick(control, QtCore.Qt.Key_Enter,
                         modifier=QtCore.Qt.ShiftModifier)
  
      def run_line(line, block=True):
          qtbot.keyClicks(control, line)
          if block:
              with qtbot.waitSignal(shell.executed):
                  qtbot.keyClick(control, QtCore.Qt.Key_Enter,
                                 modifier=QtCore.Qt.ShiftModifier)
          else:
              qtbot.keyClick(control, QtCore.Qt.Key_Enter,
                                 modifier=QtCore.Qt.ShiftModifier)
  
      if debug:
          # Enter debug
          run_line('%debug print()', block=False)
          qtbot.keyClick(control, QtCore.Qt.Key_Enter)
          # redefine run_line
          def run_line(line, block=True):
              qtbot.keyClicks(control, '!' + line)
              qtbot.keyClick(control, QtCore.Qt.Key_Enter,
                             modifier=QtCore.Qt.ShiftModifier)
              if block:
                  qtbot.waitUntil(
                      lambda: control.toPlainText().strip(
                          ).split()[-1] == "ipdb>")
  
      prev_position = scroll_bar.value()
  
      # Create a bunch of inputs
      for i in range(20):
          run_line('a = 1')
  
      assert scroll_bar.value() > prev_position
  
      # Put the scroll bar higher and check it doesn't move
      prev_position = scroll_bar.value() + scroll_bar.pageStep() // 2
      scroll_bar.setValue(prev_position)
  
      for i in range(2):
          run_line('a')
  
      assert scroll_bar.value() == prev_position
  
      # add more input and check it moved
      for i in range(10):
          run_line('a')
  
      assert scroll_bar.value() > prev_position
  
      prev_position = scroll_bar.value()
  
      # Run the printing function
      run_line('print_numbers()', block=False)
  
      qtbot.wait(1000)
  
      # Check everything advances
      assert scroll_bar.value() > prev_position
  
      # move up
      prev_position = scroll_bar.value() - scroll_bar.pageStep()
      scroll_bar.setValue(prev_position)
  
      qtbot.wait(1000)
  
      # Check position stayed the same
      assert scroll_bar.value() == prev_position
  
      # reset position
      prev_position = scroll_bar.maximum() - (scroll_bar.pageStep() * 8) // 10
      scroll_bar.setValue(prev_position)
  
      qtbot.wait(1000)
      assert scroll_bar.value() > prev_position
  
  
  @flaky(max_runs=3)
  def test_input(qtconsole, qtbot):
      """
      Test input function
      """
      window = qtconsole.window
      shell = window.active_frontend
      control = shell._control
  
      # Wait until the console is fully up
      qtbot.waitUntil(lambda: shell._prompt_html is not None,
                      timeout=SHELL_TIMEOUT)
  
      with qtbot.waitSignal(shell.executed):
          shell.execute("import time")
  
      if sys.version[0] == '2':
          input_function = 'raw_input'
      else:
          input_function = 'input'
      shell.execute("print(" + input_function + "('name: ')); time.sleep(3)")
  
      qtbot.waitUntil(lambda: control.toPlainText().split()[-1] == 'name:')
  
      qtbot.keyClicks(control, 'test')
      qtbot.keyClick(control, QtCore.Qt.Key_Enter)
      qtbot.waitUntil(lambda: not shell._reading)
      qtbot.keyClick(control, 'z', modifier=QtCore.Qt.ControlModifier)
      for i in range(10):
          qtbot.keyClick(control, QtCore.Qt.Key_Backspace)
      qtbot.waitUntil(lambda: shell._prompt_html is not None,
                      timeout=SHELL_TIMEOUT)
  
      assert 'name: test\ntest' in control.toPlainText()
  
  
  @flaky(max_runs=3)
  def test_debug(qtconsole, qtbot):
      """
      Make sure the cursor works while debugging
  
      It might not because the console is "_executing"
      """
      window = qtconsole.window
      shell = window.active_frontend
      control = shell._control
  
      # Wait until the console is fully up
      qtbot.waitUntil(lambda: shell._prompt_html is not None,
                      timeout=SHELL_TIMEOUT)
  
      # Enter execution
      code = "%debug range(1)"
      qtbot.keyClicks(control, code)
      qtbot.keyClick(control, QtCore.Qt.Key_Enter,
                     modifier=QtCore.Qt.ShiftModifier)
  
      qtbot.waitUntil(
          lambda: control.toPlainText().strip().split()[-1] == "ipdb>",
          timeout=SHELL_TIMEOUT)
  
      # We should be able to move the cursor while debugging
      qtbot.keyClicks(control, "abd")
      qtbot.wait(100)
      qtbot.keyClick(control, QtCore.Qt.Key_Left)
      qtbot.keyClick(control, 'c')
      qtbot.wait(100)
      assert control.toPlainText().strip().split()[-1] == "abcd"
  
  
  @pytest.mark.skipif(no_display, reason="Doesn't work without a display")
  class TestConsoleWidget(unittest.TestCase):
  
      @classmethod
      def setUpClass(cls):
          """ Create the application for the test case.
          """
          cls._app = QtWidgets.QApplication.instance()
          if cls._app is None:
              cls._app = QtWidgets.QApplication([])
          cls._app.setQuitOnLastWindowClosed(False)
  
      @classmethod
      def tearDownClass(cls):
          """ Exit the application.
          """
          QtWidgets.QApplication.quit()
  
      def assert_text_equal(self, cursor, text):
          cursor.select(cursor.Document)
          selection = cursor.selectedText()
          self.assertEqual(selection, text)
  
      def test_special_characters(self):
          """ Are special characters displayed correctly?
          """
          w = ConsoleWidget()
          cursor = w._get_prompt_cursor()
  
          test_inputs = ['xyz\b\b=\n',
                         'foo\b\nbar\n',
                         'foo\b\nbar\r\n',
                         'abc\rxyz\b\b=']
          expected_outputs = [u'x=z\u2029',
                              u'foo\u2029bar\u2029',
                              u'foo\u2029bar\u2029',
                              'x=z']
          for i, text in enumerate(test_inputs):
              w._insert_plain_text(cursor, text)
              self.assert_text_equal(cursor, expected_outputs[i])
              # clear all the text
              cursor.insertText('')
  
      def test_link_handling(self):
          noKeys = QtCore.Qt
          noButton = QtCore.Qt.MouseButton(0)
          noButtons = QtCore.Qt.MouseButtons(0)
          noModifiers = QtCore.Qt.KeyboardModifiers(0)
          MouseMove = QtCore.QEvent.MouseMove
          QMouseEvent = QtGui.QMouseEvent
  
          w = ConsoleWidget()
          cursor = w._get_prompt_cursor()
          w._insert_html(cursor, '<a href="http://python.org">written in</a>')
          obj = w._control
          tip = QtWidgets.QToolTip
          self.assertEqual(tip.text(), u'')
  
          # should be somewhere else
          elsewhereEvent = QMouseEvent(MouseMove, QtCore.QPoint(50,50),
                                       noButton, noButtons, noModifiers)
          w.eventFilter(obj, elsewhereEvent)
          self.assertEqual(tip.isVisible(), False)
          self.assertEqual(tip.text(), u'')
          # should be over text
          overTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
                                      noButton, noButtons, noModifiers)
          w.eventFilter(obj, overTextEvent)
          self.assertEqual(tip.isVisible(), True)
          self.assertEqual(tip.text(), "http://python.org")
  
          # should still be over text
          stillOverTextEvent = QMouseEvent(MouseMove, QtCore.QPoint(1,5),
                                           noButton, noButtons, noModifiers)
          w.eventFilter(obj, stillOverTextEvent)
          self.assertEqual(tip.isVisible(), True)
          self.assertEqual(tip.text(), "http://python.org")
  
      def test_width_height(self):
          # width()/height() QWidget properties should not be overridden.
          w = ConsoleWidget()
          self.assertEqual(w.width(), QtWidgets.QWidget.width(w))
          self.assertEqual(w.height(), QtWidgets.QWidget.height(w))
  
      def test_prompt_cursors(self):
          """Test the cursors that keep track of where the prompt begins and
          ends"""
          w = ConsoleWidget()
          w._prompt = 'prompt>'
          doc = w._control.document()
  
          # Fill up the QTextEdit area with the maximum number of blocks
          doc.setMaximumBlockCount(10)
          for _ in range(9):
              w._append_plain_text('line\n')
  
          # Draw the prompt, this should cause the first lines to be deleted
          w._show_prompt()
          self.assertEqual(doc.blockCount(), 10)
  
          # _prompt_pos should be at the end of the document
          self.assertEqual(w._prompt_pos, w._get_end_pos())
  
          # _append_before_prompt_pos should be at the beginning of the prompt
          self.assertEqual(w._append_before_prompt_pos,
                           w._prompt_pos - len(w._prompt))
  
          # insert some more text without drawing a new prompt
          w._append_plain_text('line\n')
          self.assertEqual(w._prompt_pos,
                           w._get_end_pos() - len('line\n'))
          self.assertEqual(w._append_before_prompt_pos,
                           w._prompt_pos - len(w._prompt))
  
          # redraw the prompt
          w._show_prompt()
          self.assertEqual(w._prompt_pos, w._get_end_pos())
          self.assertEqual(w._append_before_prompt_pos,
                           w._prompt_pos - len(w._prompt))
  
          # insert some text before the prompt
          w._append_plain_text('line', before_prompt=True)
          self.assertEqual(w._prompt_pos, w._get_end_pos())
          self.assertEqual(w._append_before_prompt_pos,
                           w._prompt_pos - len(w._prompt))
  
      def test_select_all(self):
          w = ConsoleWidget()
          w._append_plain_text('Header\n')
          w._prompt = 'prompt>'
          w._show_prompt()
          control = w._control
          app = QtWidgets.QApplication.instance()
  
          cursor = w._get_cursor()
          w._insert_plain_text_into_buffer(cursor, "if:\n    pass")
  
          cursor.clearSelection()
          control.setTextCursor(cursor)
  
          # "select all" action selects cell first
          w.select_all_smart()
          QTest.keyClick(control, QtCore.Qt.Key_C, QtCore.Qt.ControlModifier)
          copied = app.clipboard().text()
          self.assertEqual(copied,  'if:\n>     pass')
  
          # # "select all" action triggered a second time selects whole document
          w.select_all_smart()
          QTest.keyClick(control, QtCore.Qt.Key_C, QtCore.Qt.ControlModifier)
          copied = app.clipboard().text()
          self.assertEqual(copied,  'Header\nprompt>if:\n>     pass')
  
      def test_keypresses(self):
          """Test the event handling code for keypresses."""
          w = ConsoleWidget()
          w._append_plain_text('Header\n')
          w._prompt = 'prompt>'
          w._show_prompt()
          app = QtWidgets.QApplication.instance()
          control = w._control
  
          # Test setting the input buffer
          w._set_input_buffer('test input')
          self.assertEqual(w._get_input_buffer(), 'test input')
  
          # Ctrl+K kills input until EOL
          w._set_input_buffer('test input')
          c = control.textCursor()
          c.setPosition(c.position() - 3)
          control.setTextCursor(c)
          QTest.keyClick(control, QtCore.Qt.Key_K, QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(), 'test in')
  
          # Ctrl+V pastes
          w._set_input_buffer('test input ')
          app.clipboard().setText('pasted text')
          QTest.keyClick(control, QtCore.Qt.Key_V, QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(), 'test input pasted text')
          self.assertEqual(control.document().blockCount(), 2)
  
          # Paste should strip indentation
          w._set_input_buffer('test input ')
          app.clipboard().setText('    pasted text')
          QTest.keyClick(control, QtCore.Qt.Key_V, QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(), 'test input pasted text')
          self.assertEqual(control.document().blockCount(), 2)
  
          # Multiline paste, should also show continuation marks
          w._set_input_buffer('test input ')
          app.clipboard().setText('line1\nline2\nline3')
          QTest.keyClick(control, QtCore.Qt.Key_V, QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           'test input line1\nline2\nline3')
          self.assertEqual(control.document().blockCount(), 4)
          self.assertEqual(control.document().findBlockByNumber(1).text(),
                           'prompt>test input line1')
          self.assertEqual(control.document().findBlockByNumber(2).text(),
                           '> line2')
          self.assertEqual(control.document().findBlockByNumber(3).text(),
                           '> line3')
  
          # Multiline paste should strip indentation intelligently
          # in the case where pasted text has leading whitespace on first line
          # and we're pasting into indented position
          w._set_input_buffer('    ')
          app.clipboard().setText('    If 1:\n        pass')
          QTest.keyClick(control, QtCore.Qt.Key_V, QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           '    If 1:\n        pass')
  
          # Ctrl+Backspace should intelligently remove the last word
          w._set_input_buffer("foo = ['foo', 'foo', 'foo',    \n"
                              "       'bar', 'bar', 'bar']")
          QTest.keyClick(control, QtCore.Qt.Key_Backspace,
                         QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           ("foo = ['foo', 'foo', 'foo',    \n"
                            "       'bar', 'bar', '"))
          QTest.keyClick(control, QtCore.Qt.Key_Backspace,
                         QtCore.Qt.ControlModifier)
          QTest.keyClick(control, QtCore.Qt.Key_Backspace,
                         QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           ("foo = ['foo', 'foo', 'foo',    \n"
                            "       '"))
          QTest.keyClick(control, QtCore.Qt.Key_Backspace,
                         QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           ("foo = ['foo', 'foo', 'foo',    \n"
                            ""))
          QTest.keyClick(control, QtCore.Qt.Key_Backspace,
                         QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           "foo = ['foo', 'foo', 'foo',")
  
          # Ctrl+Delete should intelligently remove the next word
          w._set_input_buffer("foo = ['foo', 'foo', 'foo',    \n"
                              "       'bar', 'bar', 'bar']")
          c = control.textCursor()
          c.setPosition(35)
          control.setTextCursor(c)
          QTest.keyClick(control, QtCore.Qt.Key_Delete,
                         QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           ("foo = ['foo', 'foo', ',    \n"
                            "       'bar', 'bar', 'bar']"))
          QTest.keyClick(control, QtCore.Qt.Key_Delete,
                         QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           ("foo = ['foo', 'foo', \n"
                            "       'bar', 'bar', 'bar']"))
          QTest.keyClick(control, QtCore.Qt.Key_Delete,
                         QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           "foo = ['foo', 'foo', 'bar', 'bar', 'bar']")
          w._set_input_buffer("foo = ['foo', 'foo', 'foo',    \n"
                              "       'bar', 'bar', 'bar']")
          c = control.textCursor()
          c.setPosition(48)
          control.setTextCursor(c)
          QTest.keyClick(control, QtCore.Qt.Key_Delete,
                         QtCore.Qt.ControlModifier)
          self.assertEqual(w._get_input_buffer(),
                           ("foo = ['foo', 'foo', 'foo',    \n"
                            "'bar', 'bar', 'bar']"))
  
          # Left and right keys should respect the continuation prompt
          w._set_input_buffer("line 1\n"
                              "line 2\n"
                              "line 3")
          c = control.textCursor()
          c.setPosition(20)  # End of line 1
          control.setTextCursor(c)
          QTest.keyClick(control, QtCore.Qt.Key_Right)
          # Cursor should have moved after the continuation prompt
          self.assertEqual(control.textCursor().position(), 23)
          QTest.keyClick(control, QtCore.Qt.Key_Left)
          # Cursor should have moved to the end of the previous line
          self.assertEqual(control.textCursor().position(), 20)
  
          # TODO: many more keybindings
  
      def test_indent(self):
          """Test the event handling code for indent/dedent keypresses ."""
          w = ConsoleWidget()
          w._append_plain_text('Header\n')
          w._prompt = 'prompt>'
          w._show_prompt()
          control = w._control
  
          # TAB with multiline selection should block-indent
          w._set_input_buffer("")
          c = control.textCursor()
          pos=c.position()
          w._set_input_buffer("If 1:\n    pass")
          c.setPosition(pos, QtGui.QTextCursor.KeepAnchor)
          control.setTextCursor(c)
          QTest.keyClick(control, QtCore.Qt.Key_Tab)
          self.assertEqual(w._get_input_buffer(),"    If 1:\n        pass")
  
          # TAB with multiline selection, should block-indent to next multiple
          # of 4 spaces, if first line has 0 < indent < 4
          w._set_input_buffer("")
          c = control.textCursor()
          pos=c.position()
          w._set_input_buffer(" If 2:\n     pass")
          c.setPosition(pos, QtGui.QTextCursor.KeepAnchor)
          control.setTextCursor(c)
          QTest.keyClick(control, QtCore.Qt.Key_Tab)
          self.assertEqual(w._get_input_buffer(),"    If 2:\n        pass")
  
          # Shift-TAB with multiline selection should block-dedent
          w._set_input_buffer("")
          c = control.textCursor()
          pos=c.position()
          w._set_input_buffer("    If 3:\n        pass")
          c.setPosition(pos, QtGui.QTextCursor.KeepAnchor)
          control.setTextCursor(c)
          QTest.keyClick(control, QtCore.Qt.Key_Backtab)
          self.assertEqual(w._get_input_buffer(),"If 3:\n    pass")
  
      def test_complete(self):
          class TestKernelClient(object):
              def is_complete(self, source):
                  calls.append(source)
                  return msg_id
          w = ConsoleWidget()
          cursor = w._get_prompt_cursor()
          w._execute = lambda *args: calls.append(args)
          w.kernel_client = TestKernelClient()
          msg_id = object()
          calls = []
  
          # test incomplete statement (no _execute called, but indent added)
          w.execute("thing", interactive=True)
          self.assertEqual(calls, ["thing"])
          calls = []
          w._handle_is_complete_reply(
              dict(parent_header=dict(msg_id=msg_id),
                   content=dict(status="incomplete", indent="!!!")))
          self.assert_text_equal(cursor, u"thing\u2029> !!!")
          self.assertEqual(calls, [])
  
          # test complete statement (_execute called)
          msg_id = object()
          w.execute("else", interactive=True)
          self.assertEqual(calls, ["else"])
          calls = []
          w._handle_is_complete_reply(
              dict(parent_header=dict(msg_id=msg_id),
                   content=dict(status="complete", indent="###")))
          self.assertEqual(calls, [("else", False)])
          calls = []
          self.assert_text_equal(cursor, u"thing\u2029> !!!else\u2029")
  
          # test missing answer from is_complete
          msg_id = object()
          w.execute("done", interactive=True)
          self.assertEqual(calls, ["done"])
          calls = []
          self.assert_text_equal(cursor, u"thing\u2029> !!!else\u2029")
          w._trigger_is_complete_callback()
          self.assert_text_equal(cursor, u"thing\u2029> !!!else\u2029\u2029> ")
  
          # assert that late answer isn't destroying anything
          w._handle_is_complete_reply(
              dict(parent_header=dict(msg_id=msg_id),
                   content=dict(status="complete", indent="###")))
          self.assertEqual(calls, [])
  
      def test_complete_python(self):
          """Test that is_complete is working correctly for Python."""
          # Kernel client to test the responses of is_complete
          class TestIPyKernelClient(object):
              def is_complete(self, source):
                  tm = TransformerManager()
                  check_complete = tm.check_complete(source)
                  responses.append(check_complete)
  
          # Initialize widget
          responses = []
          w = ConsoleWidget()
          w._append_plain_text('Header\n')
          w._prompt = 'prompt>'
          w._show_prompt()
          w.kernel_client = TestIPyKernelClient()
  
          # Execute incomplete statement inside a block
          code = '\n'.join(["if True:", "    a = 1"])
          w._set_input_buffer(code)
          w.execute(interactive=True)
          assert responses == [('incomplete', 4)]
  
          # Execute complete statement inside a block
          responses = []
          code = '\n'.join(["if True:", "    a = 1\n\n"])
          w._set_input_buffer(code)
          w.execute(interactive=True)
          assert responses == [('complete', None)]
  