import withCachedArguments from '../withCachedArguments'

describe('withCachedArguments', () => {
  const stub = sinon.stub()
  let testObject

  beforeEach(() => {
    testObject = {
      @withCachedArguments
      myMethod (arg1, arg2) {
        stub.call()
        return arg1.value + arg2.value
      }
    }
  })

  afterEach(() => {
    stub.resetHistory()
  })

  it('calls through to the original method', () => {
    const obj1 = {value: 1}
    const obj2 = {value: 2}
    expect(testObject.myMethod(obj1, obj2)).to.eq(3)
  })

  it('caches results of previously seen arguments', () => {
    const obj1 = {value: 1}
    const obj2 = {value: 2}
    testObject.myMethod(obj1, obj2)
    expect(testObject.myMethod(obj1, obj2)).to.eq(3)
    expect(stub.callCount).to.eq(1)
  })

  it('calls the original method more times for cache misses', () => {
    const obj1 = {value: 1}
    const obj2 = {value: 2}
    testObject.myMethod(obj1, obj2)
    expect(testObject.myMethod(obj2, obj1)).to.eq(3)
    expect(stub.callCount).to.eq(2)
  })

  it('blows up if too many or too few arguments were provided', () => {
    const obj1 = {value: 1}
    const obj2 = {value: 2}
    const obj3 = {value: 3}
    expect(() => testObject.myMethod(obj1)).to.throw()
    expect(() => testObject.myMethod(obj1, obj2, obj3)).to.throw()
  })
})
