{Collection, Model} = window?.Backbone or require 'backbone'
{Capped, Filtered,
  Sorted, Reversed} = window?.BackboneProjections or require '../index'
{equal, deepEqual, ok} = window?.assert or require 'assert'

describe 'Capped', ->

  describe 'initialization from a collection', ->

    underlying = new Collection [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    assertUnderlying = (underlying) ->
      equal underlying.length, 4
      equal underlying.at(0).get('a'), 1
      equal underlying.at(1).get('a'), 2
      equal underlying.at(2).get('a'), 3
      equal underlying.at(3).get('a'), 4

    it 'caps a collection', ->
      c = new Capped(underlying, cap: 2)
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(1).get('a'), 2
      equal c.at(2), undefined
      assertUnderlying(underlying)

    it 'uses a comparator if provided', ->
      c = new Capped underlying,
        cap: 2
        comparator: (model) -> model.get('b')
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 1
      equal c.at(2), undefined
      assertUnderlying(underlying)

  describe 'responding to an underlying reset event', ->

    underlyingItems = [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    assertUnderlying = (underlying) ->
      equal underlying.length, 4
      equal underlying.at(0).get('a'), 1
      equal underlying.at(1).get('a'), 2
      equal underlying.at(2).get('a'), 3
      equal underlying.at(3).get('a'), 4

    it 'caps on reset', ->
      underlying = new Collection []
      c = new Capped(underlying, cap: 2)
      equal c.length, 0
      underlying.reset(underlyingItems)
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(1).get('a'), 2
      equal c.at(2), undefined
      assertUnderlying(underlying)

    it 'uses a comparator if provided', ->
      underlying = new Collection []
      c = new Capped underlying,
        cap: 2
        comparator: (model) -> model.get('b')
      equal c.length, 0
      underlying.reset(underlyingItems)
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 1
      equal c.at(2), undefined
      assertUnderlying(underlying)

  describe 'responding to an underlying add event', ->

    it 'responds to an add event', ->
      underlying = new Collection []
      c = new Capped(underlying, cap: 2)
      equal c.length, 0

      underlying.add {a: 1}
      equal underlying.length, 1
      equal c.length, 1

      underlying.add [{a: 2}, {a: 3}]
      equal underlying.length, 3
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(0).get('a'), underlying.at(0).get('a')
      equal c.at(1).get('a'), 2
      equal c.at(1).get('a'), underlying.at(1).get('a')
      equal c.at(2), undefined

      underlying.add {a: 4}, at: 1
      equal underlying.length, 4
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(0).get('a'), underlying.at(0).get('a')
      equal c.at(1).get('a'), 4
      equal c.at(1).get('a'), underlying.at(1).get('a')

      underlying.add {a: 5}, at: 0
      equal underlying.length, 5
      equal c.length, 2
      equal c.at(0).get('a'), 5
      equal c.at(0).get('a'), underlying.at(0).get('a')
      equal c.at(1).get('a'), 1
      equal c.at(1).get('a'), underlying.at(1).get('a')

    it 'responds to an add event w/ comparator provided', ->
      underlying = new Collection []
      c = new Capped underlying,
        cap: 2
        comparator: (model) -> model.get('b')
      equal c.length, 0

      underlying.add {a: 1, b: 3}
      equal underlying.length, 1
      equal c.length, 1

      underlying.add [{a: 2, b: 1}, {a: 3, b: 2}]
      equal underlying.length, 3
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3

      underlying.add {a: 4, b: 4}, at: 1
      equal underlying.length, 4
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3

      underlying.add {a: 5, b: 1.5}, at: 0
      equal underlying.length, 5
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 5

  describe 'responding to an underlying remove event', ->

    it 'responds to an remove event', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Capped(underlying, cap: 2)
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(0).get('a'), underlying.at(0).get('a')
      equal c.at(1).get('a'), 2
      equal c.at(1).get('a'), underlying.at(1).get('a')

      underlying.remove(underlying.at(2))
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(0).get('a'), underlying.at(0).get('a')
      equal c.at(1).get('a'), 2
      equal c.at(1).get('a'), underlying.at(1).get('a')

      underlying.remove(underlying.at(0))
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(0).get('a'), underlying.at(0).get('a')
      equal c.at(1).get('a'), 4
      equal c.at(1).get('a'), underlying.at(1).get('a')

    it 'responds to a remove event w/ comparator provided', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Capped underlying,
        cap: 2
        comparator: (model) -> model.get('b')
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 1

      underlying.remove(underlying.at(2))
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(1).get('a'), 2

      underlying.remove(underlying.at(1))
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(1).get('a'), 4

  describe 'handling of an underlying sort event', ->

    underlyingItems = [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    it 'responds to a sort event if no comparator is provided', ->
      underlying = new Collection [],
        comparator: (model) -> model.get('b')
      underlying.add underlyingItems, sort: false
      c = new Capped underlying, cap: 2
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(0).get('a'), underlying.at(0).get('a')
      equal c.at(1).get('a'), 2
      equal c.at(1).get('a'), underlying.at(1).get('a')
      underlying.sort()
      equal c.at(0).get('a'), 3
      equal c.at(0).get('a'), underlying.at(0).get('a')
      equal c.at(1).get('a'), 1
      equal c.at(1).get('a'), underlying.at(1).get('a')

    it 'ignores a sort event if comparator is provided', ->
      underlying = new Collection [],
        comparator: (model) -> model.get('b')
      underlying.add underlyingItems, sort: false
      c = new Capped underlying,
        cap: 2
        comparator: (model) -> model.get('b')
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 1
      underlying.sort()
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 1

  describe 'resizing', ->

    it 'upsizes', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Capped underlying, cap: 2
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(1).get('a'), 2
      c.resize(4)
      equal c.length, 4
      equal c.at(0).get('a'), 1
      equal c.at(1).get('a'), 2
      equal c.at(2).get('a'), 3
      equal c.at(3).get('a'), 4

    it 'upsizes w/ comparator', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Capped underlying,
        cap: 2
        comparator: (model) -> model.get('b')
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 1
      c.resize(4)
      equal c.length, 4
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 1
      equal c.at(2).get('a'), 2
      equal c.at(3).get('a'), 4

    it 'downsizes', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Capped underlying, cap: 2
      equal c.length, 2
      equal c.at(0).get('a'), 1
      equal c.at(1).get('a'), 2
      c.resize(1)
      equal c.length, 1
      equal c.at(0).get('a'), 1

    it 'downsizes w/ comparator', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Capped underlying,
        cap: 2
        comparator: (model) -> model.get('b')
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 1
      c.resize(1)
      equal c.length, 1
      equal c.at(0).get('a'), 3

describe 'Filtered', ->

  describe 'initialization from a collection', ->

    underlying = new Collection [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    assertUnderlying = (underlying) ->
      equal underlying.length, 4
      equal underlying.at(0).get('a'), 1
      equal underlying.at(1).get('a'), 2
      equal underlying.at(2).get('a'), 3
      equal underlying.at(3).get('a'), 4

    it 'filters a collection', ->
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3
      equal c.at(2), undefined
      assertUnderlying(underlying)

    it 'uses a comparator if provided', ->
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
        comparator: (model) -> model.get('b')
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 2
      equal c.at(2), undefined
      assertUnderlying(underlying)

  describe 'responding to an underlying reset event', ->

    underlyingItems = [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    assertUnderlying = (underlying) ->
      equal underlying.length, 4
      equal underlying.at(0).get('a'), 1
      equal underlying.at(1).get('a'), 2
      equal underlying.at(2).get('a'), 3
      equal underlying.at(3).get('a'), 4

    it 'filters on reset', ->
      underlying = new Collection []
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
      equal c.length, 0
      underlying.reset(underlyingItems)
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3
      equal c.at(2), undefined
      assertUnderlying(underlying)

    it 'uses a comparator if provided', ->
      underlying = new Collection []
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
        comparator: (model) -> model.get('b')
      equal c.length, 0
      underlying.reset(underlyingItems)
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 2
      equal c.at(2), undefined
      assertUnderlying(underlying)

  describe 'responding to an underlying remove event', ->

    it 'responds to an remove event', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3

      underlying.remove(underlying.at(2))
      equal c.length, 1
      equal c.at(0).get('a'), 2

      underlying.remove(underlying.at(0))
      equal c.length, 1
      equal c.at(0).get('a'), 2

    it 'responds to a remove event w/ comparator provided', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
        comparator: (model) -> model.get('b')
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 2

      underlying.remove(underlying.at(2))
      equal c.length, 1
      equal c.at(0).get('a'), 2

      underlying.remove(underlying.at(1))
      equal c.length, 0

  describe 'responding to an underlying add event', ->

    it 'responds to an add event', ->
      underlying = new Collection []
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
      equal c.length, 0

      underlying.add {a: 1}
      equal underlying.length, 1
      equal c.length, 0

      underlying.add [{a: 2}, {a: 3}]
      equal underlying.length, 3
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3
      equal c.at(2), undefined

      underlying.add {a: 4}, at: 1
      equal underlying.length, 4
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3

    it 'responds to an add event w/ comparator provided', ->
      underlying = new Collection []
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
        comparator: (model) -> model.get('b')
      equal c.length, 0

      underlying.add {a: 1, b: 3}
      equal underlying.length, 1
      equal c.length, 0

      underlying.add [{a: 2, b: 1}, {a: 3, b: 2}]
      equal underlying.length, 3
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3

      underlying.add {a: 4, b: 4}, at: 1
      equal underlying.length, 4
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3

  describe 'handling model change events', ->

    it 'responds to an underlying change event', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
      equal c.length, 2
      underlying.at(0).set('a', 1.5)
      equal c.length, 3
      equal c.at(0).get('a'), 1.5
      equal c.at(1).get('a'), 2
      equal c.at(2).get('a'), 3
      underlying.at(1).set('a', 5)
      equal c.length, 2
      equal c.at(0).get('a'), 1.5
      equal c.at(1).get('a'), 3

    it 'responds to an underlying change event w/ comparator', ->
      underlying = new Collection [
        {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
      ]
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
        comparator: (model) -> model.get('b')
      equal c.length, 2
      underlying.at(0).set('a', 1.5)
      equal c.length, 3
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 1.5
      equal c.at(2).get('a'), 2
      underlying.at(2).set('a', 5)
      equal c.length, 2
      equal c.at(0).get('a'), 1.5
      equal c.at(1).get('a'), 2

  describe 'handling of an underlying sort event', ->

    underlyingItems = [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    it 'responds to a sort event if no comparator is provided', ->
      underlying = new Collection [],
        comparator: (model) -> model.get('b')
      underlying.add underlyingItems, sort: false
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
      equal c.length, 2
      equal c.at(0).get('a'), 2
      equal c.at(1).get('a'), 3
      underlying.sort()
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 2

    it 'ignores a sort event if comparator is provided', ->
      underlying = new Collection [],
        comparator: (model) -> model.get('b')
      underlying.add underlyingItems, sort: false
      c = new Filtered underlying,
        filter: (model) -> model.get('a') < 4 and model.get('a') > 1
        comparator: (model) -> model.get('b')
      equal c.length, 2
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 2
      underlying.sort()
      equal c.at(0).get('a'), 3
      equal c.at(1).get('a'), 2

  describe 'implementation of a difference between two collections', ->

    class Difference extends Filtered
      constructor: (underlying, subtrahend, options = {}) ->
        options.filter = (model) -> not subtrahend.contains(model)
        super(underlying, options)
        this.listenTo subtrahend, 'add remove reset', this.update.bind(this)

    a = new Model()
    b = new Model()
    c = new Model()
    d = new Model()

    underlying = new Collection [a, b, c]
    subtrahend = new Collection [b, c, d]

    diff = new Difference(underlying, subtrahend)

    it 'contains models from minuend', ->
      equal diff.length, 1
      ok diff.contains(a)

    it 'does not contain models from subtrahend', ->
      ok not diff.contains(b)
      ok not diff.contains(c)

    it 'updates on changes in subtrahend', ->
      subtrahend.remove(b)
      equal diff.length, 2
      ok diff.contains(b)

      subtrahend.add(a)
      equal diff.length, 1
      ok not diff.contains(a)

      subtrahend.reset([d])
      equal diff.length, 3
      ok diff.contains(a)
      ok diff.contains(b)
      ok diff.contains(c)

  describe 'implementation of an efficient difference between two collections', ->

    class EfficientDifference extends Filtered
      constructor: (underlying, subtrahend, options = {}) ->
        options.filter = (model) -> not subtrahend.contains(model)
        super(underlying, options)
        this.listenTo subtrahend,
          add: (model) =>
            this.remove(model) if this.contains(model)
          remove: (model) =>
            this.add(model) if this.underlying.contains(model)
          reset: this.update.bind(this)

    a = new Model()
    b = new Model()
    c = new Model()
    d = new Model()

    underlying = new Collection [a, b, c]
    subtrahend = new Collection [b, c, d]

    diff = new EfficientDifference(underlying, subtrahend)

    it 'contains models from minuend', ->
      equal diff.length, 1
      ok diff.contains(a)

    it 'does not contain models from subtrahend', ->
      ok not diff.contains(b)
      ok not diff.contains(c)

    it 'updates on changes in subtrahend', ->
      subtrahend.remove(b)
      equal diff.length, 2
      ok diff.contains(b)

      subtrahend.add(a)
      equal diff.length, 1
      ok not diff.contains(a)

      subtrahend.reset([d])
      equal diff.length, 3
      ok diff.contains(a)
      ok diff.contains(b)
      ok diff.contains(c)

describe 'Sorted', ->

  it 'initializes from a collection', ->

    underlying = new Collection [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    assertUnderlying = (underlying) ->
      equal underlying.length, 4
      equal underlying.at(0).get('a'), 1
      equal underlying.at(1).get('a'), 2
      equal underlying.at(2).get('a'), 3
      equal underlying.at(3).get('a'), 4

    c = new Sorted underlying,
      comparator: (model) -> model.get('b')
    equal c.length, 4
    equal c.at(0).get('a'), 3
    equal c.at(1).get('a'), 1
    equal c.at(2).get('a'), 2
    equal c.at(3).get('a'), 4
    assertUnderlying(underlying)

  it 'responds to an underlying reset event', ->

    underlyingItems = [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    assertUnderlying = (underlying) ->
      equal underlying.length, 4
      equal underlying.at(0).get('a'), 1
      equal underlying.at(1).get('a'), 2
      equal underlying.at(2).get('a'), 3
      equal underlying.at(3).get('a'), 4

    underlying = new Collection []
    c = new Sorted underlying,
      comparator: (model) -> model.get('b')
    equal c.length, 0
    underlying.reset(underlyingItems)
    equal c.length, 4
    equal c.at(0).get('a'), 3
    equal c.at(1).get('a'), 1
    equal c.at(2).get('a'), 2
    equal c.at(3).get('a'), 4
    assertUnderlying(underlying)

  it 'responds to an underlying remove event', ->
    underlying = new Collection [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]
    c = new Sorted underlying,
      comparator: (model) -> model.get('b')
    equal c.length, 4
    equal c.at(0).get('a'), 3
    equal c.at(1).get('a'), 1
    equal c.at(2).get('a'), 2
    equal c.at(3).get('a'), 4

    underlying.remove(underlying.at(2))
    equal c.length, 3
    equal c.at(0).get('a'), 1
    equal c.at(1).get('a'), 2
    equal c.at(2).get('a'), 4

    underlying.remove(underlying.at(0))
    equal c.length, 2
    equal c.at(0).get('a'), 2
    equal c.at(1).get('a'), 4

  it 'responds to an underlying add event', ->
    underlying = new Collection []
    c = new Sorted underlying,
      comparator: (model) -> model.get('b')
    equal c.length, 0

    underlying.add {a: 1, b: 2}
    equal underlying.length, 1
    equal c.length, 1

    underlying.add [{a: 2, b: 3}, {a: 3, b: 1}]
    equal underlying.length, 3
    equal c.length, 3
    equal c.at(0).get('a'), 3
    equal c.at(1).get('a'), 1
    equal c.at(2).get('a'), 2

    underlying.add {a: 4, b: 4}, at: 1
    equal underlying.length, 4
    equal c.length, 4
    equal c.at(0).get('a'), 3
    equal c.at(1).get('a'), 1
    equal c.at(2).get('a'), 2
    equal c.at(3).get('a'), 4

describe 'Reversed', ->

  it 'initializes from a collection', ->

    underlying = new Collection [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    assertUnderlying = (underlying) ->
      equal underlying.length, 4
      equal underlying.at(0).get('a'), 1
      equal underlying.at(1).get('a'), 2
      equal underlying.at(2).get('a'), 3
      equal underlying.at(3).get('a'), 4

    c = new Reversed(underlying)
    equal c.length, 4
    equal c.at(0).get('a'), 4
    equal c.at(1).get('a'), 3
    equal c.at(2).get('a'), 2
    equal c.at(3).get('a'), 1
    assertUnderlying(underlying)

  it 'responds to an underlying reset event', ->

    underlyingItems = [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    assertUnderlying = (underlying) ->
      equal underlying.length, 4
      equal underlying.at(0).get('a'), 1
      equal underlying.at(1).get('a'), 2
      equal underlying.at(2).get('a'), 3
      equal underlying.at(3).get('a'), 4

    underlying = new Collection []
    c = new Reversed(underlying)
    equal c.length, 0
    underlying.reset(underlyingItems)
    equal c.length, 4
    equal c.at(0).get('a'), 4
    equal c.at(1).get('a'), 3
    equal c.at(2).get('a'), 2
    equal c.at(3).get('a'), 1
    assertUnderlying(underlying)

  it 'responds to an underlying remove event', ->
    underlying = new Collection [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]
    c = new Reversed(underlying)
    equal c.length, 4
    equal c.at(0).get('a'), 4
    equal c.at(1).get('a'), 3
    equal c.at(2).get('a'), 2
    equal c.at(3).get('a'), 1

    underlying.remove(underlying.at(2))
    equal c.length, 3
    equal c.at(0).get('a'), 4
    equal c.at(1).get('a'), 2
    equal c.at(2).get('a'), 1

    underlying.remove(underlying.at(0))
    equal c.length, 2
    equal c.at(0).get('a'), 4
    equal c.at(1).get('a'), 2

  it 'responds to an underlying add event', ->
    underlying = new Collection []
    c = new Reversed(underlying)
    equal c.length, 0

    underlying.add {a: 1, b: 2}
    equal underlying.length, 1
    equal c.length, 1

    underlying.add [{a: 2, b: 3}, {a: 3, b: 1}]
    equal underlying.length, 3
    equal c.length, 3
    equal c.at(0).get('a'), 3
    equal c.at(1).get('a'), 2
    equal c.at(2).get('a'), 1

    underlying.add {a: 4, b: 4}
    equal underlying.length, 4
    equal c.length, 4
    equal c.at(0).get('a'), 4
    equal c.at(1).get('a'), 3
    equal c.at(2).get('a'), 2
    equal c.at(3).get('a'), 1

  it 'responds to an underlying sort event', ->

    underlyingItems = [
      {a: 1, b: 2}, {a: 2, b: 3}, {a: 3, b: 1}, {a: 4, b: 4}
    ]

    underlying = new Collection [],
      comparator: (model) -> model.get('b')
    underlying.add underlyingItems, sort: false
    c = new Reversed(underlying)
    equal c.length, 4
    equal c.at(0).get('a'), 4
    equal c.at(1).get('a'), 3
    equal c.at(2).get('a'), 2
    equal c.at(3).get('a'), 1
    underlying.sort()
    equal c.at(0).get('a'), 4
    equal c.at(1).get('a'), 2
    equal c.at(2).get('a'), 1
    equal c.at(3).get('a'), 3
