text: // Copyright 2006 The Closure Library Authors. All Rights Reserved.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS-IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  goog.provide('goog.structs.PriorityPoolTest');
  goog.setTestOnly('goog.structs.PriorityPoolTest');
  
  goog.require('goog.structs.PriorityPool');
  goog.require('goog.testing.MockClock');
  goog.require('goog.testing.jsunit');
  
  // Implementation of the Pool class with isObjectDead() always returning TRUE,
  // so that the the Pool will not reuse any objects.
  function NoObjectReusePriorityPool(opt_min, opt_max) {
    goog.structs.PriorityPool.call(this, opt_min, opt_max);
  }
  goog.inherits(NoObjectReusePriorityPool, goog.structs.PriorityPool);
  
  NoObjectReusePriorityPool.prototype.objectCanBeReused = function(obj) {
    return false;
  };
  
  
  function testExceedMax1() {
    var p = new goog.structs.PriorityPool(0, 3);
  
    var getCount1 = 0;
    var callback1 = function(obj) {
      assertNotNull(obj);
      getCount1++;
    };
  
    var getCount2 = 0;
    var callback2 = function(obj) {
      getCount2++;
    };
  
    p.getObject(callback1);
    p.getObject(callback1);
    p.getObject(callback1);
    p.getObject(callback2);
    p.getObject(callback2);
    p.getObject(callback2);
  
    assertEquals('getCount for allocated, Should be 3', getCount1, 3);
    assertEquals('getCount for unallocated, Should be 0', getCount2, 0);
  }
  
  
  function testExceedMax2() {
    var p = new goog.structs.PriorityPool(0, 1);
  
    var getCount1 = 0;
    var callback1 = function(obj) {
      assertNotNull(obj);
      getCount1++;
    };
  
    var getCount2 = 0;
    var callback2 = function(obj) {
      getCount2++;
    };
  
    p.getObject(callback1);
    p.getObject(callback2);
    p.getObject(callback2);
    p.getObject(callback2);
    p.getObject(callback2);
    p.getObject(callback2);
  
    assertEquals('getCount for allocated, Should be 1', getCount1, 1);
    assertEquals('getCount for unallocated, Should be 0', getCount2, 0);
  }
  
  function testExceedMax3() {
    var p = new goog.structs.PriorityPool(0, 2);
  
    var obj1 = null;
    var callback1 = function(obj) {
      obj1 = obj;
    };
  
    var obj2 = null;
    var callback2 = function(obj) {
      obj2 = obj;
    };
  
    var obj3 = null;
    var callback3 = function(obj) {
      obj3 = obj;
    };
  
    p.getObject(callback1);
    p.getObject(callback2);
    p.getObject(callback3);
  
    assertNotNull(obj1);
    assertNotNull(obj2);
    assertNull(obj3);
  }
  
  function testExceedMax4() {
    var p = new goog.structs.PriorityPool(); // default: 10
    var objs = [];
  
    var getCount1 = 0;
    var callback1 = function(obj) {
      assertNotNull(obj);
      getCount1++;
    };
  
    var getCount2 = 0;
    var callback2 = function(obj) {
      getCount2++;
    };
  
    for (var i = 0; i < 12; i++) {
      p.getObject(i < 10 ? callback1 : callback2);
    }
  
    assertEquals('getCount for allocated, Should be 10', getCount1, 10);
    assertEquals('getCount for unallocated, Should be 0', getCount2, 0);
  }
  
  
  function testReleaseAndGet1() {
    var p = new goog.structs.PriorityPool(0, 10);
  
    var o = null;
    var callback = function(obj) {
      o = obj;
    };
  
    p.getObject(callback);
    assertEquals(1, p.getCount());
    assertEquals(1, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
    assertTrue('Result should be true', p.releaseObject(o));
    assertEquals(1, p.getCount());
    assertEquals(0, p.getInUseCount());
    assertEquals(1, p.getFreeCount());
  }
  
  
  function testReleaseAndGet2() {
    var p = new NoObjectReusePriorityPool(0, 10);
  
    var o = null;
    var callback = function(obj) {
      o = obj;
    };
  
    p.getObject(callback);
    assertEquals(1, p.getCount());
    assertEquals(1, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
    assertTrue('Result should be true', p.releaseObject(o));
    assertEquals(0, p.getCount());
    assertEquals(0, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
  }
  
  
  function testReleaseAndGet3() {
    var p = new goog.structs.PriorityPool(0, 10);
    var o1 = null;
    var callback1 = function(obj) {
      o1 = obj;
    };
  
    var o2 = null;
    var callback2 = function(obj) {
      o2 = obj;
    };
  
    var o3 = null;
    var callback3 = function(obj) {
      o3 = obj;
    };
  
    var o4 = {};
  
    p.getObject(callback1);
    p.getObject(callback2);
    p.getObject(callback3);
  
    assertEquals(3, p.getCount());
    assertEquals(3, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
    assertTrue('Result should be true', p.releaseObject(o1));
    assertTrue('Result should be true', p.releaseObject(o2));
    assertFalse('Result should be false', p.releaseObject(o4));
    assertEquals(3, p.getCount());
    assertEquals(1, p.getInUseCount());
    assertEquals(2, p.getFreeCount());
  }
  
  
  function testReleaseAndGet4() {
    var p = new NoObjectReusePriorityPool(0, 10);
  
    var o1 = null;
    var callback1 = function(obj) {
      o1 = obj;
    };
  
    var o2 = null;
    var callback2 = function(obj) {
      o2 = obj;
    };
  
    var o3 = null;
    var callback3 = function(obj) {
      o3 = obj;
    };
  
    var o4 = {};
  
    p.getObject(callback1);
    p.getObject(callback2);
    p.getObject(callback3);
    assertEquals(3, p.getCount());
    assertEquals(3, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
    assertTrue('Result should be true', p.releaseObject(o1));
    assertTrue('Result should be true', p.releaseObject(o2));
    assertFalse('Result should be false', p.releaseObject(o4));
    assertEquals(1, p.getCount());
    assertEquals(1, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
  }
  
  
  function testIsInPool1() {
    var p = new goog.structs.PriorityPool();
    var o1 = null;
    var callback1 = function(obj) {
      o1 = obj;
    };
  
    var o2 = null;
    var callback2 = function(obj) {
      o2 = obj;
    };
  
    var o3 = null;
    var callback3 = function(obj) {
      o3 = obj;
    };
  
    var o4 = {};
    var o5 = {};
  
    p.getObject(callback1);
    p.getObject(callback2);
    p.getObject(callback3);
    var o6 = o1;
  
    assertTrue(p.contains(o1));
    assertTrue(p.contains(o2));
    assertTrue(p.contains(o3));
    assertFalse(p.contains(o4));
    assertFalse(p.contains(o5));
    assertTrue(p.contains(o6));
  }
  
  
  function testSetMin1() {
    var p = new goog.structs.PriorityPool(0, 10);
  
    assertEquals(0, p.getCount());
    assertEquals(0, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
  
    p.setMinimumCount(10);
  
    assertEquals(10, p.getCount());
    assertEquals(0, p.getInUseCount());
    assertEquals(10, p.getFreeCount());
  }
  
  
  function testSetMin2() {
    var p = new goog.structs.PriorityPool(0, 10);
  
    assertEquals(0, p.getCount());
    assertEquals(0, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
  
    var o1 = null;
    var callback1 = function(obj) {
      o1 = obj;
    };
    p.getObject(callback1);
  
    assertEquals(1, p.getCount());
    assertEquals(1, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
  
    p.setMinimumCount(10);
  
    assertEquals(10, p.getCount());
    assertEquals(1, p.getInUseCount());
    assertEquals(9, p.getFreeCount());
  }
  
  
  function testSetMax1() {
    var p = new goog.structs.PriorityPool(0, 10);
  
    assertEquals(0, p.getCount());
    assertEquals(0, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
  
    var o1 = null;
    var callback1 = function(obj) {
      o1 = obj;
    };
  
    var o2 = null;
    var callback2 = function(obj) {
      o2 = obj;
    };
  
    var o3 = null;
    var callback3 = function(obj) {
      o3 = obj;
    };
  
    var o4 = null;
    var callback4 = function(obj) {
      o4 = obj;
    };
  
    var o5 = null;
    var callback5 = function(obj) {
      o5 = obj;
    };
  
    p.getObject(callback1);
    p.getObject(callback2);
    p.getObject(callback3);
    p.getObject(callback4);
    p.getObject(callback5);
  
    assertEquals(5, p.getCount());
    assertEquals(5, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
  
    assertTrue('Result should be true', p.releaseObject(o5));
  
    assertEquals(5, p.getCount());
    assertEquals(4, p.getInUseCount());
    assertEquals(1, p.getFreeCount());
  
    p.setMaximumCount(4);
  
    assertEquals(4, p.getCount());
    assertEquals(4, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
  }
  
  
  function testInvalidMinMax1() {
    var p = new goog.structs.PriorityPool(0, 10);
  
    assertEquals(0, p.getCount());
    assertEquals(0, p.getInUseCount());
    assertEquals(0, p.getFreeCount());
  
    assertThrows(function() {
      p.setMinimumCount(11);
    });
  }
  
  
  function testInvalidMinMax2() {
    var p = new goog.structs.PriorityPool(5, 10);
  
    assertEquals(5, p.getCount());
    assertEquals(0, p.getInUseCount());
    assertEquals(5, p.getFreeCount());
  
    assertThrows(function() {
      p.setMaximumCount(4);
    });
  }
  
  
  function testInvalidMinMax3() {
    assertThrows(function() {
      new goog.structs.PriorityPool(10, 1);
    });
  }
  
  function testQueue1() {
    var p = new goog.structs.PriorityPool(0, 2);
  
    var o1 = null;
    var callback1 = function(obj) {
      o1 = obj;
    };
  
    var o2 = null;
    var callback2 = function(obj) {
      o2 = obj;
    };
  
    var o3 = null;
    var callback3 = function(obj) {
      o3 = obj;
    };
  
    p.getObject(callback1);
    p.getObject(callback2);
    p.getObject(callback3);
  
    assertNotNull(o1);
    assertNotNull(o2);
    assertNull(o3);
  
    p.releaseObject(o1);
    assertNotNull(o3);
  }
  
  
  function testPriority1() {
    var p = new goog.structs.PriorityPool(0, 2);
  
    var o1 = null;
    var callback1 = function(obj) {
      o1 = obj;
    };
  
    var o2 = null;
    var callback2 = function(obj) {
      o2 = obj;
    };
  
    var o3 = null;
    var callback3 = function(obj) {
      o3 = obj;
    };
  
    var o4 = null;
    var callback4 = function(obj) {
      o4 = obj;
    };
  
    var o5 = null;
    var callback5 = function(obj) {
      o5 = obj;
    };
  
    var o6 = null;
    var callback6 = function(obj) {
      o6 = obj;
    };
  
    p.getObject(callback1);       // Initially seeded requests.
    p.getObject(callback2);
  
    p.getObject(callback3, 101);  // Lowest priority.
    p.getObject(callback4);       // Second lowest priority (default is 100).
    p.getObject(callback5, 99);   // Second highest priority.
    p.getObject(callback6, 0);    // Highest priority.
  
    assertNotNull(o1);
    assertNotNull(o2);
    assertNull(o3);
    assertNull(o4);
    assertNull(o5);
    assertNull(o6);
  
    p.releaseObject(o1);  // Release the first initially seeded request (o1).
    assertNotNull(o6);    // Make sure the highest priority request (o6) started.
    assertNull(o3);
    assertNull(o4);
    assertNull(o5);
  
    p.releaseObject(o2);  // Release the second, initially seeded request (o2).
    assertNotNull(o5);    // The second highest priority request starts (o5).
    assertNull(o3);
    assertNull(o4);
  
    p.releaseObject(o6);
    assertNotNull(o4);
    assertNull(o3);
  }
  
  
  function testRateLimiting() {
    var clock = new goog.testing.MockClock();
    clock.install();
  
    var p = new goog.structs.PriorityPool(0, 4);
    p.setDelay(100);
  
    var getCount = 0;
    var callback = function(obj) {
      assertNotNull(obj);
      getCount++;
    };
  
    p.getObject(callback);
    assertEquals(1, getCount);
  
    p.getObject(callback);
    assertEquals(1, getCount);
  
    clock.tick(100);
    assertEquals(2, getCount);
  
    p.getObject(callback);
    p.getObject(callback);
    assertEquals(2, getCount);
  
    clock.tick(100);
    assertEquals(3, getCount);
  
    clock.tick(100);
    assertEquals(4, getCount);
  
    p.getObject(callback);
    assertEquals(4, getCount);
  
    clock.tick(100);
    assertEquals(4, getCount);
  
    goog.dispose(clock);
  }
  
  
  function testRateLimitingWithChangingDelay() {
    var clock = new goog.testing.MockClock();
    clock.install();
  
    var p = new goog.structs.PriorityPool(0, 3);
    p.setDelay(100);
  
    var getCount = 0;
    var callback = function(obj) {
      assertNotNull(obj);
      getCount++;
    };
  
    p.getObject(callback);
    assertEquals(1, getCount);
  
    p.getObject(callback);
    assertEquals(1, getCount);
  
    clock.tick(50);
    assertEquals(1, getCount);
  
    p.setDelay(50);
    assertEquals(2, getCount);
  
    p.getObject(callback);
    assertEquals(2, getCount);
  
    clock.tick(20);
    assertEquals(2, getCount);
  
    p.setDelay(40);
    assertEquals(2, getCount);
  
    clock.tick(20);
    assertEquals(3, getCount);
  
    goog.dispose(clock);
  }
  