text: defineSuite([
          'Scene/BatchTable',
          'Core/Cartesian4',
          'Core/ComponentDatatype',
          'Core/Math',
          'Renderer/PixelDatatype',
          'Renderer/Texture',
          'Specs/createScene'
      ], function(
          BatchTable,
          Cartesian4,
          ComponentDatatype,
          CesiumMath,
          PixelDatatype,
          Texture,
          createScene) {
      'use strict';
  
      var unsignedByteAttributes = [{
          functionName : 'batchTable_getShow',
          componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
          componentsPerAttribute : 1
      }, {
          functionName : 'batchTable_getPickColor',
          componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
          componentsPerAttribute : 4,
          normalize : true
      }];
  
      var floatAttributes = [{
          functionName : 'batchTable_getShow',
          componentDatatype : ComponentDatatype.UNSIGNED_BYTE,
          componentsPerAttribute : 1
      }, {
          functionName : 'batchTable_getCenter',
          componentDatatype : ComponentDatatype.FLOAT,
          componentsPerAttribute : 4
      }];
  
      var batchTable;
      var scene;
      var context;
  
      beforeAll(function() {
          scene = createScene();
          context = scene.context;
      });
  
      afterAll(function() {
          scene.destroyForSpecs();
      });
  
      afterEach(function() {
          batchTable = batchTable && !batchTable.isDestroyed() && batchTable.destroy();
      });
  
      it('constructor', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 2);
          expect(batchTable.attributes).toBe(unsignedByteAttributes);
          expect(batchTable.numberOfInstances).toEqual(2);
      });
  
      it('constructior throws without context', function() {
          expect(function() {
              batchTable = new BatchTable(undefined, unsignedByteAttributes, 5);
          }).toThrowDeveloperError();
      });
  
      it('constructior throws without attributes', function() {
          expect(function() {
              batchTable = new BatchTable(context, undefined, 5);
          }).toThrowDeveloperError();
      });
  
      it('constructor throws without number of instances', function() {
          expect(function() {
              batchTable = new BatchTable(context, unsignedByteAttributes, undefined);
          }).toThrowDeveloperError();
      });
  
      it('sets and gets entries in the table', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
  
          var i;
          var color = new Cartesian4(0, 1, 2, 3);
  
          for (i = 0; i < batchTable.numberOfInstances; ++i) {
              batchTable.setBatchedAttribute(i, 0, 1);
              batchTable.setBatchedAttribute(i, 1, color);
          }
  
          for (i = 0; i < batchTable.numberOfInstances; ++i) {
              expect(batchTable.getBatchedAttribute(3, 0)).toEqual(1);
              expect(batchTable.getBatchedAttribute(3, 1)).toEqual(color);
          }
  
          color = new Cartesian4(4, 5, 6, 7);
          batchTable.setBatchedAttribute(3, 0, 0);
          batchTable.setBatchedAttribute(3, 1, color);
          expect(batchTable.getBatchedAttribute(3, 0)).toEqual(0);
          expect(batchTable.getBatchedAttribute(3, 1)).toEqual(color);
      });
  
      it('sets and gets entries in the table with float attributes', function() {
          var context = {
              floatingPointTexture : true
          };
          batchTable = new BatchTable(context, floatAttributes, 5);
  
          var i;
          var color = new Cartesian4(0, 1, 2, 3);
  
          for (i = 0; i < batchTable.numberOfInstances; ++i) {
              batchTable.setBatchedAttribute(i, 0, 1);
              batchTable.setBatchedAttribute(i, 1, color);
          }
  
          for (i = 0; i < batchTable.numberOfInstances; ++i) {
              expect(batchTable.getBatchedAttribute(3, 0)).toEqual(1);
              expect(batchTable.getBatchedAttribute(3, 1)).toEqual(color);
          }
  
          color = new Cartesian4(4, 5, 6, 7);
          batchTable.setBatchedAttribute(3, 0, 0);
          batchTable.setBatchedAttribute(3, 1, color);
          expect(batchTable.getBatchedAttribute(3, 0)).toEqual(0);
          expect(batchTable.getBatchedAttribute(3, 1)).toEqual(color);
      });
  
      it('sets and gets entries in the table with float attributes and forced packing', function() {
          var context = {
              floatingPointTexture : false
          };
          batchTable = new BatchTable(context, floatAttributes, 5);
  
          var i;
          var color = new Cartesian4(1.23456e12, -2.34567e30, 3.45678e-6, -4.56789e-10);
  
          for (i = 0; i < batchTable.numberOfInstances; ++i) {
              batchTable.setBatchedAttribute(i, 0, 1);
              batchTable.setBatchedAttribute(i, 1, color);
          }
  
          var value;
          for (i = 0; i < batchTable.numberOfInstances; ++i) {
              value = batchTable.getBatchedAttribute(3, 0);
              expect(value).toEqual(1);
              value = batchTable.getBatchedAttribute(3, 1);
              expect(value).toEqualEpsilon(color, CesiumMath.EPSILON6);
          }
  
          color = new Cartesian4(0, Number.MAX_VALUE, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY);
          batchTable.setBatchedAttribute(3, 0, 0);
          batchTable.setBatchedAttribute(3, 1, color);
  
          value = batchTable.getBatchedAttribute(3, 0);
          expect(value).toEqual(0);
          value = batchTable.getBatchedAttribute(3, 1);
          expect(value.x).toEqual(0.0);
          expect(value.y).toEqual(Number.POSITIVE_INFINITY);
          expect(value.z).toEqual(Number.POSITIVE_INFINITY);
          expect(value.w).toEqual(Number.NEGATIVE_INFINITY);
      });
  
      it('gets with result parameter', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
          var color = new Cartesian4(0, 1, 2, 3);
          batchTable.setBatchedAttribute(0, 1, color);
  
          var result = new Cartesian4();
          var returndValue = batchTable.getBatchedAttribute(0, 1, result);
          expect(returndValue).toBe(result);
          expect(result).toEqual(color);
      });
  
      it('get entry throws when instance index is out of range', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
          expect(function() {
              batchTable.getBatchedAttribute(-1, 0);
          }).toThrowDeveloperError();
          expect(function() {
              batchTable.getBatchedAttribute(100, 0);
          }).toThrowDeveloperError();
      });
  
      it('get entry throws when attribute index is out of range', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
          expect(function() {
              batchTable.getBatchedAttribute(0, -1);
          }).toThrowDeveloperError();
          expect(function() {
              batchTable.getBatchedAttribute(0, 100);
          }).toThrowDeveloperError();
      });
  
      it('set entry throws when instance index is out of range', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
          expect(function() {
              batchTable.setBatchedAttribute(-1, 0, 0);
          }).toThrowDeveloperError();
          expect(function() {
              batchTable.setBatchedAttribute(100, 0, 1);
          }).toThrowDeveloperError();
      });
  
      it('set entry throws when attribute index is out of range', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
          expect(function() {
              batchTable.setBatchedAttribute(0, -1, 1);
          }).toThrowDeveloperError();
          expect(function() {
              batchTable.setBatchedAttribute(0, 100, 1);
          }).toThrowDeveloperError();
      });
  
      it('set entry throws when value is undefined', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
          expect(function() {
              batchTable.setBatchedAttribute(0, 0, undefined);
          }).toThrowDeveloperError();
      });
  
      it('creates a uniform callback with unsigned byte texture', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
          batchTable.update(scene.frameState);
  
          var uniforms = batchTable.getUniformMapCallback()({});
          expect(uniforms.batchTexture).toBeDefined();
          expect(uniforms.batchTexture()).toBeInstanceOf(Texture);
          expect(uniforms.batchTexture().pixelDatatype).toEqual(PixelDatatype.UNSIGNED_BYTE);
          expect(uniforms.batchTextureDimensions).toBeDefined();
          expect(uniforms.batchTextureDimensions().x).toBeGreaterThan(0);
          expect(uniforms.batchTextureDimensions().y).toBeGreaterThan(0);
          expect(uniforms.batchTextureStep).toBeDefined();
          expect(uniforms.batchTextureStep().x).toBeGreaterThan(0);
          expect(uniforms.batchTextureStep().y).toBeGreaterThan(0);
          expect(uniforms.batchTextureStep().z).toBeGreaterThan(0);
          expect(uniforms.batchTextureStep().w).toBeGreaterThan(0);
      });
  
      it('creates a uniform callback with float texture', function() {
          if (!context.floatingPointTexture) {
              return;
          }
  
          batchTable = new BatchTable(context, floatAttributes, 5);
          batchTable.update(scene.frameState);
  
          var uniforms = batchTable.getUniformMapCallback()({});
          expect(uniforms.batchTexture).toBeDefined();
          expect(uniforms.batchTexture()).toBeInstanceOf(Texture);
          expect(uniforms.batchTexture().pixelDatatype).toEqual(PixelDatatype.FLOAT);
          expect(uniforms.batchTextureDimensions).toBeDefined();
          expect(uniforms.batchTextureDimensions().x).toBeGreaterThan(0);
          expect(uniforms.batchTextureDimensions().y).toBeGreaterThan(0);
          expect(uniforms.batchTextureStep).toBeDefined();
          expect(uniforms.batchTextureStep().x).toBeGreaterThan(0);
          expect(uniforms.batchTextureStep().y).toBeGreaterThan(0);
          expect(uniforms.batchTextureStep().z).toBeGreaterThan(0);
          expect(uniforms.batchTextureStep().w).toBeGreaterThan(0);
  
          if (scene.context.floatingPointTexture) {
              expect(uniforms.batchTexture().pixelDatatype).toEqual(PixelDatatype.FLOAT);
          } else {
              expect(uniforms.batchTexture().pixelDatatype).toEqual(PixelDatatype.UNSIGNED_BYTE);
          }
      });
  
      it('create shader functions', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
  
          var shader = 'void main() { gl_Position = vec4(0.0); }';
          var modifiedShader = batchTable.getVertexShaderCallback()(shader);
          expect(modifiedShader.indexOf(batchTable.attributes[0].functionName)).not.toEqual(-1);
          expect(modifiedShader.indexOf(batchTable.attributes[1].functionName)).not.toEqual(-1);
      });
  
      it('isDestroyed', function() {
          batchTable = new BatchTable(context, unsignedByteAttributes, 5);
          expect(batchTable.isDestroyed()).toEqual(false);
          batchTable.destroy();
          expect(batchTable.isDestroyed()).toEqual(true);
      });
  }, 'WebGL');
  