search_api_meilisearch-1.0.x-dev/tests/src/Kernel/Backend/QueryFilterTest.php

tests/src/Kernel/Backend/QueryFilterTest.php
<?php

namespace Drupal\Tests\search_api_meilisearch\Kernel\Backend;

use Drupal\Core\Logger\LoggerChannel;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\search_api\SearchApiException;
use PHPUnit\Framework\Attributes\Group;

/**
 * Provides tests for filtered searching via search api index.
 *
 * @group search_api_meilisearch
 */
#[Group('search_api_meilisearch')]
class QueryFilterTest extends BackendKernelTestBase {

  protected const TEST_INDEX = 'kernel_backend_filter_test_index';

  /**
   * Tests search with various query conditions.
   */
  public function testSearchConditions(): void {
    $this->prepareTestIndex(self::TEST_INDEX);
    $this->populateIndex();

    // Search without any conditions.
    $results = $this->index->query()->range()->execute();
    $this->assertCount(5, $results->getResultItems());

    // Search with a condition that yields no results.
    $query = $this->index->query()->range();
    $query->addCondition('name', 'Test entity');

    $result = $query->execute();
    $this->assertEquals(0, $result->getResultCount());

    // Search with a single condition.
    $query = $this->index->query()->range();
    $query->addCondition('name', 'Test entity 1');

    $result = $query->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search with a negated single condition.
    $query = $this->index->query()->range();
    $query->addCondition('name', 'Test entity 1', '<>');

    $result = $query->execute();
    $this->assertEquals(4, $result->getResultCount());

    // Search with multiple conditions.
    $query = $this->index->query()->range();

    $conditionGroup1 = $query->createConditionGroup('OR');
    $conditionGroup1->addCondition('name', 'Test entity');
    $conditionGroup1->addCondition('name', 'Test entity 1');

    $conditionGroup2 = $query->createConditionGroup();
    $conditionGroup2->addCondition('name', 'Test entity 2');

    $baseConditionGroup = $query->createConditionGroup('OR');
    $baseConditionGroup
      ->addConditionGroup($conditionGroup1)
      ->addConditionGroup($conditionGroup2);

    $query = $this->index->query()->range();
    $query->addConditionGroup($baseConditionGroup);

    $result = $query->execute();
    $this->assertEquals(2, $result->getResultCount());

    // Search with an integer field condition.
    $query = $this->index->query()->range();
    $query->addCondition('weight', 100, '<');

    $result = $query->execute();
    $this->assertEquals(2, $result->getResultCount());

    // Search with an IN operator.
    $query = $this->index->query()->range();
    $query->addCondition(
      'name',
      ['Test entity 1', 'Test entity', 'Test entity 4'],
      'IN',
    );

    $result = $query->execute();
    $this->assertEquals(2, $result->getResultCount());

    // Search with a NOT IN operator.
    $query = $this->index->query()->range();
    $query->addCondition(
      'name',
      ['Test entity 1', 'Test entity 4'],
      'NOT IN',
    );

    $result = $query->execute();
    $this->assertEquals(3, $result->getResultCount());

    // Search with a BETWEEN operator.
    $query = $this->index->query()->range();
    $query->addCondition(
      'weight',
      [90, '103'],
      'BETWEEN',
    );

    $result = $query->execute();
    $this->assertEquals(3, $result->getResultCount());

    // Search with a NOT BETWEEN operator.
    $query = $this->index->query()->range();
    $query->addCondition(
      'weight',
      [90, '103'],
      'NOT BETWEEN',
    );

    $result = $query->execute();
    $this->assertEquals(2, $result->getResultCount());

    // Search with non-alphanumeric filter value.
    EntityTest::create([
      'name' => 'Test:entity',
      'body' => 'This is the body of entity',
      'weight' => 10,
    ])->save();
    $this->index->indexItems();

    $result = $this->index
      ->query()
      ->range()
      ->addCondition('name', 'test:entity')
      ->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search with an empty field condition.
    EntityTest::create([
      'name' => 'Another Test Entity',
      'body' => NULL,
      'weight' => 100,
    ])->save();
    $this->index->indexItems();

    $query = $this->index->query()->range();
    $query->addCondition('body', NULL);

    $result = $query->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search with empty field excluded.
    $query = $this->index->query()->range();
    $query->addCondition('body', NULL, '<>');

    $result = $query->execute();
    $this->assertEquals(6, $result->getResultCount());
  }

