text: define([
          'Core/TileAvailability',
          'Core/Cartographic',
          'Core/GeographicTilingScheme',
          'Core/Rectangle',
          'Core/WebMercatorTilingScheme'
      ], function(
          TileAvailability,
          Cartographic,
          GeographicTilingScheme,
          Rectangle,
          WebMercatorTilingScheme) {
          'use strict';
  
  describe('Core/TileAvailability', function() {
  
      var webMercator = new WebMercatorTilingScheme();
      var geographic = new GeographicTilingScheme();
  
      function createAvailability(tilingScheme, maxLevel) {
          var availability = new TileAvailability(tilingScheme, 15);
          availability.addAvailableTileRange(0, 0, 0, tilingScheme.getNumberOfXTilesAtLevel(), tilingScheme.getNumberOfYTilesAtLevel());
          return availability;
      }
  
      describe('computeMaximumLevelAtPosition', function() {
          it('returns -1 if  position outside the tiling scheme', function() {
              var availability = createAvailability(webMercator, 15);
              expect(availability.computeMaximumLevelAtPosition(Cartographic.fromDegrees(25.0, 88.0))).toBe(-1);
          });
  
          it('returns 0 if there are no rectangles', function() {
              var availability = createAvailability(geographic, 15);
              expect(availability.computeMaximumLevelAtPosition(Cartographic.fromDegrees(25.0, 88.0))).toBe(0);
          });
  
          it('returns the higher level when on a boundary at level 0', function() {
              var availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(0, 0, 0, 0, 0);
              availability.addAvailableTileRange(1, 1, 0, 1, 0);
              expect(availability.computeMaximumLevelAtPosition(Cartographic.fromRadians(0.0, 0.0))).toBe(1);
  
              // Make sure it isn't dependent on the order we add the rectangles.
              availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(1, 1, 0, 1, 0);
              availability.addAvailableTileRange(0, 0, 0, 0, 0);
              expect(availability.computeMaximumLevelAtPosition(Cartographic.fromRadians(0.0, 0.0))).toBe(1);
          });
  
          it('returns the higher level when on a boundary at level 1', function() {
              var availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(0, 0, 0, 1, 0);
              availability.addAvailableTileRange(1, 1, 1, 1, 1);
              expect(availability.computeMaximumLevelAtPosition(Cartographic.fromRadians(-Math.PI / 2.0, 0.0))).toBe(1);
          });
      });
  
      describe('computeBestAvailableLevelOverRectangle', function() {
          it('returns 0 if there are no rectangles', function() {
              var availability = createAvailability(geographic, 15);
              expect(availability.computeBestAvailableLevelOverRectangle(Rectangle.fromDegrees(1.0, 2.0, 3.0, 4.0))).toBe(0);
          });
  
          it('reports the correct level when entirely inside a worldwide rectangle of that level', function() {
              var availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(5, 0, 0, geographic.getNumberOfXTilesAtLevel(5) - 1, geographic.getNumberOfYTilesAtLevel(5) - 1);
              availability.addAvailableTileRange(6, 7, 8, 9, 10);
              expect(availability.computeBestAvailableLevelOverRectangle(Rectangle.fromDegrees(1.0, 2.0, 3.0, 4.0))).toBe(5);
          });
  
          it('reports the correct level when entirely inside a smaller rectangle of that level', function() {
              var availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(5, 0, 0, geographic.getNumberOfXTilesAtLevel(5) - 1, geographic.getNumberOfYTilesAtLevel(5) - 1);
              availability.addAvailableTileRange(6, 7, 8, 9, 10);
              var rectangle = geographic.tileXYToRectangle(8, 9, 6);
              expect(availability.computeBestAvailableLevelOverRectangle(rectangle)).toBe(6);
          });
  
          it ('reports the correct level when partially overlapping a smaller rectangle', function() {
              var availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(5, 0, 0, geographic.getNumberOfXTilesAtLevel(5) - 1, geographic.getNumberOfYTilesAtLevel(5) - 1);
              availability.addAvailableTileRange(6, 7, 8, 7, 8);
              var rectangle = geographic.tileXYToRectangle(7, 8, 6);
              rectangle.west -= 0.01;
              rectangle.east += 0.01;
              rectangle.south -= 0.01;
              rectangle.north += 0.01;
              expect(availability.computeBestAvailableLevelOverRectangle(rectangle)).toBe(5);
          });
  
          it('works with a rectangle crossing 180 degrees longitude', function() {
              var availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(5, 0, 0, geographic.getNumberOfXTilesAtLevel(5) - 1, geographic.getNumberOfYTilesAtLevel(5) - 1);
              availability.addAvailableTileRange(6, 0, 0, 10, geographic.getNumberOfYTilesAtLevel(6) - 1);
              availability.addAvailableTileRange(6, geographic.getNumberOfXTilesAtLevel(6) - 11, 0, geographic.getNumberOfXTilesAtLevel(6) - 1, geographic.getNumberOfYTilesAtLevel(6) - 1);
              var rectangle = Rectangle.fromDegrees(179.0, 45.0, -179.0, 50.0);
              expect(availability.computeBestAvailableLevelOverRectangle(rectangle)).toBe(6);
  
              rectangle = Rectangle.fromDegrees(45.0, 45.0, -45.0, 50.0);
              expect(availability.computeBestAvailableLevelOverRectangle(rectangle)).toBe(5);
          });
  
          it('works when four rectangles combine to cover the area', function() {
              var availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(5, 0, 0, geographic.getNumberOfXTilesAtLevel(5) - 1, geographic.getNumberOfYTilesAtLevel(5) - 1);
              availability.addAvailableTileRange(6, 0, 2, 1, 3);
              availability.addAvailableTileRange(6, 2, 0, 3, 1);
              availability.addAvailableTileRange(6, 0, 0, 1, 1);
              availability.addAvailableTileRange(6, 2, 2, 3, 3);
              var rectangle = geographic.tileXYToRectangle(0, 0, 4);
              expect(availability.computeBestAvailableLevelOverRectangle(rectangle)).toBe(6);
          });
      });
  
      describe('addAvailableTileRange', function() {
          it('keeps availability ranges sorted by rectangle', function() {
              var availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(0, 0, 0, 1, 0);
              availability.addAvailableTileRange(1, 0, 0, 3, 1);
              expect(availability.computeMaximumLevelAtPosition(new Cartographic(-Math.PI / 2.0, 0.0))).toBe(1);
  
              // We should get the same result adding them in the opposite order.
              availability = createAvailability(geographic, 15);
              availability.addAvailableTileRange(1, 0, 0, 3, 1);
              availability.addAvailableTileRange(0, 0, 0, 1, 0);
              expect(availability.computeMaximumLevelAtPosition(new Cartographic(-Math.PI / 2.0, 0.0))).toBe(1);
          });
      });
  });
  });
  