   selectedBufferRanges = ->
     expect editor.getSelectedBufferRanges()
 
+  set = (options={}) ->
+    if options.keystroke?
+      keystroke(options.keystroke)
+    if options.text?
+      editor.setText(options.text)
+    if options.cursor?
+      editor.setCursorScreenPosition options.cursor
+    if options.cursorBuffer?
+      editor.setCursorBufferPosition options.cursorBuffer
+    if options.addCursor?
+      editor.addCursorAtBufferPosition options.addCursor
+    if options.register?
+      vimState.register.set '"', text: options.register
+
   ensure = (_keystroke, options={}) ->
+    # input
     unless _.isEmpty(_keystroke)
-      keystroke(_keystroke)
+      if _.isArray(_keystroke)
+        for k in _keystroke
+          if _.isString(k)
+            keystroke(k)
+          else
+            if k.normal?
+              submitNormalModeInputText k.normal
+            else if k.normalChar?
+              normalModeInputKeydown k.normalChar
+            else if k.ctrl?
+              keydown k.ctrl, ctrl: true
+      else
+        keystroke(_keystroke)
+
+    # validate
+    # [NOTE] Order is important.
+    # e.g. Text need to be set before changing cursor position.
     if options.text?
       expect(editor.getText()).toBe options.text
     if options.cursor?
       expect(editor.getCursorScreenPosition()).toEqual options.cursor
+    if options.cursorBuffer?
+      expect(editor.getCursorBufferPosition()).toEqual options.cursorBuffer
     if options.register?
       expect(vimState.register.get('"').text).toBe options.register
     if options.selectedText?


    describe "as a motion", ->
      it "moves the cursor to the specified search pattern", ->
        keydown('/')

        submitNormalModeInputText 'def'

        expect(editor.getCursorBufferPosition()).toEqual [1, 0]
        expect(pane.activate).toHaveBeenCalled()

      it "loops back around", ->
        editor.setCursorBufferPosition([3, 0])
        keydown('/')
        submitNormalModeInputText 'def'

        expect(editor.getCursorBufferPosition()).toEqual [1, 0]

      it "uses a valid regex as a regex", ->
        keydown('/')
        # Cycle through the 'abc' on the first line with a character pattern
        submitNormalModeInputText '[abc]'
        expect(editor.getCursorBufferPosition()).toEqual [0, 1]
        keydown('n')
        expect(editor.getCursorBufferPosition()).toEqual [0, 2]

      it "uses an invalid regex as a literal string", ->
        # Go straight to the literal [abc
        editor.setText("abc\n[abc]\n")
        keydown('/')
        submitNormalModeInputText '[abc'
        expect(editor.getCursorBufferPosition()).toEqual [1, 0]
        keydown('n')
        expect(editor.getCursorBufferPosition()).toEqual [1, 0]

      it "uses ? as a literal string", ->
        editor.setText("abc\n[a?c?\n")
        keydown('/')
        submitNormalModeInputText '?'
        expect(editor.getCursorBufferPosition()).toEqual [1, 2]
        keydown('n')
        expect(editor.getCursorBufferPosition()).toEqual [1, 4]

      it 'works with selection in visual mode', ->
        editor.setText('one two three')
        keydown('v')
        keydown('/')
        submitNormalModeInputText 'th'
        expect(editor.getCursorBufferPosition()).toEqual [0, 9]
        keydown('d')
        expect(editor.getText()).toBe 'hree'

      it 'extends selection when repeating search in visual mode', ->
        editor.setText('line1\nline2\nline3')
        keydown('v')
        keydown('/')
        submitNormalModeInputText 'line'
        {start, end} = editor.getSelectedBufferRange()
        expect(start.row).toEqual 0

      selectedBufferRange().toEqual options.selectedBufferRange
    if options.selectedBufferRanges?
      selectedBufferRanges().toEqual options.selectedBufferRanges
    if options.scrollTop?
      expect(editor.getScrollTop()).toEqual options.scrollTop

    if options.selectedScreenRange?
      selectedScreenRange().toEqual options.selectedScreenRange