  /**
   * Tests filtering with special characters such as quotes, backslashes etc.
   */
  public function testFiltersWithSpecialCharacters(): void {
    $this->prepareTestIndex(self::TEST_INDEX);

    // Search with filter value containing single quote, double quote and
    // backslash.
    EntityTest::create([
      'name' => 'he":llo\\\'',
      'body' => 'This is the body of entity',
      'weight' => 10,
    ])->save();
    $this->index->indexItems();
    $result = $this->index
      ->query()
      ->range()
      ->addCondition('name', 'he":llo\\\'')
      ->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search with filter value wrapped in double quotes.
    EntityTest::create([
      'name' => '"test\'s entity"',
      'body' => 'This is the body of entity',
      'weight' => 10,
    ])->save();
    $this->index->indexItems();

    $result = $this->index
      ->query()
      ->range()
      ->addCondition('name', '"test\'s entity"')
      ->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search with filter value wrapped in single quotes.
    EntityTest::create([
      'name' => '\'test"s entity\'',
      'body' => 'This is the body of entity',
      'weight' => 10,
    ])->save();
    $this->index->indexItems();

    $result = $this->index
      ->query()
      ->range()
      ->addCondition('name', '\'test"s entity\'')
      ->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search with filter value wrapped in double quotes at beginning and
    // single quotes at the end.
    EntityTest::create([
      'name' => '"test:entity\'',
      'body' => 'This is the body of entity',
      'weight' => 10,
    ])->save();
    $this->index->indexItems();

    $result = $this->index
      ->query()
      ->range()
      ->addCondition('name', '"test:entity\'')
      ->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search with two backslashes in filter.
    EntityTest::create([
      'name' => '"test:entity\\\\"',
      'body' => 'This is the body of entity',
      'weight' => 10,
    ])->save();
    $this->index->indexItems();

    $result = $this->index->query()->range()
      ->addCondition('name', '"test:entity\\\\"')
      ->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search filter containing only two backslashes.
    EntityTest::create([
      'name' => '\\\\',
      'body' => 'This is the body of entity',
      'weight' => 10,
    ])->save();
    $this->index->indexItems();

    $result = $this->index->query()->range()
      ->addCondition('name', '\\\\')
      ->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search with one backslash at the end.
    EntityTest::create([
      'name' => 'test:entity\\',
      'body' => 'This is the body of entity',
      'weight' => 10,
    ])->save();
    $this->index->indexItems();

    $result = $this->index
      ->query()
      ->range()
      ->addCondition('name', 'test:entity\\')
      ->execute();
    $this->assertEquals(1, $result->getResultCount());

    // Search with three backslashes at the end.
    EntityTest::create([
      'name' => 'test:entity\\\\\\',
      'body' => 'This is the body of entity',
      'weight' => 10,
    ])->save();
    $this->index->indexItems();

    $result = $this->index
      ->query()
      ->range()
      ->addCondition('name', 'test:entity\\\\\\')
      ->execute();
    $this->assertEquals(1, $result->getResultCount());
  }

  /**
   * Tests search throws exception with non-existing field filter.
   */
  public function testFilteredSearchWithNonExistingField(): void {
    $mockLogger = $this->createMock(LoggerChannel::class);
    $mockLogger->expects($this->once())->method('error');
    $this->container->set('logger.channel.search_api_meilisearch', $mockLogger);
    $this->prepareTestIndex(self::TEST_INDEX);
    $this->populateIndex();

    $query = $this->index->query()->range();
    $query->addCondition('non_existing_field', 'test');

    $this->expectException(SearchApiException::class);
    $query->execute();
  }

  /**
   * Populates the index with entities.
   */
  protected function populateIndex(): void {
    foreach ([100, 99, 102, 80, 104] as $key => $weight) {
      EntityTest::create([
        'name' => 'Test entity ' . $key,
        'body' => 'This is the body of entity' . $key,
        'weight' => $weight,
      ])->save();
    }

    $this->index->indexItems();
  }

  /**
   * {@inheritdoc}
   */
  protected function getTestIndexes(): array {
    return [
      self::TEST_INDEX,
    ];
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc