describe('Stash::Item', function () {
  var pool = new Stash.Pool();
  var driver = pool.drivers[0];
  var foo = pool.getItem('foo');

  context('#_calculateExpiration_', function () {
    it('should return false for false expiration', function () {
      expect(Stash.Item._calculateExpiration_(false)).to.be.false;
    });

    it('should return the time for Date values', function () {
      var date = new Date();

      expect(Stash.Item._calculateExpiration_(date))
        .to.be.equal(date.getTime());
    });

    it('should increase Date.now by seconds', function () {
      var date = Date.now() + 100 * 1000;

      expect(Stash.Item._calculateExpiration_(100) - date)
        .to.be.lt(100);
    });
  });

  context('#get', function () {
    it('should return null if no data is saved', function (done) {
      foo.get().then(function (data) {
        catching(done, function () {
          expect(data).to.be.null;
        });
      });
    });

    it('should use SP_NONE as default cache policy', function (done) {
      foo.get().then(function () {
        catching(done, function () {
          expect(foo.cachePolicy).to.be.equal(Stash.Item.SP_NONE);
        });
      });
    });

    it('should call callback with data', function (done) {
      foo.set('bar')
      .then(function () {
        return foo.get();
      })
      .then(function (data) {
        catching(done, function () {
          expect(data).to.be.equal('bar');
        });
      });
    });
  });

  context('#set', function () {
    it('should set a value to an item', function (done) {
      foo.set('bar').then(function () {
        return foo.get();
      })
      .then(function (data) {
          expect(data).to.be.equal('bar');
          done();
      });
    });

    it('should unlock cache', function (done) {
      foo.lock().then(function () {
        return foo.set('baz');
      }).then(function () {
        return foo.isLocked(foo.key);
      }).then(function (locked) {
        catching(done, function () {
          expect(locked).to.be.false;
        });
      });
    });

    it('should call the callback', function (done) {
      foo.set('baz')
      .then(function (err) {
        catching(done, function () {});
      });
    });
  });

  context('#isMiss', function () {
    it('should return true if cache is expired', function (done) {
      foo.set('bar', -1)
      .then(function () {
        return foo.isMiss();
      })
      .then(function (missed) {
        catching(done, function () {
          expect(missed).to.be.true;
        });
      });
    });

    it('should return false when it is still valid', function (done) {
      foo.set('bar', 100)
      .then(function () {
        return foo.isMiss();
      })
      .then(function (missed) {
        catching(done, function () {
          expect(missed).to.be.false;
        });
      })
    });

    it('should accept an expiration Date', function () {
      foo.set('bar', new Date(Date.now() + 1000));
      expect(foo.isMiss()).to.be.false;

      foo.set('bar', new Date(Date.now() - 100));
      expect(foo.isMiss()).to.be.true;
    });

    context('Expired & Locked', function () {
      context('SP_NONE', function (done) {
        it('should be the default cache policy', function () {
          foo.get()
          .then(function () {
            catching(done, function () {
              expect(foo.cachePolicy).to.be.equal(Stash.Item.SP_NONE);
            });
          });
        });

        it('should return true', function (done) {
          foo.set('bar', -1).then(function () {
            return foo.lock();
          }).then(function () {
            return foo.get(Stash.Item.SP_NONE);
          }).then(function () {
            return foo.isMiss();
          }).then(function (missed) {
            catching(done, function () {
              expect(missed).to.be.true;
            });
          });
        });
      });

      context('SP_OLD', function (done) {
        it('should return false if cache is locked', function () {
          foo.lock().then(function () {
            return foo.get(Stash.Item.SP_OLD);
          }).then(function () {
            return foo.isMiss();
          }).then(function (missed) {
            catching(done, function () {
              expect(missed).to.be.false;
            });
          });
        });
      });

      context('SP_PRECOMPUTE', function () {
        it('should return true before expiration for a single instance', function (done) {
          var bar;

          foo.set('bar', 100).then(function () {
            return foo.get(Stash.Item.SP_PRECOMPUTE, 110);
          }).then(function () {
            return foo.isMiss();
          }).then(function (missed) {
            try {
              expect(missed).to.be.true;
            } catch (err) {
              done(err);
            }
          }).then(function () {
            return foo.lock();
          }).then(function () {
            bar = pool.getItem(foo.key);
            return bar.get(Stash.Item.SP_PRECOMPUTE, 110);
          }).then(function () {
            return bar.isMiss();
          }).then(function (missed) {
            catching(done, function () {
              expect(missed).to.be.false;
            });
          });
        });
      });

      context('SP_VALUE', function () {
        it('should return the specified value when locked', function () {
          foo.set('bar');
          foo.lock();
          expect(foo.get(Stash.Item.SP_VALUE, 'baz')).to.be.equal('baz');
        });
      });
    });
  });

  context('#clear', function () {
    it('should immediately invalidate a key', function () {
      foo.set('bar', 1000);
      foo.clear();
      expect(foo.get()).to.be.null;
    });
  });

  context('#lock', function () {
    it('should set cache as locked', function () {
      foo.lock();
      expect(foo.pool.drivers[0].get(foo.key).locked)
        .to.be.true;
    });
  });
});

@@ -2918,32 +2918,36 @@
 ate', function (
+done
 ) %7B%0A      foo.se
@@ -2987,138 +2987,451 @@
 00))
-;%0A      expect(foo.isMiss()).to.be.false;%0A%0A      foo.set('bar', new Date(Date.now() - 100));%0A      expect(foo.isMiss()).to.be.true
+.then(function () %7B%0A        return foo.isMiss();%0A      %7D).then(function (missed) %7B%0A        try %7B%0A          expect(missed).to.be.false;%0A        %7D catch(err) %7B done(err); %7D%0A      %7D).then(function () %7B%0A        return foo.set('bar', new Date(Date.now() - 100));%0A      %7D).then(function () %7B%0A        return foo.isMiss();%0A      %7D).then(function (missed) %7B%0A        catching(done, function () %7B%0A          expect(missed).to.be.true;%0A        %7D);%0A      %7D)
 ;%0A  

fix Item expiration accepts Date