<?php

/**
 * @file
 * Tests for block.module.
 */

abstract class BeanSetup extends DrupalWebTestCase {
  protected $admin_user;
  protected $plugin_name;


  function setUp() {
    parent::setUp('bean', 'ctools', 'entity', 'bean_test', 'block');
    $this->addAdminUser();
  }

  function addAdminUser() {
    $permissions = array_keys(bean_permission());
    $permissions += array(
      'administer blocks',
      'access administration pages',
      'access content',
    );
    $this->admin_user = $this->drupalCreateUser($permissions);
    $this->drupalLogin($this->admin_user);

    // Test plugin name
    $this->plugin_name = 'test_bean';
  }
}

/**
 * Test specific parts of the bean type class
 */
class BeanUnitTests extends BeanSetup {
  public static function getInfo() {
    return array(
      'name' => 'Bean Unit Tests',
      'description' => 'Test that the individual methods of the bean and bean type classes work.',
      'group' => 'Bean',
    );

  }

  /**
   * Test the URL of the bean types
   */
  function testBeanTypeURL() {
    $test_plugin = array(
      'label' => t('Test'),
      'name' => 'test_name',
      'description' => t('This is a test plugin'),
      'handler' => array(
        'class' => 'BeanTestPlugin',
        'parent' => 'bean',
      ),
    );

    $bean_type = new BeanDefault($test_plugin);
    $bean_type->type = "test_name";
    $this->assertEqual($bean_type->buildURL(), "test-name", t('URL is formatted correctly.'));
  }
}

/**
 * Test the API
 */
class BeanTestPlugins extends BeanSetup {

  public static function getInfo() {
    return array(
      'name' => 'Bean Plugin',
      'description' => 'Test the bean plugin API.',
      'group' => 'Bean',
    );
  }

  /**
   * Test loading of the plugin
   */
  function testBeanLoadPlugin() {
    // Load the class
    $plugin_class = bean_load_plugin_class('test_bean');
    $plugin_class_name = get_class($plugin_class);

    // Plugin should be implement the BeanTypePluginInterface interface
    if (bean_check_plugin_class($plugin_class_name)) {
      $this->pass(t('Bean type should use the BeanTypePluginInterface interface'));
    }
    else {
      $this->fail(t('Bean type should use the BeanTypePluginInterface interface'));
    }

    // Verify that a bean plugin with an invalid class does not load
    $this->assertFalse(bean_load_plugin_class('test_no_bean'), t('Bean type should not load with an invalid class'));
    $this->assertFalse(bean_load_plugin_class('test_wrong_class'), t('Bean type should not load with an invalid class'));
  }

  /**
   * Verity that the correct links appear
   */
  function testBeanTypeLinks() {
    $this->drupalGet('block/add');
    // Verify the block add pages exists
    $this->assertResponse(200, t('Block Add Page is accessible'));

    // There should 2 plugins links
    $this->assertLinkByHref('block/add/test-bean', 0, t('A link to the bean add for each type should exist'));
    $this->assertLinkByHref('block/add/test-bean-2', 0, t('A link to the bean add for each type should exist'));
    $this->assertNoLinkByHref('block/add/test-no-bean', t('A link to an invalid bean type should not exist'));
    $this->assertNoLinkByHref('block/add/test-wrong-class', t('A link to an invalid bean type should not exist'));
  }


  /**
   * Test the bean form
   */
  function testBeanTypeForm() {

    foreach (bean_get_types() as $type) {
      $this->drupalGet("block/add/{$type->buildUrl()}");

      // Verify the core fields are there
      $this->assertFieldById('edit-label', '', t('Label exists on bean add form.'));
      $this->assertFieldById('edit-title', '', t('Title exists on bean add form.'));
      $this->assertFieldById('edit-view-mode', '', t('View Mode exists on bean add form.'));
    }
  }
}

class BeanTests extends BeanSetup {
  public static function getInfo() {
    return array(
      'name' => 'Bean functionality',
      'description' => 'Test the bean API.',
      'group' => 'Bean',
    );
  }

