<?php

/**
 * @file
 * Definition of Drupal\filefield_sources\Tests\ReferenceSourceTest.
 */

namespace Drupal\filefield_sources\Tests;

use Drupal\Component\Utility\Unicode;

/**
 * Tests the reference source.
 *
 * @group filefield_sources
 */
class ReferenceSourceTest extends FileFieldSourcesTestBase {

  /**
   * Tests reference source enabled.
   */
  public function testReferenceSourceEnabled() {

    // Create test file.
    $file = $this->createPermanentFileEntity();

    $this->enableSources(array(
      'reference' => TRUE,
    ));

    // Upload a file by 'Reference' source.
    $this->uploadFileByReferenceSource($file->id(), $file->getFilename(), 0);

    // We can only refer one file on single value field.
    $this->assertNoFieldByXPath('//input[@type="submit"]', t('Select'), t('After uploading a file, "Select" button is no longer displayed.'));

    // Remove uploaded file.
    $this->removeFile($file->getFileName(), 0);

    // Can select file again.
    $this->assertFieldByXpath('//input[@type="submit"]', t('Select'), 'After clicking the "Remove" button, the "Select" button is displayed.');
  }

  /**
   * Test autocompletion.
   */
  public function testAutocompletion() {
    // Create test file.
    $file = $this->createPermanentFileEntity();
    $filename = $file->getFileName();
    $first_character = substr($filename, 0, 1);
    $second_character = substr($filename, 1, 1);

    // Switch to 'Starts with' match type.
    $this->updateFilefieldSourcesSettings('source_reference', 'autocomplete', '0');

    // STARTS_WITH: empty results.
    $query = $this->findCharacterNotInString($first_character);
    $autocomplete_result = $this->drupalGetJSON('file/reference/node/' . $this->typeName . '/' . $this->fieldName, array('query' => array('q' => $query)));
    $this->assertEqual($autocomplete_result, array(), "No files that have name starts with '$query'");

    // STARTS_WITH: not empty results.
    $query = $first_character;
    $autocomplete_result = $this->drupalGetJSON('file/reference/node/' . $this->typeName . '/' . $this->fieldName, array('query' => array('q' => $query)));
    $this->assertEqual($autocomplete_result[0]['label'], $filename, 'Autocompletion return correct label.');
    $this->assertEqual($autocomplete_result[0]['value'], $filename . ' [fid:' . $file->id() . ']', 'Autocompletion return correct value.');

    // Switch to 'Contains' match type.
    $this->updateFilefieldSourcesSettings('source_reference', 'autocomplete', '1');

    // CONTAINS: empty results.
    $query = $this->findCharacterNotInString($filename);
    $autocomplete_result = $this->drupalGetJSON('file/reference/node/' . $this->typeName . '/' . $this->fieldName, array('query' => array('q' => $query)));
    $this->assertEqual($autocomplete_result, array(), "No files that have name contains '$query'");

    // CONTAINS: not empty results.
    $query = $second_character;
    $autocomplete_result = $this->drupalGetJSON('file/reference/node/' . $this->typeName . '/' . $this->fieldName, array('query' => array('q' => $query)));
    $this->assertEqual($autocomplete_result[0]['label'], $filename, 'Autocompletion return correct label.');
    $this->assertEqual($autocomplete_result[0]['value'], $filename . ' [fid:' . $file->id() . ']', 'Autocompletion return correct value.');
  }

  /**
   * Find the first character that is not in string.
   *
   * Only find for lower case character.
   *
   * @param string $string
   *   String to check.
   *
   * @return string
   *   First character that is not in the string.
   */
  protected function findCharacterNotInString($string) {
    // Only check for lower case string.
    $string = Unicode::strtolower($string);

    // Lower case characters and numbers generated by
    // \Drupal\simpletest\TestBase::randomMachineName().
    $values = array_merge(range(97, 122), range(48, 57));
    foreach ($values as $value) {
      $character = chr($value);
      if (strpos($string, $character) === FALSE) {
        return $character;
      }
    }
  }

}
