           gutter = description.gutter
           return description if gutter.name is gutterName
 
-      describe "the array itself", ->
+      describe "the array itself, an array of gutter descriptions", ->
         it "updates when gutters are added to the editor model, and keeps the gutters sorted by priority", ->
           presenter = buildPresenter()
           gutter1 = editor.addGutter({name: 'test-gutter-1', priority: -100, visible: true})

            expectStateUpdate presenter, -> presenter.setBackgroundColor("rgba(0, 0, 255, 0)")
            expect(getStylesForGutterWithName(presenter, 'line-number').backgroundColor).toBe "rgba(0, 0, 255, 0)"
            expect(getStylesForGutterWithName(presenter, 'test-gutter').backgroundColor).toBe "rgba(0, 0, 255, 0)"

      # TODO
      describe ".customDecorations", ->
        [presenter, gutter, decorationItem, decorationParams] = []
        [marker1, decoration1, marker2, decoration2, marker3, decoration3] = []

        # Set the scrollTop to 0 to show the very top of the file.
        # Set the explicitHeight to make 10 lines visible.
        scrollTop = 0
        lineHeight = 10
        explicitHeight = lineHeight * 10
        lineOverdrawMargin = 1

        decorationStateForGutterName = (presenter, gutterName) ->
          presenter.getState().gutters.customDecorations[gutterName]

        beforeEach ->
          # At the beginning of each test, decoration1 and decoration2 are in visible range,
          # but not decoration3.
          presenter = buildPresenter({explicitHeight, scrollTop, lineHeight, lineOverdrawMargin})
          gutter = editor.addGutter({name: 'test-gutter', visible: true})
          decorationItem = document.createElement('div')
          decorationItem.class = 'decoration-item'
          decorationParams =
            type: 'gutter'
            gutterName: 'test-gutter'
            class: 'test-class'
            item: decorationItem
          marker1 = editor.markBufferRange([[0,0],[1,0]])
          decoration1 = editor.decorateMarker(marker1, decorationParams)
          marker2 = editor.markBufferRange([[9,0],[12,0]])
          decoration2 = editor.decorateMarker(marker2, decorationParams)
          marker3 = editor.markBufferRange([[13,0],[14,0]])
          decoration3 = editor.decorateMarker(marker3, decorationParams)

          # Clear any batched state updates.
          presenter.getState()

        it "contains all decorations within the visible buffer range", ->
          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id].top).toBe lineHeight * marker1.getScreenRange().start.row
          expect(decorationState[decoration1.id].height).toBe lineHeight * marker1.getScreenRange().getRowCount()
          expect(decorationState[decoration1.id].item).toBe decorationItem
          expect(decorationState[decoration1.id].class).toBe 'test-class'

          expect(decorationState[decoration2.id].top).toBe lineHeight * marker2.getScreenRange().start.row
          expect(decorationState[decoration2.id].height).toBe lineHeight * marker2.getScreenRange().getRowCount()
          expect(decorationState[decoration2.id].item).toBe decorationItem
          expect(decorationState[decoration2.id].class).toBe 'test-class'

          expect(decorationState[decoration3.id]).toBeUndefined()

        it "updates when ::scrollTop changes", ->
          # This update will scroll decoration1 out of view, and decoration3 into view.
          expectStateUpdate presenter, -> presenter.setScrollTop(scrollTop + lineHeight * 5)

          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id]).toBeUndefined()
          expect(decorationState[decoration2.id].top).toBeDefined()
          expect(decorationState[decoration3.id].top).toBeDefined()

        it "updates when ::explicitHeight changes", ->
          # This update will make all three decorations visible.
          expectStateUpdate presenter, -> presenter.setExplicitHeight(explicitHeight + lineHeight * 5)

          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id].top).toBeDefined()
          expect(decorationState[decoration2.id].top).toBeDefined()
          expect(decorationState[decoration3.id].top).toBeDefined()

        it "updates when ::lineHeight changes", ->
          # This update will make all three decorations visible.
          expectStateUpdate presenter, -> presenter.setLineHeight(Math.ceil(1.0 * explicitHeight / marker3.getBufferRange().end.row))

          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id].top).toBeDefined()
          expect(decorationState[decoration2.id].top).toBeDefined()
          expect(decorationState[decoration3.id].top).toBeDefined()

        it "updates when the editor's content changes", ->
          # This update will add enough lines to push decoration2 out of view.
          expectStateUpdate presenter, -> editor.setTextInBufferRange([[8,0],[9,0]],'\n\n\n\n\n')

          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id].top).toBeDefined()
          expect(decorationState[decoration2.id]).toBeUndefined()
          expect(decorationState[decoration3.id]).toBeUndefined()

        it "updates when a decoration's marker is modified", ->
          # This update will move decoration1 out of view.
          expectStateUpdate presenter, ->
            newRange = new Range([13,0],[14,0])
            marker1.setBufferRange(newRange)

          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id]).toBeUndefined()
          expect(decorationState[decoration2.id].top).toBeDefined()
          expect(decorationState[decoration3.id]).toBeUndefined()

        describe "when a decoration's properties are modified", ->
          it "updates the item applied to the decoration, if the decoration item is changed", ->
            # This changes the decoration class. The visibility of the decoration should not be affected.
            newItem = document.createElement('div')
            newItem.class = 'new-decoration-item'
            newDecorationParams =
              type: 'gutter'
              gutterName: 'test-gutter'
              class: 'test-class'
              item: newItem
            expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams)

            decorationState = decorationStateForGutterName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id].item).toBe newItem
            expect(decorationState[decoration2.id].item).toBe decorationItem
            expect(decorationState[decoration3.id]).toBeUndefined()

          it "updates the class applied to the decoration, if the decoration class is changed", ->
            # This changes the decoration item. The visibility of the decoration should not be affected.
            newDecorationParams =
              type: 'gutter'
              gutterName: 'test-gutter'
              class: 'new-test-class'
              item: decorationItem
            expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams)

            decorationState = decorationStateForGutterName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id].class).toBe 'new-test-class'
            expect(decorationState[decoration2.id].class).toBe 'test-class'
            expect(decorationState[decoration3.id]).toBeUndefined()

          it "updates the type of the decoration, if the decoration type is changed", ->
            # This changes the type of the decoration. This should remove the decoration from the gutter.
            newDecorationParams =
              type: 'line'
              gutterName: 'test-gutter' # This is an invalid/meaningless option here, but it shouldn't matter.
              class: 'test-class'
              item: decorationItem
            expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams)

            decorationState = decorationStateForGutterName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id]).toBeUndefined()
            expect(decorationState[decoration2.id].top).toBeDefined()
            expect(decorationState[decoration3.id]).toBeUndefined()

          it "updates the gutter the decoration targets, if the decoration gutterName is changed", ->
            # This changes which gutter this decoration applies to. Since this gutter does not exist,
            # the decoration should not appear in the customDecorations state.
            newDecorationParams =
              type: 'gutter'
              gutterName: 'test-gutter-2'
              class: 'new-test-class'
              item: decorationItem
            expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams)

            decorationState = decorationStateForGutterName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id]).toBeUndefined()
            expect(decorationState[decoration2.id].top).toBeDefined()
            expect(decorationState[decoration3.id]).toBeUndefined()

            # After adding the targeted gutter, the decoration will appear in the state for that gutter,
            # since it should be visible.
            expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'})
            newGutterDecorationState = decorationStateForGutterName(presenter, 'test-gutter-2')
            expect(newGutterDecorationState[decoration1.id].top).toBeDefined()
            expect(newGutterDecorationState[decoration2.id]).toBeUndefined()
            expect(newGutterDecorationState[decoration3.id]).toBeUndefined()
            oldGutterDecorationState = decorationStateForGutterName(presenter, 'test-gutter')
            expect(oldGutterDecorationState[decoration1.id]).toBeUndefined()
            expect(oldGutterDecorationState[decoration2.id].top).toBeDefined()
            expect(oldGutterDecorationState[decoration3.id]).toBeUndefined()

        it "updates when the editor's mini state changes, and is cleared when the editor is mini", ->
          expectStateUpdate presenter, -> editor.setMini(true)
          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState).toBeUndefined()

          # The decorations should return to the original state.
          expectStateUpdate presenter, -> editor.setMini(false)
          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id].top).toBeDefined()
          expect(decorationState[decoration2.id].top).toBeDefined()
          expect(decorationState[decoration3.id]).toBeUndefined()

        it "updates when a gutter's visibility changes, and is cleared when the gutter is not visible", ->
          expectStateUpdate presenter, -> gutter.hide()
          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id]).toBeUndefined()
          expect(decorationState[decoration2.id]).toBeUndefined()
          expect(decorationState[decoration3.id]).toBeUndefined()

          # The decorations should return to the original state.
          expectStateUpdate presenter, -> gutter.show()
          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id].top).toBeDefined()
          expect(decorationState[decoration2.id].top).toBeDefined()
          expect(decorationState[decoration3.id]).toBeUndefined()

        it "updates when a gutter is added to the editor", ->
          decorationParams =
            type: 'gutter'
            gutterName: 'test-gutter-2'
            class: 'test-class'
          marker4 = editor.markBufferRange([[0,0],[1,0]])
          decoration4 = editor.decorateMarker(marker4, decorationParams)
          expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'})

          decorationState = decorationStateForGutterName(presenter, 'test-gutter-2')
          expect(decorationState[decoration1.id]).toBeUndefined()
          expect(decorationState[decoration2.id]).toBeUndefined()
          expect(decorationState[decoration3.id]).toBeUndefined()
          expect(decorationState[decoration4.id].top).toBeDefined()

        it "updates when editor lines are folded", ->
          oldDimensionsForDecoration1 =
            top: lineHeight * marker1.getScreenRange().start.row
            height: lineHeight * marker1.getScreenRange().getRowCount()
          oldDimensionsForDecoration2 =
            top: lineHeight * marker2.getScreenRange().start.row
            height: lineHeight * marker2.getScreenRange().getRowCount()

          # Based on the contents of sample.js, this should affect all but the top
          # part of decoration1.
          expectStateUpdate presenter, -> editor.foldBufferRow(0)

          decorationState = decorationStateForGutterName(presenter, 'test-gutter')
          expect(decorationState[decoration1.id].top).toBe oldDimensionsForDecoration1.top
          expect(decorationState[decoration1.id].height).not.toBe oldDimensionsForDecoration1.height
          # Due to the issue described here: https://github.com/atom/atom/issues/6454, decoration2
          # will be bumped up to the row that was folded and still made visible, instead of being
          # entirely collapsed. (The same thing will happen to decoration3.)
          expect(decorationState[decoration2.id].top).not.toBe oldDimensionsForDecoration2.top
          expect(decorationState[decoration2.id].height).not.toBe oldDimensionsForDecoration2.height

  # disabled until we fix an issue with display buffer markers not updating when
  # they are moved on screen but not in the buffer

          gutter.destroy()
          expect(getStateForGutterWithName(presenter, 'test-gutter')).toBeUndefined()

      describe "for a gutter description that corresponds to a custom gutter", ->
        describe ".content", ->
          getContentForGutterWithName = (presenter, gutterName) ->
            fullState = getStateForGutterWithName(presenter, gutterName)
            return fullState.content if fullState

          [presenter, gutter, decorationItem, decorationParams] = []
          [marker1, decoration1, marker2, decoration2, marker3, decoration3] = []

          # Set the scrollTop to 0 to show the very top of the file.
          # Set the explicitHeight to make 10 lines visible.
          scrollTop = 0
          lineHeight = 10
          explicitHeight = lineHeight * 10
          lineOverdrawMargin = 1

          beforeEach ->
            # At the beginning of each test, decoration1 and decoration2 are in visible range,
            # but not decoration3.
            presenter = buildPresenter({explicitHeight, scrollTop, lineHeight, lineOverdrawMargin})
            gutter = editor.addGutter({name: 'test-gutter', visible: true})
            decorationItem = document.createElement('div')
            decorationItem.class = 'decoration-item'
            decorationParams =
              type: 'gutter'
              gutterName: 'test-gutter'
              class: 'test-class'
              item: decorationItem
            marker1 = editor.markBufferRange([[0,0],[1,0]])
            decoration1 = editor.decorateMarker(marker1, decorationParams)
            marker2 = editor.markBufferRange([[9,0],[12,0]])
            decoration2 = editor.decorateMarker(marker2, decorationParams)
            marker3 = editor.markBufferRange([[13,0],[14,0]])
            decoration3 = editor.decorateMarker(marker3, decorationParams)

            # Clear any batched state updates.
            presenter.getState()

          it "contains all decorations within the visible buffer range", ->
            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id].top).toBe lineHeight * marker1.getScreenRange().start.row
            expect(decorationState[decoration1.id].height).toBe lineHeight * marker1.getScreenRange().getRowCount()
            expect(decorationState[decoration1.id].item).toBe decorationItem
            expect(decorationState[decoration1.id].class).toBe 'test-class'

            expect(decorationState[decoration2.id].top).toBe lineHeight * marker2.getScreenRange().start.row
            expect(decorationState[decoration2.id].height).toBe lineHeight * marker2.getScreenRange().getRowCount()
            expect(decorationState[decoration2.id].item).toBe decorationItem
            expect(decorationState[decoration2.id].class).toBe 'test-class'

            expect(decorationState[decoration3.id]).toBeUndefined()

          it "updates when ::scrollTop changes", ->
            # This update will scroll decoration1 out of view, and decoration3 into view.
            expectStateUpdate presenter, -> presenter.setScrollTop(scrollTop + lineHeight * 5)

            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id]).toBeUndefined()
            expect(decorationState[decoration2.id].top).toBeDefined()
            expect(decorationState[decoration3.id].top).toBeDefined()

          it "updates when ::explicitHeight changes", ->
            # This update will make all three decorations visible.
            expectStateUpdate presenter, -> presenter.setExplicitHeight(explicitHeight + lineHeight * 5)

            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id].top).toBeDefined()
            expect(decorationState[decoration2.id].top).toBeDefined()
            expect(decorationState[decoration3.id].top).toBeDefined()

          it "updates when ::lineHeight changes", ->
            # This update will make all three decorations visible.
            expectStateUpdate presenter, -> presenter.setLineHeight(Math.ceil(1.0 * explicitHeight / marker3.getBufferRange().end.row))

            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id].top).toBeDefined()
            expect(decorationState[decoration2.id].top).toBeDefined()
            expect(decorationState[decoration3.id].top).toBeDefined()

          it "updates when the editor's content changes", ->
            # This update will add enough lines to push decoration2 out of view.
            expectStateUpdate presenter, -> editor.setTextInBufferRange([[8,0],[9,0]],'\n\n\n\n\n')

            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id].top).toBeDefined()
            expect(decorationState[decoration2.id]).toBeUndefined()
            expect(decorationState[decoration3.id]).toBeUndefined()

          it "updates when a decoration's marker is modified", ->
            # This update will move decoration1 out of view.
            expectStateUpdate presenter, ->
              newRange = new Range([13,0],[14,0])
              marker1.setBufferRange(newRange)

            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id]).toBeUndefined()
            expect(decorationState[decoration2.id].top).toBeDefined()
            expect(decorationState[decoration3.id]).toBeUndefined()

          describe "when a decoration's properties are modified", ->
            it "updates the item applied to the decoration, if the decoration item is changed", ->
              # This changes the decoration class. The visibility of the decoration should not be affected.
              newItem = document.createElement('div')
              newItem.class = 'new-decoration-item'
              newDecorationParams =
                type: 'gutter'
                gutterName: 'test-gutter'
                class: 'test-class'
                item: newItem
              expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams)

              decorationState = getContentForGutterWithName(presenter, 'test-gutter')
              expect(decorationState[decoration1.id].item).toBe newItem
              expect(decorationState[decoration2.id].item).toBe decorationItem
              expect(decorationState[decoration3.id]).toBeUndefined()

            it "updates the class applied to the decoration, if the decoration class is changed", ->
              # This changes the decoration item. The visibility of the decoration should not be affected.
              newDecorationParams =
                type: 'gutter'
                gutterName: 'test-gutter'
                class: 'new-test-class'
                item: decorationItem
              expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams)

              decorationState = getContentForGutterWithName(presenter, 'test-gutter')
              expect(decorationState[decoration1.id].class).toBe 'new-test-class'
              expect(decorationState[decoration2.id].class).toBe 'test-class'
              expect(decorationState[decoration3.id]).toBeUndefined()

            it "updates the type of the decoration, if the decoration type is changed", ->
              # This changes the type of the decoration. This should remove the decoration from the gutter.
              newDecorationParams =
                type: 'line'
                gutterName: 'test-gutter' # This is an invalid/meaningless option here, but it shouldn't matter.
                class: 'test-class'
                item: decorationItem
              expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams)

              decorationState = getContentForGutterWithName(presenter, 'test-gutter')
              expect(decorationState[decoration1.id]).toBeUndefined()
              expect(decorationState[decoration2.id].top).toBeDefined()
              expect(decorationState[decoration3.id]).toBeUndefined()

            it "updates the gutter the decoration targets, if the decoration gutterName is changed", ->
              # This changes which gutter this decoration applies to. Since this gutter does not exist,
              # the decoration should not appear in the customDecorations state.
              newDecorationParams =
                type: 'gutter'
                gutterName: 'test-gutter-2'
                class: 'new-test-class'
                item: decorationItem
              expectStateUpdate presenter, -> decoration1.setProperties(newDecorationParams)

              decorationState = getContentForGutterWithName(presenter, 'test-gutter')
              expect(decorationState[decoration1.id]).toBeUndefined()
              expect(decorationState[decoration2.id].top).toBeDefined()
              expect(decorationState[decoration3.id]).toBeUndefined()

              # After adding the targeted gutter, the decoration will appear in the state for that gutter,
              # since it should be visible.
              expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'})
              newGutterDecorationState = getContentForGutterWithName(presenter, 'test-gutter-2')
              expect(newGutterDecorationState[decoration1.id].top).toBeDefined()
              expect(newGutterDecorationState[decoration2.id]).toBeUndefined()
              expect(newGutterDecorationState[decoration3.id]).toBeUndefined()
              oldGutterDecorationState = getContentForGutterWithName(presenter, 'test-gutter')
              expect(oldGutterDecorationState[decoration1.id]).toBeUndefined()
              expect(oldGutterDecorationState[decoration2.id].top).toBeDefined()
              expect(oldGutterDecorationState[decoration3.id]).toBeUndefined()

          it "updates when the editor's mini state changes, and is cleared when the editor is mini", ->
            expectStateUpdate presenter, -> editor.setMini(true)
            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState).toBeUndefined()

            # The decorations should return to the original state.
            expectStateUpdate presenter, -> editor.setMini(false)
            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id].top).toBeDefined()
            expect(decorationState[decoration2.id].top).toBeDefined()
            expect(decorationState[decoration3.id]).toBeUndefined()

          it "updates when a gutter's visibility changes, and is cleared when the gutter is not visible", ->
            expectStateUpdate presenter, -> gutter.hide()
            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id]).toBeUndefined()
            expect(decorationState[decoration2.id]).toBeUndefined()
            expect(decorationState[decoration3.id]).toBeUndefined()

            # The decorations should return to the original state.
            expectStateUpdate presenter, -> gutter.show()
            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id].top).toBeDefined()
            expect(decorationState[decoration2.id].top).toBeDefined()
            expect(decorationState[decoration3.id]).toBeUndefined()

          it "updates when a gutter is added to the editor", ->
            decorationParams =
              type: 'gutter'
              gutterName: 'test-gutter-2'
              class: 'test-class'
            marker4 = editor.markBufferRange([[0,0],[1,0]])
            decoration4 = editor.decorateMarker(marker4, decorationParams)
            expectStateUpdate presenter, -> editor.addGutter({name: 'test-gutter-2'})

            decorationState = getContentForGutterWithName(presenter, 'test-gutter-2')
            expect(decorationState[decoration1.id]).toBeUndefined()
            expect(decorationState[decoration2.id]).toBeUndefined()
            expect(decorationState[decoration3.id]).toBeUndefined()
            expect(decorationState[decoration4.id].top).toBeDefined()

          it "updates when editor lines are folded", ->
            oldDimensionsForDecoration1 =
              top: lineHeight * marker1.getScreenRange().start.row
              height: lineHeight * marker1.getScreenRange().getRowCount()
            oldDimensionsForDecoration2 =
              top: lineHeight * marker2.getScreenRange().start.row
              height: lineHeight * marker2.getScreenRange().getRowCount()

            # Based on the contents of sample.js, this should affect all but the top
            # part of decoration1.
            expectStateUpdate presenter, -> editor.foldBufferRow(0)

            decorationState = getContentForGutterWithName(presenter, 'test-gutter')
            expect(decorationState[decoration1.id].top).toBe oldDimensionsForDecoration1.top
            expect(decorationState[decoration1.id].height).not.toBe oldDimensionsForDecoration1.height
            # Due to the issue described here: https://github.com/atom/atom/issues/6454, decoration2
            # will be bumped up to the row that was folded and still made visible, instead of being
            # entirely collapsed. (The same thing will happen to decoration3.)
            expect(decorationState[decoration2.id].top).not.toBe oldDimensionsForDecoration2.top
            expect(decorationState[decoration2.id].height).not.toBe oldDimensionsForDecoration2.height

      describe "regardless of what kind of gutter a gutter description corresponds to", ->
        [customGutter] = []