  /**
   * Test the bean API
   */
  public function testBeanAPI() {
    $values = array(
      'delta' => 'test_bean',
      'label' => t('Test Bean'),
      'title' => t('Test Bean'),
      'type' => $this->plugin_name,
      'view_mode' => 'default',
      'data' => array(
        'test_boolean' => FALSE,
        'test_string' => t('New String'),
        'test_array' => array(
          'test_array_1' => 'new_value',
        ),
      ),
    );

    $bean = bean_create($values);
    $this->assertTrue(bean_save($bean), t('Bean was saved'));

    $values['label'] = $values['title'] = t('Test Bean 2');
    $values['delta'] = 'test_bean2';
    $bean = bean_create($values);
    $this->assertTrue(bean_save($bean), t('Bean was saved'));

    $beans = array_values(bean_load_multiple(FALSE, array('type' => $this->plugin_name)));
    $this->assertEqual($beans[0]->label, t('Test Bean'), 'Created and loaded bean.');
    $this->assertEqual($beans[1]->label, t('Test Bean 2'), 'Created and loaded bean.');

    // Delete the first bean
    $delete_id = $beans[0]->bid;
    bean_delete($beans[0]);

    $bean = $beans[1];

    // Try to load deleted bean
    $delete_bean = bean_load($delete_id, TRUE);
    $this->assertFalse($delete_bean, t('Bean Deleted'));

    // Load by delta
    $delta_bean = bean_load_delta('test_bean2', TRUE);
    $this->assertEqual($delta_bean->identifier(), $bean->identifier(), t('Bean loaded by delta'));

    // Test devel pages
    if (module_exists('devel')) {
      $this->drupalGet("block/{$bean->identifier()}/devel");
      $this->assertResponse(200, t('Devel load page is viewable'));
      $this->assertText($bean->label(), t('Devel load page is viewable'));

      $this->drupalGet("block/{$bean->identifier()}/devel/render");
      $this->assertResponse(200, t('Devel render page is viewable'));
      $this->assertText($bean->label(), t('Devel render page is viewable'));
    }

    // Test a bean with an invalid plugin
    $values['type'] = 'fake_plugin';
    $values['delta'] = 'fake_bean_plugin';
    $bean = bean_create($values);
    $this->assertTrue(bean_save($bean), t('Bean with invalid type was saved'));
    $this->assertTrue(bean_load_delta('fake_bean_plugin'), t('Bean with an invalid plugin is loaded'));

    // Test a bean with a plugin with an invalid class
    $values['delta'] = 'missing_class';
    $values['type'] = 'test_no_bean';
    $bean = bean_create($values);
    $this->assertTrue(bean_save($bean), t('Bean with a plugin that has an invalid class is saved'));
    $this->assertTrue(bean_load_delta('missing_class'), t('Bean with a plugin that has an invalid class is loaded'));
  }

  /**
   * Tests viewing beans.
   */
  function testRendering() {
    $values = array(
      'delta' => 'test_bean',
      'label' => t('Test Bean'),
      'title' => t('Test Bean'),
      'type' => $this->plugin_name,
      'view_mode' => 'default',
      'data' => array(
        'test_boolean' => FALSE,
        'test_string' => t('New String'),
        'test_array' => array(
          'test_array_1' => 'new_value',
        ),
      ),
    );

    $bean = bean_create($values);
    bean_save($bean);

    $this->drupalGet($bean->url());
    $this->assertResponse(200, t('Bean Page is viewable'));
    $this->assertText($bean->label(), t('Bean Page is viewable'));

    $this->drupalGet("block/{$bean->identifier()}");
    $this->assertResponse(200, t('Legacy Bean Page is viewable'));
    $this->assertText($bean->label(), t('Legacy Bean Page is viewable'));
  }
}

/**
 * This should test the access to beans
 */
class BeanAccess extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Bean Access',
      'description' => 'Test the access to beans.',
      'group' => 'Bean',
    );
  }

  /**
   * Test
   */
  public function testAccess() {
    $this->assertTrue(TRUE, t('Not implemented'));
  }
}

/**
 * Integration Tests
 */
class BeanIntegrationTests extends DrupalWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Bean Integration Tests',
      'description' => 'Make sure everything works from the front end.',
      'group' => 'Bean',
    );
  }

  protected function setUp() {
    parent::setUp();
  }

  /**
   * Test that reactions when there are no bean types
   */

  /**
   * Test adding a bean
   */
  public function testBeanAdd() {
    $this->assertTrue(TRUE, t('Not implemented'));
  }

  /**
   * Test Editing a Bean
   */
  public function testBeanEdit() {
    $this->assertTrue(TRUE, t('Not implemented'));
  }

  /**
   * Test Deleting a Bean
   */
  public function testBeanDelete() {
    $this->assertTrue(TRUE, t('Not implemented'));
  }

  /**
   * Place a bean block on the page
   */
  public function testBeanPlacement() {
    $this->assertTrue(TRUE, t('Not implemented'));
  }
}
