<?php

/**
 * @file
 * Entity CRUD API tests.
 */

use Drupal\simpletest\WebTestBase;

/**
 * Tests the basic Entity API.
 */
class EntityAPITestCase extends WebTestBase {

  public static function getInfo() {
    return array(
      'name' => 'Entity CRUD',
      'description' => 'Tests basic CRUD functionality.',
      'group' => 'Entity API',
    );
  }

  function setUp() {
    parent::setUp('entity', 'entity_test');
  }

  /**
   * Tests basic CRUD functionality of the Entity API.
   */
  function testCRUD() {
    $user1 = $this->drupalCreateUser();

    // Create some test entities.
    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
    $entity->save();
    $entity = entity_create('entity_test', array('name' => 'test2', 'uid' => $user1->uid));
    $entity->save();
    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
    $entity->save();

    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test')));

    $this->assertEqual($entities[0]->name, 'test', 'Created and loaded entity.');
    $this->assertEqual($entities[1]->name, 'test', 'Created and loaded entity.');

    // Test loading a single entity.
    $loaded_entity = entity_test_load($entity->id);
    $this->assertEqual($loaded_entity->id, $entity->id, 'Loaded a single entity by id.');

    // Test deleting an entity.
    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
    $entities[0]->delete();
    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
    $this->assertEqual($entities, array(), 'Entity deleted.');

    // Test updating an entity.
    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test')));
    $entities[0]->name = 'test3';
    $entities[0]->save();
    $entity = entity_test_load($entities[0]->id);
    $this->assertEqual($entity->name, 'test3', 'Entity updated.');

    // Try deleting multiple test entities by deleting all.
    $ids = array_keys(entity_test_load_multiple(FALSE));
    entity_test_delete_multiple($ids);

    $all = entity_test_load_multiple(FALSE);
    $this->assertTrue(empty($all), 'Deleted all entities.');
  }

  /**
   * Tests Entity getters/setters.
   */
  function testEntityGettersSetters() {
    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
    $this->assertNull($entity->get('uid'), 'Property is not set.');

    $entity->set('uid', $GLOBALS['user']->uid);
    $this->assertEqual($entity->uid, $GLOBALS['user']->uid, 'Property has been set.');

    $value = $entity->get('uid');
    $this->assertEqual($value, $entity->uid, 'Property has been retrieved.');

    // Make sure setting/getting translations boils down to setting/getting the
    // regular value as the entity and property are not translatable.
    $entity->set('uid', NULL, 'en');
    $this->assertNull($entity->uid, 'Language neutral property has been set.');

    $value = $entity->get('uid', 'en');
    $this->assertNull($value, 'Language neutral property has been retrieved.');
  }
}

/**
 * Tests entity translation.
 */
class EntityTranslationTestCase extends WebTestBase {

  public static function getInfo() {
    return array(
      'name' => 'Entity Translation',
      'description' => 'Tests entity translation functionality.',
      'group' => 'Entity API',
    );
  }

  function setUp() {
    parent::setUp('entity_test', 'language', 'locale');
    // Enable translations for the test entity type.
    variable_set('entity_test_translation', TRUE);

    // Create a translatable test field.
    $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
    $field = array(
      'field_name' => $this->field_name,
      'type' => 'text',
      'cardinality' => 4,
      'translatable' => TRUE,
    );
    field_create_field($field);
    $this->field = field_read_field($this->field_name);

    $instance = array(
      'field_name' => $this->field_name,
      'entity_type' => 'entity_test',
      'bundle' => 'entity_test',
    );
    field_create_instance($instance);
    $this->instance = field_read_instance('entity_test', $this->field_name, 'entity_test');

    // Create test languages.
    $this->langcodes = array();
    for ($i = 0; $i < 3; ++$i) {
      $language = (object) array(
        'langcode' => 'l' . $i,
        'name' => $this->randomString(),
      );
      $this->langcodes[$i] = $language->langcode;
      language_save($language);
    }
  }

