/**!
 *
 * Copyright (c) 2015 Cisco Systems, Inc. See LICENSE file.
 * @private
 */

import {assert} from '@ciscospark/test-helper-chai';

export default function runAbstractStorageAdapterSpec(adapter) {
  const key = `key`;
  const namespace = `namespace`;
  const obj = {a: 1};
  const primitive = 1;
  const options = {
    logger: console
  };

  describe(`#bind()`, () => {
    // namespace and options.logger are required more to make sure we always
    // call bind correctly rather than to make sure the adapter uses them.
    it(`requires a namespace`, () => assert.isRejected(adapter.bind(), /`namespace` is required/));

    it(`requires a logger option`, () => assert.isRejected(adapter.bind(namespace), /`options.logger` is required/));

    it(`returns a db interface`, () => assert.isFulfilled(adapter.bind(namespace, options)));

    describe(`bound`, () => {
      let bound;
      before(() => adapter.bind(namespace, options)
        .then((b) => {
          bound = b;
        }));

      describe(`#put()`, () => {
        it(`puts a primitive into the store`, () => bound.put(key, primitive)
          .then(() => assert.becomes(bound.get(key), primitive)));

        it(`puts an object into the store`, () => bound.put(key, obj)
          .then(() => assert.becomes(bound.get(key), obj)));

        it(`handles concurrency`, () => Promise.all([
          bound.put(key, 1),
          bound.put(key, 2),
          bound.put(key, 3)
        ])
          .then(() => assert.becomes(bound.get(key), 3)));

        it(`puts same key in different namespaces`, () => {
          adapter.bind(`namespace2`, options)
            .then((b) => {
              bound.put(key, primitive)
                .then(() => assert.becomes(bound.get(key), primitive));
              const primitive2 = 2;
              b.put(key, primitive2)
                .then(() => assert.becomes(b.get(key), primitive2));
            });
        });
      });

      describe(`#get()`, () => {
        it(`gets a primitive from the store`, () => bound.put(key, primitive)
          .then(() => assert.becomes(bound.get(key), primitive)));

        it(`gets an object from the store`, () => bound.put(key, obj)
          .then(() => assert.becomes(bound.get(key), obj)));

        it(`rejects if the key cannot be found`, () => assert.isRejected(bound.get(`notakey`)));
      });

      describe(`#del()`, () => {
        it(`removes a primitive from the store`, () => bound.put(key, primitive)
          .then(() => assert.becomes(bound.get(key), primitive))
          .then(() => assert.isFulfilled(bound.del(key)))
          .then(() => assert.isRejected(bound.get(key))));

        it(`removes an object from the store`, () => bound.put(key, obj)
          .then(() => assert.becomes(bound.get(key), obj))
          .then(() => assert.isFulfilled(bound.del(key)))
          .then(() => assert.isRejected(bound.get(key))));
      });
    });
  });
}

@@ -1592,42 +1592,60 @@
     
-adapter.bind(%60namespace2%60, options
+let value;%0A          return bound.put(key, primitive
 )%0A  
@@ -1653,33 +1653,32 @@
          .then((
-b
 ) =%3E %7B%0A         
@@ -1685,33 +1685,88 @@
     
+ value =
  bound.
-pu
+ge
 t(key
-, primitive
+);%0A              return adapter.bind(%60namespace2%60, options
 )%0A  
@@ -1790,57 +1790,20 @@
 en((
+b
 ) =%3E 
-assert.becomes(bound.get(key), primitive));%0A
+%7B%0A    
     
@@ -1848,16 +1848,20 @@
         
+    
 b.put(ke
@@ -1883,32 +1883,36 @@
                 
+  
+  
 .then(() =%3E asse
@@ -1911,46 +1911,250 @@
  =%3E 
-assert.becomes(b.get(key), primitive2)
+%7B%0A                      const assert1 = assert.becomes(value, primitive);%0A                      const assert2 = assert.becomes(b.get(key), primitive2);%0A                      return assert1 && assert2;%0A                    %7D);%0A                %7D
 );%0A 

put both values first, then read