xref: /dokuwiki/_test/tests/Search/Collection/DirectCollectionTest.php (revision 9369b4a991666bc911474806b106d8958e79f4c1)
1<?php
2
3namespace dokuwiki\test\Search\Collection;
4
5use dokuwiki\Search\Collection\PageTitleCollection;
6use dokuwiki\Search\Exception\IndexIntegrityException;
7use dokuwiki\Search\Exception\IndexLockException;
8use dokuwiki\Search\Index\MemoryIndex;
9
10class DirectCollectionTest extends \DokuWikiTest
11{
12    /**
13     * Add a token and verify it's stored at the entity's position
14     */
15    public function testAddEntity()
16    {
17        $index = new MockDirectCollection('a_entity', 'a_token');
18        $index->lock();
19        $index->addEntity('wiki:start', ['Welcome to DokuWiki']);
20        $index->unlock();
21
22        $idxEntity = new MemoryIndex('a_entity');
23        $this->assertEquals('wiki:start', $idxEntity->retrieveRow(0));
24
25        $idxToken = new MemoryIndex('a_token');
26        $this->assertEquals('Welcome to DokuWiki', $idxToken->retrieveRow(0));
27    }
28
29    /**
30     * Updating an entity should overwrite the previous token
31     */
32    public function testUpdateEntity()
33    {
34        $index = new MockDirectCollection('b_entity', 'b_token');
35
36        $index->lock();
37        $index->addEntity('wiki:start', ['Old Title']);
38        $index->unlock();
39
40        $index->lock();
41        $index->addEntity('wiki:start', ['New Title']);
42        $index->unlock();
43
44        $idxToken = new MemoryIndex('b_token');
45        $this->assertEquals('New Title', $idxToken->retrieveRow(0));
46    }
47
48    /**
49     * Empty token list should store empty string
50     */
51    public function testEmptyToken()
52    {
53        $index = new MockDirectCollection('c_entity', 'c_token');
54        $index->lock();
55        $index->addEntity('wiki:start', []);
56        $index->unlock();
57
58        $idxToken = new MemoryIndex('c_token');
59        $this->assertEquals('', $idxToken->retrieveRow(0));
60    }
61
62    /**
63     * getToken should return the stored value
64     */
65    public function testGetToken()
66    {
67        $index = new MockDirectCollection('d_entity', 'd_token');
68        $index->lock();
69        $index->addEntity('wiki:start', ['My Page Title']);
70        $index->unlock();
71
72        $this->assertEquals('My Page Title', $index->getToken('wiki:start'));
73    }
74
75    /**
76     * Adding entity without lock should throw exception
77     */
78    public function testAddEntityWithoutLock()
79    {
80        $this->expectException(IndexLockException::class);
81
82        $index = new MockDirectCollection();
83        $index->addEntity('wiki:start', ['Title']);
84    }
85
86    /**
87     * Test that PageTitleCollection uses correct index names
88     */
89    public function testPageTitleCollection()
90    {
91        $index = new PageTitleCollection();
92        $index->lock();
93        $index->addEntity('wiki:start', ['Welcome']);
94        $index->unlock();
95
96        $idxToken = new MemoryIndex('title');
97        $this->assertEquals('Welcome', $idxToken->retrieveRow(0));
98
99        $this->assertEquals('Welcome', $index->getToken('wiki:start'));
100    }
101
102    /**
103     * resolveTokenFrequencies maps token RID = entity RID with frequency 1
104     */
105    public function testResolveTokenFrequencies()
106    {
107        $index = new MockDirectCollection('rtf_entity', 'rtf_token');
108        $index->lock();
109        $index->addEntity('wiki:start', ['Title One']);
110        $index->addEntity('wiki:syntax', ['Title Two']);
111        $index->unlock();
112
113        $result = $index->resolveTokenFrequencies(0, [0, 1]);
114        $this->assertEquals([
115            0 => [0 => 1],
116            1 => [1 => 1],
117        ], $result);
118    }
119
120    /**
121     * getEntitiesWithData returns entities that have non-empty tokens
122     */
123    public function testGetEntitiesWithData()
124    {
125        $index = new MockDirectCollection('ewd_entity', 'ewd_token');
126        $index->lock();
127        $index->addEntity('wiki:start', ['Title One']);
128        $index->addEntity('wiki:empty', []);
129        $index->addEntity('wiki:syntax', ['Title Two']);
130        $index->unlock();
131
132        $result = $index->getEntitiesWithData();
133        sort($result);
134        $this->assertEquals(['wiki:start', 'wiki:syntax'], $result);
135    }
136
137    /**
138     * checkIntegrity passes on a healthy DirectCollection
139     */
140    public function testCheckIntegrityHealthy()
141    {
142        $index = new MockDirectCollection('cih_entity', 'cih_token');
143        $index->lock();
144        $index->addEntity('wiki:start', ['Title One']);
145        $index->unlock();
146
147        $index->checkIntegrity(); // should not throw
148        $this->assertTrue(true);
149    }
150
151    /**
152     * checkIntegrity passes on an empty DirectCollection
153     */
154    public function testCheckIntegrityEmpty()
155    {
156        $index = new MockDirectCollection('cie_entity', 'cie_token');
157        $index->checkIntegrity(); // should not throw
158        $this->assertTrue(true);
159    }
160
161    /**
162     * checkIntegrity detects entity/token line count mismatch
163     */
164    public function testCheckIntegrityMismatch()
165    {
166        global $conf;
167        $index = new MockDirectCollection('cim_entity', 'cim_token');
168        $index->lock();
169        $index->addEntity('wiki:start', ['Title One']);
170        $index->unlock();
171
172        // corrupt: add extra line to token index
173        file_put_contents($conf['indexdir'] . '/cim_token.idx', "extra\n", FILE_APPEND);
174
175        $this->expectException(IndexIntegrityException::class);
176        (new MockDirectCollection('cim_entity', 'cim_token'))->checkIntegrity();
177    }
178}
179