'use strict';

import UsageCounter from './usageCounter';
import 'should';

/**
 * @test {UsageCounter}
 */
describe('UsageCounter', () => {

  let counter: UsageCounter;

  beforeEach(() => {
    counter = new UsageCounter();
  });

  /**
   * @test {UsageCounter#acquire}
   */
  describe('acquire', () => {

    /**
     * @test {UsageCounter#acquire}
     */
    it('should acquire key', () => {
      counter.acquire('key1', 'usage1');
      counter.acquire('key1', 'usage1');
      counter.acquire('key1', 'usage2');
      counter.acquire('key2', 'usage1');

      counter.isAcquiredBy('key1', 'usage1').should.be.true();
      counter.isAcquiredBy('key1', 'usage2').should.be.true();
      counter.isAcquiredBy('key1', 'usage3').should.be.false();
      counter.isAcquiredBy('key2', 'usage1').should.be.true();
      counter.isAcquiredBy('key2', 'usage2').should.be.false();
      counter.isAcquiredBy('key3', 'usage1').should.be.false();
    });

  });

  /**
   * @test {UsageCounter#release}
   */
  describe('release', () => {

    /**
     * @test {UsageCounter#release}
     */
    it('should release key', () => {
      counter.acquire('key1', 'usage1');
      counter.acquire('key1', 'usage2');
      counter.release('key1', 'usage1');
      counter.isInUse('key1').should.be.true();

      counter.release('key1', 'usage3');
      counter.release('key2', 'usage2');
      counter.isInUse('key1').should.be.true();

      counter.release('key1', 'usage2');
      counter.isInUse('key1').should.be.false();
    });

  });

  /**
   * @test {UsageCounter#isInUse}
   */
  describe('isInUse', () => {

    /**
     * @test {UsageCounter#isInUse}
     */
    it('should return if a key is in use', () => {
      counter.isInUse('key1').should.be.false();

      counter.acquire('key1', 'usage1');
      counter.acquire('key1', 'usage2');
      counter.isInUse('key1').should.be.true();

      counter.release('key1', 'usage1');
      counter.isInUse('key1').should.be.true();

      counter.release('key1', 'usage2');
      counter.isInUse('key1').should.be.false();
    });

  });

  /**
   * @test {UsageCounter#getUsageIds}
   */
  describe('getUsageIds', () => {

    /**
     * @test {UsageCounter#getUsageIds}
     */
    it('should return usage IDs of a key', () => {
      counter.getUsages('key1').should.deepEqual(new Set());

      counter.acquire('key1', 'usage1');
      counter.acquire('key1', 'usage1');
      counter.acquire('key1', 'usage2');
      counter.acquire('key2', 'usage3');
      counter.getUsages('key1').should.deepEqual(new Set(['usage1', 'usage2']));
    });

  });

  /**
   * @test {UsageCounter#isAcquiredBy}
   */
  describe('isAcquiredBy', () => {

    /**
     * @test {UsageCounter#isAcquiredBy}
     */
    it('should return if a key is acquired by specific usage ID', () => {
      counter.isAcquiredBy('key1', 'usage1').should.be.false();

      counter.acquire('key1', 'usage1');
      counter.acquire('key1', 'usage1');
      counter.isAcquiredBy('key1', 'usage1').should.be.true();
      counter.isAcquiredBy('key1', 'usage2').should.be.false();

      counter.release('key1', 'usage1');
      counter.isAcquiredBy('key1', 'usage1').should.be.false();
    });

  });

  /**
   * @test {UsageCounter#getAcquiredBy}
   */
  describe('getAcquiredBy', () => {

    /**
     * @test {UsageCounter#getAcquiredBy}
     */
    it('should return keys acquired by specified usage ID', () => {
      counter.getAcquiredBy('usage1').should.deepEqual([]);

      counter.acquire('key1', 'usage1');
      counter.acquire('key2', 'usage1');
      counter.acquire('key3', 'usage2');
      counter.getAcquiredBy('usage1').should.deepEqual(['key1', 'key2']);

      counter.release('key1', 'usage1');
      counter.getAcquiredBy('usage1').should.deepEqual(['key2']);

      counter.release('key2', 'usage1');
      counter.getAcquiredBy('usage1').should.deepEqual([]);
    });
    
  });

});
