<?php

/**
 * @file
 * Main OpenLayers Test file
 *
 * This file contains the tests for the openlayers
 * module.  Please note that since this module
 * depends heavily on Javascript, these tests are
 * limited in ensuring that the OpenLayers module
 * functions 100% correctly.
 *
 * For reference, @see:
 * http://api.drupal.org/api/drupal/modules--simpletest--drupal_web_test_case.php/class/DrupalWebTestCase/7
 *
 * @ingroup openlayers
 */

/**
 * Test the OpenLayers core functionality.
 */
class OpenLayersCore extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'OpenLayers Core',
      'description' => 'Tests OpenLayers core functions.',
      'group' => 'OpenLayers',
    );
  }

  function setUp() {
    // Install modules
    parent::setUp('openlayers', 'ctools', 'openlayers_ui', 'openlayers_test');
  }

  /**
   * Test openlayers_include
   */
  function testInclude() {
    $user = $this->drupalCreateUser(array('administer openlayers'));
    $this->drupalLogin($user);

    // Go to test page and ensure includes happened.
    $this->drupalGet('admin/structure/openlayers/test');
    $this->assertRaw('openlayers.css', t('The OpenLayers CSS file was included'));
    $this->assertRaw('openlayers.js', t('The OpenLayers JS file was included'));
  }

  /**
   * Test map rendering
   */
  function testRender() {
    $rendered = openlayers_render_map();
    //$this->verbose('Map output: ' . var_export($rendered, TRUE));

    // Check output
    $this->assertTrue((stripos($rendered, 'default') !== FALSE), t('Default name found'));
    $this->assertTrue((stripos($rendered, 'id="openlayers-container-openlayers-map') !== FALSE),
      t('Container ID found'));
    $this->assertTrue((stripos($rendered, 'id="openlayers-map') !== FALSE),
      t('Map ID found'));
    $this->assertTrue((stripos($rendered, 'class="openlayers-map') !== FALSE),
      t('Map Class found'));
  }
}

/**
 * Test OpenLayers basic UI
 */
class OpenLayersUI extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'OpenLayers UI',
      'description' => 'Tests OpenLayers basic UI.',
      'group' => 'OpenLayers',
    );
  }

  function setUp() {
    // Install modules
    parent::setUp('openlayers', 'ctools', 'openlayers_ui', 'openlayers_test');
  }

  /**
   * Ensure that the source can be updated
   */
  function testSourceChange() {
    $user = $this->drupalCreateUser(array('administer openlayers'));
    $this->drupalLogin($user);

    // Update source settings
    $new_openlayers_source = 'http://openlayers.org/nightly/OpenLayers.js';
    $openlayers_settings = array(
      'openlayers_source_type' => 'external',
      'openlayers_source_external' => $new_openlayers_source
    );
    $this->drupalPost('admin/structure/openlayers', $openlayers_settings, t('Save configuration'));
    // Go to map page
    $this->drupalGet('admin/structure/openlayers');
    $this->assertResponse(200, t('User can reach the settings page.'));
    // Check that the new source change is represented
    $this->drupalGet('admin/structure/openlayers');
    $this->assertRaw($new_openlayers_source, t('The OpenLayers source was changed'));
  }
}

/**
 * Test OpenLayers maps.
 */
