Remove some useless comments
[phpmyadmin.git] / test / classes / Navigation / Nodes / NodeTest.php
blobab4cb89874cf01c17caaab9acce3ab934664a48c
1 <?php
3 declare(strict_types=1);
5 namespace PhpMyAdmin\Tests\Navigation\Nodes;
7 use PhpMyAdmin\DatabaseInterface;
8 use PhpMyAdmin\Navigation\NodeFactory;
9 use PhpMyAdmin\Navigation\Nodes\Node;
10 use PhpMyAdmin\Tests\AbstractTestCase;
11 use ReflectionMethod;
13 class NodeTest extends AbstractTestCase
15 /**
16 * SetUp for test cases
18 protected function setUp(): void
20 parent::setUp();
21 parent::loadDefaultConfig();
22 $GLOBALS['server'] = 0;
23 $GLOBALS['cfg']['Server']['DisableIS'] = false;
26 /**
27 * SetUp for AddNode
29 public function testAddNode(): void
31 $parent = NodeFactory::getInstance('Node', 'parent');
32 $child = NodeFactory::getInstance('Node', 'child');
33 $parent->addChild($child);
34 $this->assertEquals(
35 $parent->getChild($child->name),
36 $child
38 $this->assertEquals(
39 $parent->getChild($child->realName, true),
40 $child
44 /**
45 * SetUp for getChild
47 public function testGetChildError(): void
49 $parent = NodeFactory::getInstance('Node', 'parent');
50 $this->assertNull(
51 $parent->getChild('foo')
53 $this->assertNull(
54 $parent->getChild('foo', true)
58 /**
59 * SetUp for getChild
61 public function testRemoveNode(): void
63 $parent = NodeFactory::getInstance('Node', 'parent');
64 $child = NodeFactory::getInstance('Node', 'child');
65 $parent->addChild($child);
66 $this->assertEquals(
67 $parent->getChild($child->name),
68 $child
70 $parent->removeChild($child->name);
71 $this->assertNull(
72 $parent->getChild($child->name)
76 /**
77 * SetUp for hasChildren
79 public function testNodeHasChildren(): void
81 $parent = NodeFactory::getInstance();
82 $emptyContainer = NodeFactory::getInstance(
83 'Node',
84 'empty',
85 Node::CONTAINER
87 $child = NodeFactory::getInstance();
88 // test with no children
89 $this->assertEquals(
90 $parent->hasChildren(true),
91 false
93 $this->assertEquals(
94 $parent->hasChildren(false),
95 false
97 // test with an empty container
98 $parent->addChild($emptyContainer);
99 $this->assertEquals(
100 $parent->hasChildren(true),
101 true
103 $this->assertEquals(
104 $parent->hasChildren(false),
105 false
107 // test with a real child
108 $parent->addChild($child);
109 $this->assertEquals(
110 $parent->hasChildren(true),
111 true
113 $this->assertEquals(
114 $parent->hasChildren(false),
115 true
120 * SetUp for numChildren
122 public function testNumChildren(): void
124 // start with root node only
125 $parent = NodeFactory::getInstance();
126 $this->assertEquals($parent->numChildren(), 0);
127 // add a child
128 $child = NodeFactory::getInstance();
129 $parent->addChild($child);
130 $this->assertEquals($parent->numChildren(), 1);
131 // add a direct grandchild, this one doesn't count as
132 // it's not enclosed in a CONTAINER
133 $child->addChild(NodeFactory::getInstance());
134 $this->assertEquals($parent->numChildren(), 1);
135 // add a container, this one doesn't count wither
136 $container = NodeFactory::getInstance(
137 'Node',
138 'default',
139 Node::CONTAINER
141 $parent->addChild($container);
142 $this->assertEquals($parent->numChildren(), 1);
143 // add a grandchild to container, this one counts
144 $container->addChild(NodeFactory::getInstance());
145 $this->assertEquals($parent->numChildren(), 2);
146 // add another grandchild to container, this one counts
147 $container->addChild(NodeFactory::getInstance());
148 $this->assertEquals($parent->numChildren(), 3);
152 * SetUp for parents
154 public function testParents(): void
156 $parent = NodeFactory::getInstance();
157 $this->assertEquals($parent->parents(), []); // exclude self
158 $this->assertEquals($parent->parents(true), [$parent]); // include self
160 $child = NodeFactory::getInstance();
161 $parent->addChild($child);
163 $this->assertEquals($child->parents(), [$parent]); // exclude self
164 $this->assertEquals(
165 $child->parents(true),
167 $child,
168 $parent,
170 ); // include self
174 * SetUp for realParent
176 public function testRealParent(): void
178 $parent = NodeFactory::getInstance();
179 $this->assertFalse($parent->realParent());
181 $child = NodeFactory::getInstance();
182 $parent->addChild($child);
183 $this->assertEquals($child->realParent(), $parent);
187 * Tests whether Node->hasSiblings() method returns false
188 * when the node does not have any siblings.
190 * @test
192 public function testHasSiblingsWithNoSiblings(): void
194 $parent = NodeFactory::getInstance();
195 $child = NodeFactory::getInstance();
196 $parent->addChild($child);
197 $this->assertFalse($child->hasSiblings());
201 * Tests whether Node->hasSiblings() method returns true
202 * when it actually has siblings.
204 * @test
206 public function testHasSiblingsWithSiblings(): void
208 $parent = NodeFactory::getInstance();
209 $firstChild = NodeFactory::getInstance();
210 $parent->addChild($firstChild);
211 $secondChild = NodeFactory::getInstance();
212 $parent->addChild($secondChild);
213 // Normal case; two Node:NODE type siblings
214 $this->assertTrue($firstChild->hasSiblings());
216 $parent = NodeFactory::getInstance();
217 $firstChild = NodeFactory::getInstance();
218 $parent->addChild($firstChild);
219 $secondChild = NodeFactory::getInstance(
220 'Node',
221 'default',
222 Node::CONTAINER
224 $parent->addChild($secondChild);
225 // Empty Node::CONTAINER type node should not be considered in hasSiblings()
226 $this->assertFalse($firstChild->hasSiblings());
228 $grandChild = NodeFactory::getInstance();
229 $secondChild->addChild($grandChild);
230 // Node::CONTAINER type nodes with children are counted for hasSiblings()
231 $this->assertTrue($firstChild->hasSiblings());
235 * It is expected that Node->hasSiblings() method always return true
236 * for Nodes that are 3 levels deep (columns and indexes).
238 * @test
240 public function testHasSiblingsForNodesAtLevelThree(): void
242 $parent = NodeFactory::getInstance();
243 $child = NodeFactory::getInstance();
244 $parent->addChild($child);
245 $grandChild = NodeFactory::getInstance();
246 $child->addChild($grandChild);
247 $greatGrandChild = NodeFactory::getInstance();
248 $grandChild->addChild($greatGrandChild);
250 // Should return false for node that are two levels deeps
251 $this->assertFalse($grandChild->hasSiblings());
252 // Should return true for node that are three levels deeps
253 $this->assertTrue($greatGrandChild->hasSiblings());
257 * Tests private method _getWhereClause()
259 * @test
261 public function testGetWhereClause(): void
263 $method = new ReflectionMethod(
264 Node::class,
265 'getWhereClause'
267 $method->setAccessible(true);
269 // Vanilla case
270 $node = NodeFactory::getInstance();
271 $this->assertEquals(
272 'WHERE TRUE ',
273 $method->invoke($node, 'SCHEMA_NAME')
276 // When a schema names is passed as search clause
277 $this->assertEquals(
278 "WHERE TRUE AND `SCHEMA_NAME` LIKE '%schemaName%' ",
279 $method->invoke($node, 'SCHEMA_NAME', 'schemaName')
282 if (! isset($GLOBALS['cfg']['Server'])) {
283 $GLOBALS['cfg']['Server'] = [];
286 // When hide_db regular expression is present
287 $GLOBALS['cfg']['Server']['hide_db'] = 'regexpHideDb';
288 $this->assertEquals(
289 "WHERE TRUE AND `SCHEMA_NAME` NOT REGEXP 'regexpHideDb' ",
290 $method->invoke($node, 'SCHEMA_NAME')
292 unset($GLOBALS['cfg']['Server']['hide_db']);
294 // When only_db directive is present and it's a single db
295 $GLOBALS['cfg']['Server']['only_db'] = 'stringOnlyDb';
296 $this->assertEquals(
297 "WHERE TRUE AND ( `SCHEMA_NAME` LIKE 'stringOnlyDb' ) ",
298 $method->invoke($node, 'SCHEMA_NAME')
300 unset($GLOBALS['cfg']['Server']['only_db']);
302 // When only_db directive is present and it's an array of dbs
303 $GLOBALS['cfg']['Server']['only_db'] = [
304 'onlyDbOne',
305 'onlyDbTwo',
307 $this->assertEquals(
308 "WHERE TRUE AND ( `SCHEMA_NAME` LIKE 'onlyDbOne' "
309 . "OR `SCHEMA_NAME` LIKE 'onlyDbTwo' ) ",
310 $method->invoke($node, 'SCHEMA_NAME')
312 unset($GLOBALS['cfg']['Server']['only_db']);
316 * Tests getData() method when DisableIS is false and navigation tree
317 * grouping enabled.
319 * @test
321 public function testGetDataWithEnabledISAndGroupingEnabled(): void
323 $pos = 10;
324 $limit = 20;
325 $GLOBALS['cfg']['Server']['DisableIS'] = false;
326 $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true;
327 $GLOBALS['cfg']['FirstLevelNavigationItems'] = $limit;
328 $GLOBALS['cfg']['NavigationTreeDbSeparator'] = '_';
330 $expectedSql = 'SELECT `SCHEMA_NAME` ';
331 $expectedSql .= 'FROM `INFORMATION_SCHEMA`.`SCHEMATA`, ';
332 $expectedSql .= '(';
333 $expectedSql .= 'SELECT DB_first_level ';
334 $expectedSql .= 'FROM ( ';
335 $expectedSql .= 'SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, ';
336 $expectedSql .= "'_', 1) ";
337 $expectedSql .= 'DB_first_level ';
338 $expectedSql .= 'FROM INFORMATION_SCHEMA.SCHEMATA ';
339 $expectedSql .= 'WHERE TRUE ';
340 $expectedSql .= ') t ';
341 $expectedSql .= 'ORDER BY DB_first_level ASC ';
342 $expectedSql .= 'LIMIT ' . $pos . ', ' . $limit;
343 $expectedSql .= ') t2 ';
344 $expectedSql .= "WHERE TRUE AND 1 = LOCATE(CONCAT(DB_first_level, '_'), ";
345 $expectedSql .= "CONCAT(SCHEMA_NAME, '_')) ";
346 $expectedSql .= 'ORDER BY SCHEMA_NAME ASC';
348 // It would have been better to mock _getWhereClause method
349 // but strangely, mocking private methods is not supported in PHPUnit
350 $node = NodeFactory::getInstance();
352 $dbi = $this->getMockBuilder(DatabaseInterface::class)
353 ->disableOriginalConstructor()
354 ->getMock();
355 $dbi->expects($this->once())
356 ->method('fetchResult')
357 ->with($expectedSql);
358 $dbi->expects($this->any())->method('escapeString')
359 ->will($this->returnArgument(0));
360 $GLOBALS['dbi'] = $dbi;
361 $node->getData('', $pos);
365 * Tests getData() method when DisableIS is false and navigation tree
366 * grouping disabled.
368 * @test
370 public function testGetDataWithEnabledISAndGroupingDisabled(): void
372 $pos = 10;
373 $limit = 20;
374 $GLOBALS['cfg']['Server']['DisableIS'] = false;
375 $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = false;
376 $GLOBALS['cfg']['FirstLevelNavigationItems'] = $limit;
378 $expectedSql = 'SELECT `SCHEMA_NAME` ';
379 $expectedSql .= 'FROM `INFORMATION_SCHEMA`.`SCHEMATA` ';
380 $expectedSql .= 'WHERE TRUE ';
381 $expectedSql .= 'ORDER BY `SCHEMA_NAME` ';
382 $expectedSql .= 'LIMIT ' . $pos . ', ' . $limit;
384 // It would have been better to mock _getWhereClause method
385 // but strangely, mocking private methods is not supported in PHPUnit
386 $node = NodeFactory::getInstance();
388 $dbi = $this->getMockBuilder(DatabaseInterface::class)
389 ->disableOriginalConstructor()
390 ->getMock();
391 $dbi->expects($this->once())
392 ->method('fetchResult')
393 ->with($expectedSql);
394 $dbi->expects($this->any())->method('escapeString')
395 ->will($this->returnArgument(0));
397 $GLOBALS['dbi'] = $dbi;
398 $node->getData('', $pos);
402 * Tests getData() method when DisableIS is true and navigation tree
403 * grouping enabled.
405 * @test
407 public function testGetDataWithDisabledISAndGroupingEnabled(): void
409 $pos = 0;
410 $limit = 10;
411 $GLOBALS['cfg']['Server']['DisableIS'] = true;
412 $GLOBALS['dbs_to_test'] = false;
413 $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true;
414 $GLOBALS['cfg']['FirstLevelNavigationItems'] = $limit;
415 $GLOBALS['cfg']['NavigationTreeDbSeparator'] = '_';
417 $node = NodeFactory::getInstance();
419 $dbi = $this->getMockBuilder(DatabaseInterface::class)
420 ->disableOriginalConstructor()
421 ->getMock();
422 $dbi->expects($this->once())
423 ->method('tryQuery')
424 ->with("SHOW DATABASES WHERE TRUE AND `Database` LIKE '%db%' ")
425 ->will($this->returnValue(true));
426 $dbi->expects($this->exactly(3))
427 ->method('fetchArray')
428 ->willReturnOnConsecutiveCalls(
429 ['0' => 'db'],
430 ['0' => 'aa_db'],
431 null
434 $dbi->expects($this->once())
435 ->method('fetchResult')
436 ->with(
437 "SHOW DATABASES WHERE TRUE AND `Database` LIKE '%db%' AND ("
438 . " LOCATE('db_', CONCAT(`Database`, '_')) = 1"
439 . " OR LOCATE('aa_', CONCAT(`Database`, '_')) = 1 )"
441 $dbi->expects($this->any())->method('escapeString')
442 ->will($this->returnArgument(0));
444 $GLOBALS['dbi'] = $dbi;
445 $node->getData('', $pos, 'db');
449 * Tests the getPresence method when DisableIS is false and navigation tree
450 * grouping enabled.
452 * @test
454 public function testGetPresenceWithEnabledISAndGroupingEnabled(): void
456 $GLOBALS['cfg']['Server']['DisableIS'] = false;
457 $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true;
458 $GLOBALS['cfg']['NavigationTreeDbSeparator'] = '_';
460 $query = 'SELECT COUNT(*) ';
461 $query .= 'FROM ( ';
462 $query .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, '_', 1) ";
463 $query .= 'DB_first_level ';
464 $query .= 'FROM INFORMATION_SCHEMA.SCHEMATA ';
465 $query .= 'WHERE TRUE ';
466 $query .= ') t ';
468 // It would have been better to mock _getWhereClause method
469 // but strangely, mocking private methods is not supported in PHPUnit
470 $node = NodeFactory::getInstance();
472 $dbi = $this->getMockBuilder(DatabaseInterface::class)
473 ->disableOriginalConstructor()
474 ->getMock();
475 $dbi->expects($this->once())
476 ->method('fetchValue')
477 ->with($query);
478 $GLOBALS['dbi'] = $dbi;
479 $node->getPresence();
483 * Tests the getPresence method when DisableIS is false and navigation tree
484 * grouping disabled.
486 * @test
488 public function testGetPresenceWithEnabledISAndGroupingDisabled(): void
490 $GLOBALS['cfg']['Server']['DisableIS'] = false;
491 $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = false;
493 $query = 'SELECT COUNT(*) ';
494 $query .= 'FROM INFORMATION_SCHEMA.SCHEMATA ';
495 $query .= 'WHERE TRUE ';
497 $node = NodeFactory::getInstance();
498 $dbi = $this->getMockBuilder(DatabaseInterface::class)
499 ->disableOriginalConstructor()
500 ->getMock();
501 $dbi->expects($this->once())
502 ->method('fetchValue')
503 ->with($query);
504 $GLOBALS['dbi'] = $dbi;
505 $node->getPresence();
509 * Tests the getPresence method when DisableIS is true
511 * @test
513 public function testGetPresenceWithDisabledIS(): void
515 $GLOBALS['cfg']['Server']['DisableIS'] = true;
516 $GLOBALS['dbs_to_test'] = false;
517 $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true;
519 $node = NodeFactory::getInstance();
521 // test with no search clause
522 $dbi = $this->getMockBuilder(DatabaseInterface::class)
523 ->disableOriginalConstructor()
524 ->getMock();
525 $dbi->expects($this->once())
526 ->method('tryQuery')
527 ->with('SHOW DATABASES WHERE TRUE ');
528 $dbi->expects($this->any())->method('escapeString')
529 ->will($this->returnArgument(0));
531 $GLOBALS['dbi'] = $dbi;
532 $node->getPresence();
534 // test with a search clause
535 $dbi = $this->getMockBuilder(DatabaseInterface::class)
536 ->disableOriginalConstructor()
537 ->getMock();
538 $dbi->expects($this->once())
539 ->method('tryQuery')
540 ->with("SHOW DATABASES WHERE TRUE AND `Database` LIKE '%dbname%' ");
541 $dbi->expects($this->any())->method('escapeString')
542 ->will($this->returnArgument(0));
544 $GLOBALS['dbi'] = $dbi;
545 $node->getPresence('', 'dbname');