  /**
   * Tests language related methods of the Entity class.
   */
  function testEntityLanguageMethods() {
    $entity = entity_create('entity_test', array(
      'name' => 'test',
      'uid' => $GLOBALS['user']->uid,
    ));
    $this->assertFalse($entity->language(), 'No entity language has been specified.');
    $this->assertFalse($entity->translations(), 'No translations are available');

    // Set the value in default language.
    $entity->set($this->field_name, array(0 => array('value' => 'default value')));
    // Get the value.
    $value = $entity->get($this->field_name);
    $this->assertEqual($value, array(0 => array('value' => 'default value')), 'Untranslated value retrieved.');

    // Set the value in a certain language. As the entity is not
    // language-specific it should use the default language and so ignore the
    // specified language.
    $entity->set($this->field_name, array(0 => array('value' => 'default value2')), $this->langcodes[1]);
    $value = $entity->get($this->field_name);
    $this->assertEqual($value, array(0 => array('value' => 'default value2')), 'Untranslated value updated.');
    $this->assertFalse($entity->translations(), 'No translations are available');

    // Test getting a field value using the default language for a not
    // language-specific entity.
    $value = $entity->get($this->field_name, $this->langcodes[1]);
    $this->assertEqual($value, array(0 => array('value' => 'default value2')), 'Untranslated value retrieved.');

    // Now, make the entity language-specific by assigning a language and test
    // translating it.
    $entity->langcode = $this->langcodes[0];
    $entity->{$this->field_name} = array();
    $this->assertEqual($entity->language(), language_load($this->langcodes[0]), 'Entity language retrieved.');
    $this->assertFalse($entity->translations(), 'No translations are available');

    // Set the value in default language.
    $entity->set($this->field_name, array(0 => array('value' => 'default value')));
    // Get the value.
    $value = $entity->get($this->field_name);
    $this->assertEqual($value, array(0 => array('value' => 'default value')), 'Untranslated value retrieved.');

    // Set a translation.
    $entity->set($this->field_name, array(0 => array('value' => 'translation 1')), $this->langcodes[1]);
    $value = $entity->get($this->field_name, $this->langcodes[1]);
    $this->assertEqual($value, array(0 => array('value' => 'translation 1')), 'Translated value set.');
    // Make sure the untranslated value stays.
    $value = $entity->get($this->field_name);
    $this->assertEqual($value, array(0 => array('value' => 'default value')), 'Untranslated value stays.');

    $translations[$this->langcodes[1]] = language_load($this->langcodes[1]);
    $this->assertEqual($entity->translations(), $translations, 'Translations retrieved.');

    // Try to get a not available translation.
    $value = $entity->get($this->field_name, $this->langcodes[2]);
    $this->assertNull($value, 'A translation that is not available is NULL.');
  }
}

/**
 * Tests Entity API base functionality.
 */
class EntityAPIInfoTestCase extends WebTestBase  {

  public static function getInfo() {
    return array(
      'name' => 'Entity info',
      'description' => 'Makes sure entity info is accurately cached.',
      'group' => 'Entity API',
    );
  }

  /**
   * Ensures entity info cache is updated after changes.
   */
  function testEntityInfoChanges() {
    module_enable(array('entity_cache_test'));
    $entity_info = entity_get_info();
    $this->assertTrue(isset($entity_info['entity_cache_test']), 'Test entity type found.');

    // Change the label of the test entity type and make sure changes appear
    // after flushing caches.
    variable_set('entity_cache_test_label', 'New label.');
    $this->resetAll();
    $info = entity_get_info('entity_cache_test');
    $this->assertEqual($info['label'], 'New label.', 'New label appears in entity info.');

    // Disable the providing module and make sure the entity type is gone.
    module_disable(array('entity_cache_test', 'entity_cache_test_dependency'));
    $entity_info = entity_get_info();
    $this->assertFalse(isset($entity_info['entity_cache_test']), 'Entity type of the providing module is gone.');
  }

  /**
   * Tests entity info cache after enabling a module with a dependency on an entity providing module.
   *
   * @see entity_cache_test_watchdog()
   */
  function testEntityInfoCacheWatchdog() {
    module_enable(array('entity_cache_test'));
    $info = variable_get('entity_cache_test');
    $this->assertEqual($info['label'], 'Entity Cache Test', 'Entity info label is correct.');
    $this->assertEqual($info['controller class'], 'Drupal\entity\EntityController', 'Entity controller class info is correct.');
  }
}