class OpenLayersMaps extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'OpenLayers Maps',
      'description' => 'Tests the OpenLayers maps system.',
      'group' => 'OpenLayers',
    );
  }

  function setUp() {
    // Install modules
    parent::setUp('openlayers', 'ctools', 'openlayers_ui', 'openlayers_test');
  }

  /**
   * Ensure that the map shows up in the interface
   */
  function testOpenLayersMaps() {
    $user = $this->drupalCreateUser(array('administer openlayers'));
    $this->drupalLogin($user);

    // Go to map page
    $this->drupalGet('admin/structure/openlayers/maps');
    $this->assertResponse(200, t('User can reach map list.'));

    // Ensure that the default test is listed
    $this->assertText(t('Default Map'),
      t('Assert that the default map\'s title appears.'));

    // Maps
    $this->drupalGet('admin/structure/openlayers/maps/default/export');
    $this->assertResponse(200, t('User can reach default map export page.'));

    $this->drupalGet('admin/structure/openlayers/maps/clone/default');
    $this->assertResponse(200, t('User can reach default map clone page.'));

    $this->drupalGet('admin/structure/openlayers/maps/add');
    $this->assertResponse(200, t('User can reach map add page.'));
  }

  /**
   * Add a new map
   */
  function testMapAdd() {
    $user = $this->drupalCreateUser(array('administer openlayers'));
    $this->drupalLogin($user);

    // Add new map.  Add scaleline so we can look for it later
    $map_settings = array(
      'name' => 'testing_map',
      'title' => t('Testing Map'),
      'description' => t('Testing Map description.'),
      'behaviors[openlayers_behavior_scaleline][enabled]' => TRUE,
    );
    $this->drupalPost('admin/structure/openlayers/maps/add', $map_settings, t('Save'));
    $this->assertText(t('Map saved.'), t('The map was successfully saved.'));

    // Remove Map
    $this->drupalPost('admin/structure/openlayers/maps/list/' . $map_settings['name'] . '/delete',
      array(), t('Delete'));
    $this->assertText('Map was deleted.', t('Map removed succesfully.'));
  }
}

/**
 * Test OpenLayers styles.
 */
class OpenLayersStyles extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'OpenLayers Styles',
      'description' => 'Tests the OpenLayers Styles system.',
      'group' => 'OpenLayers',
    );
  }

  function setUp() {
    // Install modules
    parent::setUp('openlayers', 'ctools', 'openlayers_ui', 'openlayers_test');
  }

  function testOpenLayersStyles() {
    $user = $this->drupalCreateUser(array('administer openlayers'));
    $this->drupalLogin($user);

    // New style.
    $new_style = array(
      'name' => 'unitstyle',
      'title' => 'Unit Style',
      'description' => 'Unit Style for Drupal',
    );

    // Check basic navigation.
    $this->drupalGet('admin/structure/openlayers/styles/list/default/export');
    $this->assertResponse(200, t('User can reach default style export page.'));
    $this->drupalGet('admin/structure/openlayers/styles/add');
    $this->assertResponse(200, t('User can reach style add page.'));

    // Add new style.
    $this->drupalPost('admin/structure/openlayers/styles/add', $new_style, t('Save'));
    $this->assertText(t('Style saved.'),
      t('The style was successfully saved.'));

    // Test that the style shows up in the style list.
    $this->drupalGet('admin/structure/openlayers/styles');
    $this->assertRaw(t('Unit Style'),
      t('A new style has been added by the test'));

    // Test removing style.
    $this->drupalPost('admin/structure/openlayers/styles/list/unitstyle/delete',
      array(), t('Delete'));
    $this->assertText('Style was deleted.',
      t('Style removed succesfully.'));
  }
}

/**
 * Test OpenLayers layers.
 */
