text: /*global defineSuite*/
  defineSuite([
          'Scene/CullingVolume',
          'Core/AxisAlignedBoundingBox',
          'Core/BoundingSphere',
          'Core/Cartesian3',
          'Core/Intersect',
          'Scene/PerspectiveFrustum'
      ], function(
          CullingVolume,
          AxisAlignedBoundingBox,
          BoundingSphere,
          Cartesian3,
          Intersect,
          PerspectiveFrustum) {
      'use strict';
  
      var cullingVolume;
  
      beforeEach(function() {
          var frustum = new PerspectiveFrustum();
          frustum.near = 1.0;
          frustum.far = 2.0;
          frustum.fov = (Math.PI) / 3;
          frustum.aspectRatio = 1.0;
          cullingVolume = frustum.computeCullingVolume(new Cartesian3(), Cartesian3.negate(Cartesian3.UNIT_Z, new Cartesian3()), Cartesian3.UNIT_Y);
      });
  
      it('computeVisibility throws without a bounding volume', function() {
          expect(function() {
              return new CullingVolume().computeVisibility();
          }).toThrowDeveloperError();
      });
  
      it('computeVisibilityWithPlaneMask throws without a bounding volume', function() {
          expect(function() {
              return new CullingVolume().computeVisibilityWithPlaneMask(undefined, CullingVolume.MASK_INDETERMINATE);
          }).toThrowDeveloperError();
      });
  
      it('computeVisibilityWithPlaneMask throws without a parent plane mask', function() {
          expect(function() {
              return new CullingVolume().computeVisibilityWithPlaneMask(new BoundingSphere(), undefined);
          }).toThrowDeveloperError();
      });
  
      function testWithAndWithoutPlaneMask(culling, bound, intersect) {
          expect(culling.computeVisibility(bound)).toEqual(intersect);
  
          var mask = culling.computeVisibilityWithPlaneMask(bound, CullingVolume.MASK_INDETERMINATE);
          if (intersect === Intersect.INSIDE) {
              expect(mask).toEqual(CullingVolume.MASK_INSIDE);
          } else if (intersect === Intersect.OUTSIDE) {
              expect(mask).toEqual(CullingVolume.MASK_OUTSIDE);
          } else {
              expect(mask).not.toEqual(CullingVolume.MASK_INSIDE);
              expect(mask).not.toEqual(CullingVolume.MASK_OUTSIDE);
          }
          expect(culling.computeVisibilityWithPlaneMask(bound, mask)).toEqual(mask);
      }
  
      describe('box intersections', function() {
  
          it('can contain an axis aligned bounding box', function() {
              var box1 = AxisAlignedBoundingBox.fromPoints([
                  new Cartesian3(-0.5, 0, -1.25),
                  new Cartesian3(0.5, 0, -1.25),
                  new Cartesian3(-0.5, 0, -1.75),
                  new Cartesian3(0.5, 0, -1.75)
              ]);
              testWithAndWithoutPlaneMask(cullingVolume, box1, Intersect.INSIDE);
          });
  
          describe('can partially contain an axis aligned bounding box', function() {
  
              it('on the far plane', function() {
                  var box2 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-0.5, 0, -1.5),
                      new Cartesian3(0.5, 0, -1.5),
                      new Cartesian3(-0.5, 0, -2.5),
                      new Cartesian3(0.5, 0, -2.5)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box2, Intersect.INTERSECTING);
              });
  
              it('on the near plane', function() {
                  var box3 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-0.5, 0, -0.5),
                      new Cartesian3(0.5, 0, -0.5),
                      new Cartesian3(-0.5, 0, -1.5),
                      new Cartesian3(0.5, 0, -1.5)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box3, Intersect.INTERSECTING);
              });
  
              it('on the left plane', function() {
                  var box4 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-1.5, 0, -1.25),
                      new Cartesian3(0, 0, -1.25),
                      new Cartesian3(-1.5, 0, -1.5),
                      new Cartesian3(0, 0, -1.5)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box4, Intersect.INTERSECTING);
              });
  
              it('on the right plane', function() {
                  var box5 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(0, 0, -1.25),
                      new Cartesian3(1.5, 0, -1.25),
                      new Cartesian3(0, 0, -1.5),
                      new Cartesian3(1.5, 0, -1.5)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box5, Intersect.INTERSECTING);
              });
  
              it('on the top plane', function() {
                  var box6 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-0.5, 0, -1.25),
                      new Cartesian3(0.5, 0, -1.25),
                      new Cartesian3(-0.5, 2.0, -1.75),
                      new Cartesian3(0.5, 2.0, -1.75)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box6, Intersect.INTERSECTING);
              });
  
              it('on the bottom plane', function() {
                  var box7 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-0.5, -2.0, -1.25),
                      new Cartesian3(0.5, 0, -1.25),
                      new Cartesian3(-0.5, -2.0, -1.5),
                      new Cartesian3(0.5, 0, -1.5)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box7, Intersect.INTERSECTING);
              });
          });
  
          describe('can not contain an axis aligned bounding box', function() {
  
              it('past the far plane', function() {
                  var box8 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-0.5, 0, -2.25),
                      new Cartesian3(0.5, 0, -2.25),
                      new Cartesian3(-0.5, 0, -2.75),
                      new Cartesian3(0.5, 0, -2.75)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box8, Intersect.OUTSIDE);
              });
  
              it('before the near plane', function() {
                  var box9 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-0.5, 0, -0.25),
                      new Cartesian3(0.5, 0, -0.25),
                      new Cartesian3(-0.5, 0, -0.75),
                      new Cartesian3(0.5, 0, -0.75)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box9, Intersect.OUTSIDE);
              });
  
              it('past the left plane', function() {
                  var box10 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-5, 0, -1.25),
                      new Cartesian3(-3, 0, -1.25),
                      new Cartesian3(-5, 0, -1.75),
                      new Cartesian3(-3, 0, -1.75)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box10, Intersect.OUTSIDE);
              });
  
              it('past the right plane', function() {
                  var box11 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(3, 0, -1.25),
                      new Cartesian3(5, 0, -1.25),
                      new Cartesian3(3, 0, -1.75),
                      new Cartesian3(5, 0, -1.75)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box11, Intersect.OUTSIDE);
              });
  
              it('past the top plane', function() {
                  var box12 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-0.5, 3, -1.25),
                      new Cartesian3(0.5, 3, -1.25),
                      new Cartesian3(-0.5, 5, -1.75),
                      new Cartesian3(0.5, 5, -1.75)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box12, Intersect.OUTSIDE);
              });
  
              it('past the bottom plane', function() {
                  var box13 = AxisAlignedBoundingBox.fromPoints([
                      new Cartesian3(-0.5, -3, -1.25),
                      new Cartesian3(0.5, -3, -1.25),
                      new Cartesian3(-0.5, -5, -1.75),
                      new Cartesian3(0.5, -5, -1.75)
                  ]);
                  testWithAndWithoutPlaneMask(cullingVolume, box13, Intersect.OUTSIDE);
              });
  
          });
      });
  
      describe('sphere intersection', function() {
  
          it('can contain a sphere', function() {
              var sphere1 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -1.25), new Cartesian3(0, 0, -1.75)]);
              testWithAndWithoutPlaneMask(cullingVolume, sphere1, Intersect.INSIDE);
          });
  
          describe('can partially contain a sphere', function() {
  
              it('on the far plane', function() {
                  var sphere2 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -1.5), new Cartesian3(0, 0, -2.5)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere2, Intersect.INTERSECTING);
              });
  
              it('on the near plane', function() {
                  var sphere3 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -0.5), new Cartesian3(0, 0, -1.5)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere3, Intersect.INTERSECTING);
              });
  
              it('on the left plane', function() {
                  var sphere4 = BoundingSphere.fromPoints([new Cartesian3(-1.0, 0, -1.5), new Cartesian3(0, 0, -1.5)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere4, Intersect.INTERSECTING);
              });
  
              it('on the right plane', function() {
                  var sphere5 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -1.5), new Cartesian3(1.0, 0, -1.5)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere5, Intersect.INTERSECTING);
              });
  
              it('on the top plane', function() {
                  var sphere6 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -1.5), new Cartesian3(0, 2.0, -1.5)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere6, Intersect.INTERSECTING);
              });
  
              it('on the bottom plane', function() {
                  var sphere7 = BoundingSphere.fromPoints([new Cartesian3(0, -2.0, -1.5), new Cartesian3(0, 0, -1.5)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere7, Intersect.INTERSECTING);
              });
          });
  
          describe('can not contain a sphere', function() {
  
              it('past the far plane', function() {
                  var sphere8 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -2.25), new Cartesian3(0, 0, -2.75)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere8, Intersect.OUTSIDE);
              });
  
              it('before the near plane', function() {
                  var sphere9 = BoundingSphere.fromPoints([new Cartesian3(0, 0, -0.25), new Cartesian3(0, 0, -0.5)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere9, Intersect.OUTSIDE);
              });
  
              it('past the left plane', function() {
                  var sphere10 = BoundingSphere.fromPoints([new Cartesian3(-5, 0, -1.25), new Cartesian3(-4.5, 0, -1.75)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere10, Intersect.OUTSIDE);
              });
  
              it('past the right plane', function() {
                  var sphere11 = BoundingSphere.fromPoints([new Cartesian3(4.5, 0, -1.25), new Cartesian3(5, 0, -1.75)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere11, Intersect.OUTSIDE);
              });
  
              it('past the top plane', function() {
                  var sphere12 = BoundingSphere.fromPoints([new Cartesian3(-0.5, 4.5, -1.25), new Cartesian3(-0.5, 5, -1.25)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere12, Intersect.OUTSIDE);
              });
  
              it('past the bottom plane', function() {
                  var sphere13 = BoundingSphere.fromPoints([new Cartesian3(-0.5, -4.5, -1.25), new Cartesian3(-0.5, -5, -1.25)]);
                  testWithAndWithoutPlaneMask(cullingVolume, sphere13, Intersect.OUTSIDE);
              });
          });
      });
  
      describe('construct from bounding sphere', function() {
          var boundingSphereCullingVolume = new BoundingSphere(new Cartesian3(1000.0, 2000.0, 3000.0), 100.0);
          var cullingVolume = CullingVolume.fromBoundingSphere(boundingSphereCullingVolume);
  
          it('throws without a boundingSphere', function() {
              expect(function() {
                  CullingVolume.fromBoundingSphere(undefined);
              }).toThrowDeveloperError();
          });
  
          it('can contain a volume', function() {
              var sphere1 = BoundingSphere.clone(boundingSphereCullingVolume);
              sphere1.radius *= 0.5;
              testWithAndWithoutPlaneMask(cullingVolume, sphere1, Intersect.INSIDE);
          });
  
          describe('can partially contain a volume', function() {
  
              it('on the far plane', function() {
                  var offset = new Cartesian3(0.0, 0.0, boundingSphereCullingVolume.radius * 1.5);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere2 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere2, Intersect.INTERSECTING);
              });
  
              it('on the near plane', function() {
                  var offset = new Cartesian3(0.0, 0.0, -boundingSphereCullingVolume.radius * 1.5);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere3 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere3, Intersect.INTERSECTING);
              });
  
              it('on the left plane', function() {
                  var offset = new Cartesian3(-boundingSphereCullingVolume.radius * 1.5, 0.0, 0.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere4 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere4, Intersect.INTERSECTING);
              });
  
              it('on the right plane', function() {
                  var offset = new Cartesian3(boundingSphereCullingVolume.radius * 1.5, 0.0, 0.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere5 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere5, Intersect.INTERSECTING);
              });
  
              it('on the top plane', function() {
                  var offset = new Cartesian3(0.0, boundingSphereCullingVolume.radius * 1.5, 0.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere6 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere6, Intersect.INTERSECTING);
              });
  
              it('on the bottom plane', function() {
                  var offset = new Cartesian3(0.0, -boundingSphereCullingVolume.radius * 1.5, 0.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere7 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere7, Intersect.INTERSECTING);
              });
          });
  
          describe('can not contain a volume', function() {
  
              it('past the far plane', function() {
                  var offset = new Cartesian3(0.0, 0.0, boundingSphereCullingVolume.radius * 2.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere8 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere8, Intersect.OUTSIDE);
              });
  
              it('before the near plane', function() {
                  var offset = new Cartesian3(0.0, 0.0, -boundingSphereCullingVolume.radius * 2.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere9 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere9, Intersect.OUTSIDE);
              });
  
              it('past the left plane', function() {
                  var offset = new Cartesian3(-boundingSphereCullingVolume.radius * 2.0, 0.0, 0.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere10 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere10, Intersect.OUTSIDE);
              });
  
              it('past the right plane', function() {
                  var offset = new Cartesian3(boundingSphereCullingVolume.radius * 2.0, 0.0, 0.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere11 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere11, Intersect.OUTSIDE);
              });
  
              it('past the top plane', function() {
                  var offset = new Cartesian3(0.0, boundingSphereCullingVolume.radius * 2.0, 0.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere12 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere12, Intersect.OUTSIDE);
              });
  
              it('past the bottom plane', function() {
                  var offset = new Cartesian3(0.0, -boundingSphereCullingVolume.radius * 2.0, 0.0);
                  var center = Cartesian3.add(boundingSphereCullingVolume.center, offset, new Cartesian3());
                  var radius = boundingSphereCullingVolume.radius * 0.5;
                  var sphere13 = new BoundingSphere(center, radius);
  
                  testWithAndWithoutPlaneMask(cullingVolume, sphere13, Intersect.OUTSIDE);
              });
          });
      });
  });
  