<?php 
 
declare(strict_types=1); 
 
use Fuse\Fuse; 
 
beforeEach(function () { 
    $books = require __DIR__ . '/fixtures/books.php'; 
    $this->books = $books; 
    $this->fuseOptions = [ 
        'useExtendedSearch' => true, 
        'includeMatches' => true, 
        'includeScore' => true, 
        'threshold' => 0.3, 
        'keys' => ['title', 'author.firstName', 'author.lastName'], 
    ]; 
 
    $this->idx = function (array $results): array { 
        return array_map(fn(array $result) => $result['refIndex'], $results); 
    }; 
 
    $this->idxMap = function (Fuse $fuse): array { 
        return array_map(fn(array $item) => [$item['v'], $item['i']], $fuse->getIndex()->records); 
    }; 
}); 
 
it('creates index and ensures properties exist', function () { 
    $myIndex = Fuse::createIndex($this->fuseOptions['keys'], $this->books); 
 
    expect($myIndex->records)->not->toBeNull(); 
    expect($myIndex->keys)->not->toBeNull(); 
}); 
 
it('creates index and ensures keys can be created with objects', function () { 
    $myIndex = Fuse::createIndex( 
        [['name' => 'title'], ['name' => 'author.firstName']], 
        $this->books, 
    ); 
 
    expect($myIndex->records)->not->toBeNull(); 
    expect($myIndex->keys)->not->toBeNull(); 
}); 
 
it('creates index and ensures keys can be created with getFn', function () { 
    $myIndex = Fuse::createIndex( 
        [ 
            ['name' => 'title', 'getFn' => fn($book) => $book['title']], 
            ['name' => 'author.firstName', 'getFn' => fn($book) => $book['author']['firstName']], 
        ], 
        $this->books, 
    ); 
 
    $data = json_decode(json_encode($myIndex), true); 
    expect($data['records'])->not->toBeNull(); 
    expect($data['keys'])->not->toBeNull(); 
}); 
 
it('parses index, exports it, and initializes Fuse', function () { 
    $myIndex = Fuse::createIndex($this->fuseOptions['keys'], $this->books); 
 
    expect($myIndex->size())->toBe(count($this->books)); 
 
    $data = json_decode(json_encode($myIndex), true); 
    expect($data['records'])->not->toBeNull(); 
    expect($data['keys'])->not->toBeNull(); 
 
    $parsedIndex = Fuse::parseIndex($data); 
    expect($parsedIndex->size())->toBe(count($this->books)); 
}); 
 
it('searches parsed index using getFn', function () { 
    $fuse = new Fuse($this->books, [ 
        'useExtendedSearch' => true, 
        'includeMatches' => true, 
        'includeScore' => true, 
        'threshold' => 0.3, 
        'keys' => [ 
            ['name' => 'bookTitle', 'getFn' => fn($book) => $book['title']], 
            ['name' => 'authorName', 'getFn' => fn($book) => $book['author']['firstName']], 
        ], 
    ]); 
 
    $result = $fuse->search(['bookTitle' => 'old man']); 
 
    expect($result)->toHaveCount(1); 
    expect(($this->idx)($result))->toContain(0); 
}); 
 
it('instantiates Fuse with an index', function () { 
    $myIndex = Fuse::createIndex($this->fuseOptions['keys'], $this->books); 
    $fuse = new Fuse($this->books, $this->fuseOptions, $myIndex); 
 
    $result = $fuse->search(['title' => 'old man']); 
 
    expect($result)->toHaveCount(1); 
    expect(($this->idx)($result))->toContain(0); 
    expect($result[0]['matches'][0]['indices'])->toContain([0, 2], [4, 6]); 
}); 
 
it('adds an object to the index', function () { 
    $fuse = new Fuse($this->books, $this->fuseOptions); 
 
    $fuse->add(['title' => 'book', 'author' => ['firstName' => 'Kiro', 'lastName' => 'Risk']]); 
 
    $result = $fuse->search('kiro'); 
 
    expect($result)->toHaveCount(1); 
    expect(($this->idx)($result))->toContain(count($this->books)); 
}); 
 
it('adds a string to the index', function () { 
    $fuse = new Fuse(['apple', 'orange'], ['includeScore' => true]); 
 
    $fuse->add('banana'); 
    $result = $fuse->search('banana'); 
 
    expect($result)->toHaveCount(1); 
    expect(($this->idx)($result))->toContain(2); 
}); 
 
it('removes a string from the index', function () { 
    $fuse = new Fuse(['apple', 'orange', 'banana', 'pear']); 
 
    expect($fuse->getIndex()->size())->toBe(4); 
    expect(($this->idxMap)($fuse))->toContain( 
        ['apple', 0], 
        ['orange', 1], 
        ['banana', 2], 
        ['pear', 3], 
    ); 
 
    $fuse->removeAt(1); 
 
    expect($fuse->getIndex()->size())->toBe(3); 
    expect(($this->idxMap)($fuse))->toContain(['apple', 0], ['banana', 1], ['pear', 2]); 
 
    $results = $fuse->remove(fn($doc) => $doc === 'banana' || $doc === 'pear'); 
 
    expect($results)->toHaveCount(2); 
    expect($fuse->getIndex()->size())->toBe(1); 
 
    $fuseReflection = new ReflectionObject($fuse); 
    $docsProperty = $fuseReflection->getProperty('docs'); 
    $docsProperty->setAccessible(true); 
 
    expect($docsProperty->getValue($fuse))->toHaveCount(1); 
}); 
 
 |