class OpenLayersLayers extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'OpenLayers Layers',
      'description' => 'Tests the OpenLayers Layers system.',
      'group' => 'OpenLayers',
    );
  }

  function setUp() {
    // Install modules
    parent::setUp('openlayers', 'ctools', 'openlayers_ui', 'openlayers_test');
  }

  function testOpenLayersLayers() {
    $user = $this->drupalCreateUser(array('administer openlayers'));
    $this->drupalLogin($user);

    // New layers to add
    $layer_inputs = array(
      'openlayers_layer_type_osm' => array(
        'name' => 'unitlayerosm',
        'title' => 'Unit Layer',
        'description' => 'Unit Layer for Drupal',
      ),
      'openlayers_layer_type_xyz' => array(
        'name' => 'unitlayerxyz',
        'title' => 'Unit Layer',
        'description' => 'Unit Layer for Drupal',
      ),
      'openlayers_layer_type_kml' => array(
        'name' => 'unitlayerkml',
        'title' => 'Unit Layer',
        'description' => 'Unit Layer for Drupal',
        'openlayers_layer_type_kml[method]' => 'raw',
        'openlayers_layer_type_kml[raw]' => $this->randomString(32)
      ),
      'openlayers_layer_type_wms' => array(
        'name' => 'unitlayerwms',
        'title' => 'Unit Layer',
        'description' => 'Unit Layer for Drupal',
      ),
      'openlayers_layer_type_cloudmade' => array(
        'name' => 'unitlayercloudmade',
        'title' => 'Unit Layer',
        'description' => 'Unit Layer for Drupal',
      ),
      'openlayers_layer_type_bing' => array(
        'name' => 'unitlayerbing',
        'title' => 'Unit Layer',
        'description' => 'Unit Layer for Drupal',
      ),
      'openlayers_layer_type_google' => array(
        'name' => 'unitlayergoogle',
        'title' => 'Unit Layer',
        'description' => 'Unit Layer for Drupal',
      )
    );

    // Basic navigation.
    $this->drupalGet('admin/structure/openlayers/layers/add');
    $this->assertResponse(200, t('User can reach layer add page.'));

    // Go through each new layer for testing.
    foreach ($layer_inputs as $layer_type => $input_data) {
      // Test saving new layer.
      $input_data['layer_type'] = $layer_type;
      $this->drupalPost('admin/structure/openlayers/layers/add',
        $input_data, t('Save'));
      $this->assertText(t('Layer saved.'),
        t('The layer was successfully saved.'));

      // Ensure that the layer shows up in the list.
      $this->drupalGet('admin/structure/openlayers/layers');
      $this->assertRaw($input_data['title'],
        t('A new layer of layer type %type_name has been added by the test',
          array('%type_name' => $layer_type)));

      // Test removing layer.
      $this->drupalPost('admin/structure/openlayers/layers/list/' .
        $input_data['name'] . '/delete', array(), t('Delete'));
      $this->assertText('Layer was deleted.',
        t('Layer removed succesfully.'));
    }
  }
}

/**
 * Test Case for Map Alters
 */
class OpenLayersMapAlters extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'OpenLayers Map Alters',
      'description' => 'Tests the OpenLayers map alter hooks.',
      'group' => 'OpenLayers',
    );
  }

  function setUp() {
    // Install modules
    parent::setUp('openlayers', 'ctools', 'openlayers_ui', 'openlayers_test');
  }

  function testOpenLayersMapAlters() {
    $user = $this->drupalCreateUser(array('administer openlayers'));
    $this->drupalLogin($user);

    // Styles
    $this->drupalGet('admin/structure/openlayers/test');
    $this->assertText(t('OpenLayers preprocess map alter hook fired.'),
      t('Map preprocess alter fired correctly.'));
    $this->assertText(t('OpenLayers map alter hook fired.'),
      t('Map alter fired correctly.'));
  }
}

/**
 * OpenLayers Unit Tests
 *
 * Do not use t() in Unit tests.
 * https://drupal.org/node/811254
 *
 * Unit tests do not bootstrap Drupal very
 * far which makes them a bit useless if
 * we are utilizing Drupal API functions.
 */
class OpenLayersUnitTests extends DrupalUnitTestCase {
  public static function getInfo() {
    return array(
      'name' => 'OpenLayers Unit Tests',
      'description' => 'Tests functions for OpenLayers.',
      'group' => 'OpenLayers',
    );
  }

  function testOpenLayersStylePath() {
    module_load_include('inc', 'openlayers', 'includes/openlayers.render');
    global $base_url;

    // Full URL
    $path = 'http://example.org/sites/all/modules/openlayers/example/${path}.jpg';
    $styled_path = openlayers_style_path($path);
    $this->assertTrue($styled_path === $path, 'OpenLayers Style Path function with full URL.');

    // Just replacement value
    $path = '${path}';
    $styled_path = openlayers_style_path($path);
    $this->assertTrue($styled_path === $path, 'OpenLayers Style Path function with just replacement value.');

    // Relative URL
    $path = 'sites/all/modules/openlayers/example/${path}.jpg';
    $styled_path = openlayers_style_path($path);
    $this->assertTrue($styled_path === $base_url . '/' . $path, 'OpenLayers Style Path function with relative URL.');
  }
}
