You are here

ConditionTest.php in Zircon Profile 8

Same filename and directory in other branches
  1. 8.0 core/tests/Drupal/Tests/Core/Database/ConditionTest.php

File

core/tests/Drupal/Tests/Core/Database/ConditionTest.php
View source
<?php

/**
 * @file
 * Contains \Drupal\Tests\Core\Database\ConditionTest.
 */
namespace Drupal\Tests\Core\Database;

use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Database\Query\PlaceholderInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;

/**
 * @coversDefaultClass \Drupal\Core\Database\Query\Condition
 *
 * @group Database
 */
class ConditionTest extends UnitTestCase {

  /**
   * @covers ::compile
   */
  public function testSimpleCondition() {
    $connection = $this
      ->prophesize(Connection::class);
    $connection
      ->escapeField('name')
      ->will(function ($args) {
      return preg_replace('/[^A-Za-z0-9_.]+/', '', $args[0]);
    });
    $connection
      ->mapConditionOperator('=')
      ->willReturn([
      'operator' => '=',
    ]);
    $connection = $connection
      ->reveal();
    $query_placeholder = $this
      ->prophesize(PlaceholderInterface::class);
    $counter = 0;
    $query_placeholder
      ->nextPlaceholder()
      ->will(function () use (&$counter) {
      return $counter++;
    });
    $query_placeholder
      ->uniqueIdentifier()
      ->willReturn(4);
    $query_placeholder = $query_placeholder
      ->reveal();
    $condition = new Condition('AND');
    $condition
      ->condition('name', [
      'value',
    ]);
    $condition
      ->compile($connection, $query_placeholder);
    $this
      ->assertEquals(' (name = :db_condition_placeholder_0) ', $condition
      ->__toString());
    $this
      ->assertEquals([
      ':db_condition_placeholder_0' => 'value',
    ], $condition
      ->arguments());
  }

  /**
   * @covers ::compile
   *
   * @dataProvider dataProviderTestCompileWithKnownOperators()
   *
   * @param string $expected
   *   The expected generated SQL condition.
   * @param string $field
   *   The field to pass into the condition() method.
   * @param mixed $value
   *   The value to pass into the condition() method.
   * @param string $operator
   *   The operator to pass into the condition() method.
   * @param mixed $expected_arguments
   *   (optional) The expected set arguments.
   */
  public function testCompileWithKnownOperators($expected, $field, $value, $operator, $expected_arguments = NULL) {
    $connection = $this
      ->prophesize(Connection::class);
    $connection
      ->escapeField(Argument::any())
      ->will(function ($args) {
      return preg_replace('/[^A-Za-z0-9_.]+/', '', $args[0]);
    });
    $connection
      ->mapConditionOperator(Argument::any())
      ->willReturn(NULL);
    $connection = $connection
      ->reveal();
    $query_placeholder = $this
      ->prophesize(PlaceholderInterface::class);
    $counter = 0;
    $query_placeholder
      ->nextPlaceholder()
      ->will(function () use (&$counter) {
      return $counter++;
    });
    $query_placeholder
      ->uniqueIdentifier()
      ->willReturn(4);
    $query_placeholder = $query_placeholder
      ->reveal();
    $condition = new Condition('AND');
    $condition
      ->condition($field, $value, $operator);
    $condition
      ->compile($connection, $query_placeholder);
    $this
      ->assertEquals($expected, $condition
      ->__toString());
    if (isset($expected_arguments)) {
      $this
        ->assertEquals($expected_arguments, $condition
        ->arguments());
    }
  }

  /**
   * Provides a list of known operations and the expected output.
   *
   * @return array
   */
  public function dataProviderTestCompileWithKnownOperators() {

    // Below are a list of commented out test cases, which should work but
    // aren't directly supported by core, but instead need manual handling with
    // prefix/suffix at the moment.
    $data = [];
    $data[] = [
      ' (name = :db_condition_placeholder_0) ',
      'name',
      'value',
      '=',
    ];
    $data[] = [
      ' (name != :db_condition_placeholder_0) ',
      'name',
      'value',
      '!=',
    ];
    $data[] = [
      ' (name <> :db_condition_placeholder_0) ',
      'name',
      'value',
      '<>',
    ];
    $data[] = [
      ' (name >= :db_condition_placeholder_0) ',
      'name',
      'value',
      '>=',
    ];
    $data[] = [
      ' (name > :db_condition_placeholder_0) ',
      'name',
      'value',
      '>',
    ];
    $data[] = [
      ' (name <= :db_condition_placeholder_0) ',
      'name',
      'value',
      '<=',
    ];
    $data[] = [
      ' (name < :db_condition_placeholder_0) ',
      'name',
      'value',
      '<',
    ];

    // $data[] = [' ( GREATEST (1, 2, 3) ) ', '', [1, 2, 3], 'GREATEST'];
    $data[] = [
      ' (name IN  (:db_condition_placeholder_0, :db_condition_placeholder_1, :db_condition_placeholder_2)) ',
      'name',
      [
        '1',
        '2',
        '3',
      ],
      'IN',
    ];
    $data[] = [
      ' (name NOT IN  (:db_condition_placeholder_0, :db_condition_placeholder_1, :db_condition_placeholder_2)) ',
      'name',
      [
        '1',
        '2',
        '3',
      ],
      'NOT IN',
    ];

    // $data[] = [' ( INTERVAL (1, 2, 3) ) ', '', [1, 2, 3], 'INTERVAL'];
    $data[] = [
      ' (name IS NULL ) ',
      'name',
      NULL,
      'IS NULL',
    ];
    $data[] = [
      ' (name IS NOT NULL ) ',
      'name',
      NULL,
      'IS NOT NULL',
    ];
    $data[] = [
      ' (name IS :db_condition_placeholder_0) ',
      'name',
      'TRUE',
      'IS',
    ];

    // $data[] = [' ( LEAST (1, 2, 3) ) ', '', [1, 2, 3], 'LEAST'];
    $data[] = [
      " (name LIKE :db_condition_placeholder_0 ESCAPE '\\\\') ",
      'name',
      '%muh%',
      'LIKE',
      [
        ':db_condition_placeholder_0' => '%muh%',
      ],
    ];
    $data[] = [
      " (name NOT LIKE :db_condition_placeholder_0 ESCAPE '\\\\') ",
      'name',
      '%muh%',
      'NOT LIKE',
      [
        ':db_condition_placeholder_0' => '%muh%',
      ],
    ];
    $data[] = [
      " (name BETWEEN :db_condition_placeholder_0 AND :db_condition_placeholder_1) ",
      'name',
      [
        1,
        2,
      ],
      'BETWEEN',
      [
        ':db_condition_placeholder_0' => 1,
        ':db_condition_placeholder_1' => 2,
      ],
    ];

    // $data[] = [" (name NOT BETWEEN :db_condition_placeholder_0 AND :db_condition_placeholder_1) ", 'name', [1, 2], 'NOT BETWEEN', [':db_condition_placeholder_0' => 1, ':db_condition_placeholder_1' => 2]];
    // $data[] = [' ( STRCMP (name, :db_condition_placeholder_0) ) ', '', ['test-string'], 'STRCMP', [':db_condition_placeholder_0' => 'test-string']];
    // $data[] = [' (EXISTS ) ', '', NULL, 'EXISTS'];
    // $data[] = [' (name NOT EXISTS ) ', 'name', NULL, 'NOT EXISTS'];
    return $data;
  }

  /**
   * @covers ::compile
   *
   * @expectedException \PHPUnit_Framework_Error
   * @dataProvider providerTestCompileWithSqlInjectionForOperator
   */
  public function testCompileWithSqlInjectionForOperator($operator) {
    $connection = $this
      ->prophesize(Connection::class);
    $connection
      ->escapeField(Argument::any())
      ->will(function ($args) {
      return preg_replace('/[^A-Za-z0-9_.]+/', '', $args[0]);
    });
    $connection
      ->mapConditionOperator(Argument::any())
      ->willReturn(NULL);
    $connection = $connection
      ->reveal();
    $query_placeholder = $this
      ->prophesize(PlaceholderInterface::class);
    $counter = 0;
    $query_placeholder
      ->nextPlaceholder()
      ->will(function () use (&$counter) {
      return $counter++;
    });
    $query_placeholder
      ->uniqueIdentifier()
      ->willReturn(4);
    $query_placeholder = $query_placeholder
      ->reveal();
    $condition = new Condition('AND');
    $condition
      ->condition('name', 'value', $operator);
    $condition
      ->compile($connection, $query_placeholder);
  }
  public function providerTestCompileWithSqlInjectionForOperator() {
    $data = [];
    $data[] = [
      "IS NOT NULL) ;INSERT INTO {test} (name) VALUES ('test12345678'); -- ",
    ];
    $data[] = [
      "IS NOT NULL) UNION ALL SELECT name, pass FROM {users_field_data} -- ",
    ];
    $data[] = [
      "IS NOT NULL) UNION ALL SELECT name FROM {TEST_UPPERCASE} -- ",
    ];
    $data[] = [
      "= 1 UNION ALL SELECT password FROM user WHERE uid =",
    ];
    return $data;
  }

}

Classes

Namesort descending Description
ConditionTest @coversDefaultClass \Drupal\Core\Database\Query\Condition