1*ede46466SAndreas Gohr<?php 2*ede46466SAndreas Gohr 3*ede46466SAndreas Gohrnamespace dokuwiki\test\Search\Collection; 4*ede46466SAndreas Gohr 5*ede46466SAndreas Gohruse dokuwiki\Search\Collection\PageMetaCollection; 6*ede46466SAndreas Gohruse dokuwiki\Search\Exception\IndexLockException; 7*ede46466SAndreas Gohruse dokuwiki\Search\Index\MemoryIndex; 8*ede46466SAndreas Gohr 9*ede46466SAndreas Gohrclass LookupCollectionTest extends \DokuWikiTest 10*ede46466SAndreas Gohr{ 11*ede46466SAndreas Gohr /** 12*ede46466SAndreas Gohr * Add data and directly check the underlying indexes for correctness 13*ede46466SAndreas Gohr */ 14*ede46466SAndreas Gohr public function testAddEntity() 15*ede46466SAndreas Gohr { 16*ede46466SAndreas Gohr $index = new MockLookupCollection('a_entity', 'a_token', 'a_freq', 'a_reverse'); 17*ede46466SAndreas Gohr $index->lock(); 18*ede46466SAndreas Gohr $index->addEntity('wiki:start', ['wiki:logo.png', 'wiki:banner.jpg', 'wiki:icon.svg']); 19*ede46466SAndreas Gohr $index->unlock(); 20*ede46466SAndreas Gohr 21*ede46466SAndreas Gohr // check entity index 22*ede46466SAndreas Gohr $idxEntity = new MemoryIndex('a_entity'); 23*ede46466SAndreas Gohr $this->assertEquals('wiki:start', $idxEntity->retrieveRow(0)); 24*ede46466SAndreas Gohr 25*ede46466SAndreas Gohr // check token index (single file, no suffix) 26*ede46466SAndreas Gohr $idxToken = new MemoryIndex('a_token'); 27*ede46466SAndreas Gohr $this->assertEquals('wiki:logo.png', $idxToken->retrieveRow(0)); 28*ede46466SAndreas Gohr $this->assertEquals('wiki:banner.jpg', $idxToken->retrieveRow(1)); 29*ede46466SAndreas Gohr $this->assertEquals('wiki:icon.svg', $idxToken->retrieveRow(2)); 30*ede46466SAndreas Gohr 31*ede46466SAndreas Gohr // check frequency index — all frequencies are 1 (written without *1) 32*ede46466SAndreas Gohr $idxFreq = new MemoryIndex('a_freq'); 33*ede46466SAndreas Gohr $this->assertEquals('0', $idxFreq->retrieveRow(0)); // entity 0 with implicit freq 1 34*ede46466SAndreas Gohr $this->assertEquals('0', $idxFreq->retrieveRow(1)); 35*ede46466SAndreas Gohr $this->assertEquals('0', $idxFreq->retrieveRow(2)); 36*ede46466SAndreas Gohr 37*ede46466SAndreas Gohr // check reverse index 38*ede46466SAndreas Gohr $idxRev = new MemoryIndex('a_reverse'); 39*ede46466SAndreas Gohr $this->assertEquals('0:1:2', $idxRev->retrieveRow(0)); 40*ede46466SAndreas Gohr } 41*ede46466SAndreas Gohr 42*ede46466SAndreas Gohr /** 43*ede46466SAndreas Gohr * Duplicate tokens should be deduplicated 44*ede46466SAndreas Gohr */ 45*ede46466SAndreas Gohr public function testAddEntityDedup() 46*ede46466SAndreas Gohr { 47*ede46466SAndreas Gohr $index = new MockLookupCollection('b_entity', 'b_token', 'b_freq', 'b_reverse'); 48*ede46466SAndreas Gohr $index->lock(); 49*ede46466SAndreas Gohr $index->addEntity('wiki:start', ['wiki:logo.png', 'wiki:logo.png', 'wiki:banner.jpg']); 50*ede46466SAndreas Gohr $index->unlock(); 51*ede46466SAndreas Gohr 52*ede46466SAndreas Gohr $idxToken = new MemoryIndex('b_token'); 53*ede46466SAndreas Gohr $this->assertEquals('wiki:logo.png', $idxToken->retrieveRow(0)); 54*ede46466SAndreas Gohr $this->assertEquals('wiki:banner.jpg', $idxToken->retrieveRow(1)); 55*ede46466SAndreas Gohr 56*ede46466SAndreas Gohr $idxRev = new MemoryIndex('b_reverse'); 57*ede46466SAndreas Gohr $this->assertEquals('0:1', $idxRev->retrieveRow(0)); 58*ede46466SAndreas Gohr } 59*ede46466SAndreas Gohr 60*ede46466SAndreas Gohr /** 61*ede46466SAndreas Gohr * Updating an entity should remove old tokens and add new ones 62*ede46466SAndreas Gohr */ 63*ede46466SAndreas Gohr public function testUpdateEntity() 64*ede46466SAndreas Gohr { 65*ede46466SAndreas Gohr $index = new MockLookupCollection('c_entity', 'c_token', 'c_freq', 'c_reverse'); 66*ede46466SAndreas Gohr 67*ede46466SAndreas Gohr // initial add 68*ede46466SAndreas Gohr $index->lock(); 69*ede46466SAndreas Gohr $index->addEntity('wiki:start', ['wiki:logo.png', 'wiki:banner.jpg']); 70*ede46466SAndreas Gohr $index->unlock(); 71*ede46466SAndreas Gohr 72*ede46466SAndreas Gohr // update: remove logo, keep banner, add icon 73*ede46466SAndreas Gohr $index->lock(); 74*ede46466SAndreas Gohr $index->addEntity('wiki:start', ['wiki:banner.jpg', 'wiki:icon.svg']); 75*ede46466SAndreas Gohr $index->unlock(); 76*ede46466SAndreas Gohr 77*ede46466SAndreas Gohr // logo should be removed from frequency index 78*ede46466SAndreas Gohr $idxFreq = new MemoryIndex('c_freq'); 79*ede46466SAndreas Gohr $this->assertEquals('', $idxFreq->retrieveRow(0)); // logo removed 80*ede46466SAndreas Gohr $this->assertEquals('0', $idxFreq->retrieveRow(1)); // banner still on entity 0 81*ede46466SAndreas Gohr $this->assertEquals('0', $idxFreq->retrieveRow(2)); // icon added on entity 0 82*ede46466SAndreas Gohr 83*ede46466SAndreas Gohr // reverse index should only have banner and icon 84*ede46466SAndreas Gohr $idxRev = new MemoryIndex('c_reverse'); 85*ede46466SAndreas Gohr $this->assertEquals('1:2', $idxRev->retrieveRow(0)); 86*ede46466SAndreas Gohr } 87*ede46466SAndreas Gohr 88*ede46466SAndreas Gohr /** 89*ede46466SAndreas Gohr * Test reverse assignments returns two-level structure with empty group key 90*ede46466SAndreas Gohr */ 91*ede46466SAndreas Gohr public function testReverseAssignments() 92*ede46466SAndreas Gohr { 93*ede46466SAndreas Gohr $index = new MockLookupCollection('d_entity', 'd_token', 'd_freq', 'd_reverse'); 94*ede46466SAndreas Gohr $index->lock(); 95*ede46466SAndreas Gohr $index->addEntity('wiki:start', ['wiki:logo.png', 'wiki:banner.jpg']); 96*ede46466SAndreas Gohr $index->unlock(); 97*ede46466SAndreas Gohr 98*ede46466SAndreas Gohr $result = $index->getReverseAssignments('wiki:start'); 99*ede46466SAndreas Gohr $this->assertEquals(['' => [0 => 0, 1 => 0]], $result); 100*ede46466SAndreas Gohr } 101*ede46466SAndreas Gohr 102*ede46466SAndreas Gohr /** 103*ede46466SAndreas Gohr * Adding entity without lock should throw exception 104*ede46466SAndreas Gohr */ 105*ede46466SAndreas Gohr public function testAddEntityWithoutLock() 106*ede46466SAndreas Gohr { 107*ede46466SAndreas Gohr $this->expectException(IndexLockException::class); 108*ede46466SAndreas Gohr 109*ede46466SAndreas Gohr $index = new MockLookupCollection(); 110*ede46466SAndreas Gohr $index->addEntity('wiki:start', ['wiki:logo.png']); 111*ede46466SAndreas Gohr } 112*ede46466SAndreas Gohr 113*ede46466SAndreas Gohr /** 114*ede46466SAndreas Gohr * Adding empty token list should clear entity from indexes 115*ede46466SAndreas Gohr */ 116*ede46466SAndreas Gohr public function testEmptyTokens() 117*ede46466SAndreas Gohr { 118*ede46466SAndreas Gohr $index = new MockLookupCollection('f_entity', 'f_token', 'f_freq', 'f_reverse'); 119*ede46466SAndreas Gohr 120*ede46466SAndreas Gohr // add some tokens first 121*ede46466SAndreas Gohr $index->lock(); 122*ede46466SAndreas Gohr $index->addEntity('wiki:start', ['wiki:logo.png']); 123*ede46466SAndreas Gohr $index->unlock(); 124*ede46466SAndreas Gohr 125*ede46466SAndreas Gohr // now clear 126*ede46466SAndreas Gohr $index->lock(); 127*ede46466SAndreas Gohr $index->addEntity('wiki:start', []); 128*ede46466SAndreas Gohr $index->unlock(); 129*ede46466SAndreas Gohr 130*ede46466SAndreas Gohr // frequency index should be empty for this token 131*ede46466SAndreas Gohr $idxFreq = new MemoryIndex('f_freq'); 132*ede46466SAndreas Gohr $this->assertEquals('', $idxFreq->retrieveRow(0)); 133*ede46466SAndreas Gohr 134*ede46466SAndreas Gohr // reverse index should be empty 135*ede46466SAndreas Gohr $idxRev = new MemoryIndex('f_reverse'); 136*ede46466SAndreas Gohr $this->assertEquals('', $idxRev->retrieveRow(0)); 137*ede46466SAndreas Gohr } 138*ede46466SAndreas Gohr 139*ede46466SAndreas Gohr /** 140*ede46466SAndreas Gohr * Test that PageMetaCollection('relation_media') uses correct index names 141*ede46466SAndreas Gohr */ 142*ede46466SAndreas Gohr public function testMediaCollection() 143*ede46466SAndreas Gohr { 144*ede46466SAndreas Gohr $index = new PageMetaCollection('relation_media'); 145*ede46466SAndreas Gohr $index->lock(); 146*ede46466SAndreas Gohr $index->addEntity('wiki:start', ['wiki:logo.png', 'wiki:banner.jpg']); 147*ede46466SAndreas Gohr $index->unlock(); 148*ede46466SAndreas Gohr 149*ede46466SAndreas Gohr $idxToken = new MemoryIndex('relation_media_w'); 150*ede46466SAndreas Gohr $this->assertEquals('wiki:logo.png', $idxToken->retrieveRow(0)); 151*ede46466SAndreas Gohr $this->assertEquals('wiki:banner.jpg', $idxToken->retrieveRow(1)); 152*ede46466SAndreas Gohr 153*ede46466SAndreas Gohr $idxRev = new MemoryIndex('relation_media_p'); 154*ede46466SAndreas Gohr $this->assertEquals('0:1', $idxRev->retrieveRow(0)); 155*ede46466SAndreas Gohr } 156*ede46466SAndreas Gohr 157*ede46466SAndreas Gohr /** 158*ede46466SAndreas Gohr * Test that PageMetaCollection('relation_references') uses correct index names 159*ede46466SAndreas Gohr */ 160*ede46466SAndreas Gohr public function testReferencesCollection() 161*ede46466SAndreas Gohr { 162*ede46466SAndreas Gohr $index = new PageMetaCollection('relation_references'); 163*ede46466SAndreas Gohr $index->lock(); 164*ede46466SAndreas Gohr $index->addEntity('wiki:start', ['wiki:syntax', 'wiki:welcome']); 165*ede46466SAndreas Gohr $index->unlock(); 166*ede46466SAndreas Gohr 167*ede46466SAndreas Gohr $idxToken = new MemoryIndex('relation_references_w'); 168*ede46466SAndreas Gohr $this->assertEquals('wiki:syntax', $idxToken->retrieveRow(0)); 169*ede46466SAndreas Gohr $this->assertEquals('wiki:welcome', $idxToken->retrieveRow(1)); 170*ede46466SAndreas Gohr 171*ede46466SAndreas Gohr $idxRev = new MemoryIndex('relation_references_p'); 172*ede46466SAndreas Gohr $this->assertEquals('0:1', $idxRev->retrieveRow(0)); 173*ede46466SAndreas Gohr 174*ede46466SAndreas Gohr $result = $index->getReverseAssignments('wiki:start'); 175*ede46466SAndreas Gohr $this->assertEquals(['' => [0 => 0, 1 => 0]], $result); 176*ede46466SAndreas Gohr } 177*ede46466SAndreas Gohr 178*ede46466SAndreas Gohr /** 179*ede46466SAndreas Gohr * resolveTokens should deduplicate and assign frequency 1 under empty group key 180*ede46466SAndreas Gohr */ 181*ede46466SAndreas Gohr public function testResolveTokens() 182*ede46466SAndreas Gohr { 183*ede46466SAndreas Gohr $index = new MockLookupCollection('rt_entity', 'rt_token', 'rt_freq', 'rt_reverse'); 184*ede46466SAndreas Gohr $index->lock(); 185*ede46466SAndreas Gohr 186*ede46466SAndreas Gohr $result = $this->callInaccessibleMethod($index, 'resolveTokens', [ 187*ede46466SAndreas Gohr ['wiki:logo.png', 'wiki:banner.jpg', 'wiki:logo.png'], 188*ede46466SAndreas Gohr ]); 189*ede46466SAndreas Gohr 190*ede46466SAndreas Gohr // all tokens under empty group key 191*ede46466SAndreas Gohr $this->assertArrayHasKey('', $result); 192*ede46466SAndreas Gohr $this->assertCount(2, $result['']); // deduplicated 193*ede46466SAndreas Gohr 194*ede46466SAndreas Gohr // token IDs are sequential: logo=0, banner=1 195*ede46466SAndreas Gohr $this->assertEquals(1, $result[''][0]); // logo freq=1 196*ede46466SAndreas Gohr $this->assertEquals(1, $result[''][1]); // banner freq=1 197*ede46466SAndreas Gohr } 198*ede46466SAndreas Gohr 199*ede46466SAndreas Gohr /** 200*ede46466SAndreas Gohr * resolveTokens with empty input should return empty array 201*ede46466SAndreas Gohr */ 202*ede46466SAndreas Gohr public function testResolveTokensEmpty() 203*ede46466SAndreas Gohr { 204*ede46466SAndreas Gohr $index = new MockLookupCollection('rte_entity', 'rte_token', 'rte_freq', 'rte_reverse'); 205*ede46466SAndreas Gohr $index->lock(); 206*ede46466SAndreas Gohr 207*ede46466SAndreas Gohr $result = $this->callInaccessibleMethod($index, 'resolveTokens', [[]]); 208*ede46466SAndreas Gohr 209*ede46466SAndreas Gohr $this->assertEmpty($result); 210*ede46466SAndreas Gohr } 211*ede46466SAndreas Gohr 212*ede46466SAndreas Gohr /** 213*ede46466SAndreas Gohr * countTokens should deduplicate and assign frequency 1 214*ede46466SAndreas Gohr */ 215*ede46466SAndreas Gohr public function testCountTokens() 216*ede46466SAndreas Gohr { 217*ede46466SAndreas Gohr $index = new MockLookupCollection(); 218*ede46466SAndreas Gohr 219*ede46466SAndreas Gohr $result = $this->callInaccessibleMethod($index, 'countTokens', [ 220*ede46466SAndreas Gohr ['wiki:logo.png', 'wiki:banner.jpg', 'wiki:logo.png'], 221*ede46466SAndreas Gohr ]); 222*ede46466SAndreas Gohr 223*ede46466SAndreas Gohr $this->assertEquals([ 224*ede46466SAndreas Gohr 'wiki:logo.png' => 1, 225*ede46466SAndreas Gohr 'wiki:banner.jpg' => 1, 226*ede46466SAndreas Gohr ], $result); 227*ede46466SAndreas Gohr } 228*ede46466SAndreas Gohr} 229