[Tͪ#n$;<:a4sX[ 6F1f=VxMPy$,Ѳrބ!2<-i L.\>Os9˓ELExo|
JP;@/38>i~no&?f9Qvv䳌=1K选$fj]ڟyAxI4"J"NO5q)p RbO)y3nLxLFǃla-2˃>}"ϥPSG#UI6	%SqATсϧ6U&թc
!pG?PH4)V5B:8q@Kjh= UD&*7Ky 4P99V-Z,}d]`@hm?	K~-eg!vm<PB3H^gn#8s	sQ+"`/aݨ:Cx0I5m$6CڹI'qG%)sSOf@c7NR,P@Dg2+_'AڢBϝ]LlK_^+ZEP|͕-TezDQ`l-jÇSf*yna"8;'T<nܸˠ^ @E5u
ϲn"3dZ.`Y'^(biik;,Ϝ?P]B`,Rf,Vo?T!敦_a8F	.xlԛ+EZ_P VTrKaL4++~F0(>^1L^9m{+`JʻMȜ+B'@~`oIUI,	|2Qr
\q-_a
}P$k'Y/ a(qb9{pY)|á!lsw![H0 /M[s,ց)h?wM	TWJ2_镀c;Re ^<q	MY!v$­<@@N{PG,1m4>q ,-:[-;t	鍼BB1卷ˇP+)֑0=ҫhn1K5 )?FRzר`	thvpgZ[>2a@+i(aw˦q9學_B^IPSGRDuʀȞ܂)ҫZF߳o4~sMvMT1ciuz`@+[PRa2}y'"֧8h|d7i4^+C#i_Ɍ.,_Z	Sc	_J\Yl6?HWMY,ڒVZ\/\7sH/
T@eY+kR+6Je{3FwãϏJ\Yl6?HWMY,ڒVZ\/\7n(,=uˏ;878dCs$18#`lH0B\dU<%r&;?;bډ/p>VqTJ;.my^M@ܺӬD{ڽW*ݐj?k&#G$坟0L;쁮72\BQr
\q-_m6(z??iPA
L$, gV'&W9l[&p&EjzO,u)`|)&_?E\6.}8e 릭4ڟ{u?f{XƜ3
eS5$"nUoaMODl?8c]kKn$k^ͣԥE5PU¥<9v.O;#n `O1͐Ct+\TLWCNȪ^N ǻ>>JB$tnknFEx!h0L:KU餧tTûXTj,*y&jUN[Q}?gz)L͘9750ӌk?Avi	Ҥ^AcvK&o{:PGRDuʀȞ܂)ҫZF߳o4~sMvMT1c#cTCJb~)D'a),fxtSt"ey%<gG4%v0Г	jk^Z|D.lMe
09+^J5M;9fmCUWqa~`9M-7KfPxT,u|
_nυniܟ cvF݆ǋD(	"Ǭ^2s&>]L)uεH /M[s,ց)h? 1KLϣQ=˩t=2e	eD2/~=^xT,u|
@Ça-2KOxGۃc=#QL}"!W,ܥ"v%I/JGnx<*jh.W|a9v.O;#MXzN~UH\C56P6NBś8f-YQҦ?IX}B"(ʾf2ZvYl=2\RAη=JF7<J&Ӽ*"qЂb}o$^sWo2A1;ӈ8Hu/-YHmn&=TJ{EvǚՇ"/:;λj )&j#OfG_F1/^Zh2j7[⋚c2}.i3`T";<s&DJ+S ANFr	"g=LJq@;J^J\Yl6?HWMY,ڒVZ\,}*GVUWDr-":c
J=H2b(KMaް|IWID%jh|VE^cY{T;2YNQd}NB6]9eWĲZw/jZvX*{לܴXt7Se\?sUh7cX"9VWzkI+kdX5}֕nG {Q|qTJ;.my^M@ܺӬY(Ql:)s;P26ׁDq$];=1qss&P4֠f'sU.΂VE^cY{T;2Lҳz0*`TXl
ZqaAJB/ߛN:(}CX	[
ܰ[Y>:&)mz
y٦.%B/o*dg=LJq@;J^J\Yl6?HWM.9<m~2JdMbթaB%(ISVꙔ^
UHa	X(:\Zn<G(kӺ7%{6`un`l(i\n.j3{vA+e'U`&I6(BvDһRڈV{DCj%KBw{+n&=TJ{Ev09jlxD^o |[i!޳+6!:*vx!yךZy^PKb7nU{Uw<Φ.X
بAu_cX"DgAoQr
\q-_ݕAiQ'<ǃ01hsjS2KBbrؘ<^U#/2sV݄t!~V]:KysAe 릭4ڟ{u?78,!X꫅arent->numChildren(), 1);
        // add a grandchild to container, this one counts
        $container->addChild(NodeFactory::getInstance());
        $this->assertEquals($parent->numChildren(), 2);
        // add another grandchild to container, this one counts
        $container->addChild(NodeFactory::getInstance());
        $this->assertEquals($parent->numChildren(), 3);
    }

    /**
     * SetUp for parents
     *
     * @return void
     */
    public function testParents()
    {
        $parent = NodeFactory::getInstance();
        $this->assertEquals($parent->parents(), array()); // exclude self
        $this->assertEquals($parent->parents(true), array($parent)); // include self

        $child = NodeFactory::getInstance();
        $parent->addChild($child);

        $this->assertEquals($child->parents(), array($parent)); // exclude self
        $this->assertEquals(
            $child->parents(true),
            array($child, $parent)
        ); // include self
    }

    /**
     * SetUp for realParent
     *
     * @return void
     */
    public function testRealParent()
    {
        $parent = NodeFactory::getInstance();
        $this->assertEquals($parent->realParent(), false);

        $child = NodeFactory::getInstance();
        $parent->addChild($child);
        $this->assertEquals($child->realParent(), $parent);
    }

    /**
     * Tests whether Node->hasSiblings() method returns false
     * when the node does not have any siblings.
     *
     * @return void
     * @test
     */
    public function testHasSiblingsWithNoSiblings()
    {
        $parent = NodeFactory::getInstance();
        $child = NodeFactory::getInstance();
        $parent->addChild($child);
        $this->assertEquals(false, $child->hasSiblings());
    }

    /**
     * Tests whether Node->hasSiblings() method returns true
     * when it actually has siblings.
     *
     * @return void
     * @test
     */
    public function testHasSiblingsWithSiblings()
    {
        $parent = NodeFactory::getInstance();
        $firstChild = NodeFactory::getInstance();
        $parent->addChild($firstChild);
        $secondChild = NodeFactory::getInstance();
        $parent->addChild($secondChild);
        // Normal case; two Node:NODE type siblings
        $this->assertEquals(true, $firstChild->hasSiblings());

        $parent = NodeFactory::getInstance();
        $firstChild = NodeFactory::getInstance();
        $parent->addChild($firstChild);
        $secondChild = NodeFactory::getInstance(
            'Node', 'default', Node::CONTAINER
        );
        $parent->addChild($secondChild);
        // Empty Node::CONTAINER type node should not be considered in hasSiblings()
        $this->assertEquals(false, $firstChild->hasSiblings());

        $grandChild = NodeFactory::getInstance();
        $secondChild->addChild($grandChild);
        // Node::CONTAINER type nodes with children are counted for hasSiblings()
        $this->assertEquals(true, $firstChild->hasSiblings());
    }

    /**
     * It is expected that Node->hasSiblings() method always return true
     * for Nodes that are 3 levels deep (columns and indexes).
     *
     * @return void
     * @test
     */
    public function testHasSiblingsForNodesAtLevelThree()
    {
        $parent = NodeFactory::getInstance();
        $child = NodeFactory::getInstance();
        $parent->addChild($child);
        $grandChild = NodeFactory::getInstance();
        $child->addChild($grandChild);
        $greatGrandChild = NodeFactory::getInstance();
        $grandChild->addChild($greatGrandChild);

        // Should return false for node that are two levels deeps
        $this->assertEquals(false, $grandChild->hasSiblings());
        // Should return true for node that are three levels deeps
        $this->assertEquals(true, $greatGrandChild->hasSiblings());
    }

    /**
     * Tests private method _getWhereClause()
     *
     * @return void
     * @test
     */
    public function testGetWhereClause()
    {
        $method = new ReflectionMethod(
            'PMA\libraries\navigation\nodes\Node', '_getWhereClause'
        );
        $method->setAccessible(true);

        // Vanilla case
        $node = NodeFactory::getInstance();
        $this->assertEquals(
            "WHERE TRUE ", $method->invoke($node, 'SCHEMA_NAME')
        );

        // When a schema names is passed as search clause
        $this->assertEquals(
            "WHERE TRUE AND `SCHEMA_NAME` LIKE '%schemaName%' ",
            $method->invoke($node, 'SCHEMA_NAME', 'schemaName')
        );

        if (! isset($GLOBALS['cfg']['Server'])) {
            $GLOBALS['cfg']['Server'] = array();
        }

        // When hide_db regular expression is present
        $GLOBALS['cfg']['Server']['hide_db'] = 'regexpHideDb';
        $this->assertEquals(
            "WHERE TRUE AND `SCHEMA_NAME` NOT REGEXP 'regexpHideDb' ",
            $method->invoke($node, 'SCHEMA_NAME')
        );
        unset($GLOBALS['cfg']['Server']['hide_db']);

        // When only_db directive is present and it's a single db
        $GLOBALS['cfg']['Server']['only_db'] = 'stringOnlyDb';
        $this->assertEquals(
            "WHERE TRUE AND ( `SCHEMA_NAME` LIKE 'stringOnlyDb' ) ",
            $method->invoke($node, 'SCHEMA_NAME')
        );
        unset($GLOBALS['cfg']['Server']['only_db']);

        // When only_db directive is present and it's an array of dbs
        $GLOBALS['cfg']['Server']['only_db'] = array('onlyDbOne', 'onlyDbTwo');
        $this->assertEquals(
            "WHERE TRUE AND ( `SCHEMA_NAME` LIKE 'onlyDbOne' "
            . "OR `SCHEMA_NAME` LIKE 'onlyDbTwo' ) ",
            $method->invoke($node, 'SCHEMA_NAME')
        );
        unset($GLOBALS['cfg']['Server']['only_db']);
    }

    /**
     * Tests getData() method when DisableIS is false and navigation tree
     * grouping enabled.
     *
     * @return void
     * @test
     */
    public function testGetDataWithEnabledISAndGroupingEnabled()
    {
        $pos = 10;
        $limit = 20;
        $GLOBALS['cfg']['Server']['DisableIS'] = false;
        $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true;
        $GLOBALS['cfg']['FirstLevelNavigationItems'] = $limit;
        $GLOBALS['cfg']['NavigationTreeDbSeparator'] = '_';

        $expectedSql  = "SELECT `SCHEMA_NAME` ";
        $expectedSql .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA`, ";
        $expectedSql .= "(";
        $expectedSql .= "SELECT DB_first_level ";
        $expectedSql .= "FROM ( ";
        $expectedSql .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, ";
        $expectedSql .= "'_', 1) ";
        $expectedSql .= "DB_first_level ";
        $expectedSql .= "FROM INFORMATION_SCHEMA.SCHEMATA ";
        $expectedSql .= "WHERE TRUE ";
        $expectedSql .= ") t ";
        $expectedSql .= "ORDER BY DB_first_level ASC ";
        $expectedSql .= "LIMIT $pos, $limit";
        $expectedSql .= ") t2 ";
        $expectedSql .= "WHERE TRUE AND 1 = LOCATE(CONCAT(DB_first_level, '_'), ";
        $expectedSql .= "CONCAT(SCHEMA_NAME, '_')) ";
        $expectedSql .= "ORDER BY SCHEMA_NAME ASC";

        // It would have been better to mock _getWhereClause method
        // but strangely, mocking private methods is not supported in PHPUnit
        $node = NodeFactory::getInstance();

        $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface')
            ->disableOriginalConstructor()
            ->getMock();
        $dbi->expects($this->once())
            ->method('fetchResult')
            ->with($expectedSql);
        $dbi->expects($this->any())->method('escapeString')
            ->will($this->returnArgument(0));
        $GLOBALS['dbi'] = $dbi;
        $node->getData('', $pos);
    }

    /**
     * Tests getData() method when DisableIS is false and navigation tree
     * grouping disabled.
     *
     * @return void
     * @test
     */
    public function testGetDataWithEnabledISAndGroupingDisabled()
    {
        $pos = 10;
        $limit = 20;
        $GLOBALS['cfg']['Server']['DisableIS'] = false;
        $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = false;
        $GLOBALS['cfg']['FirstLevelNavigationItems'] = $limit;

        $expectedSql  = "SELECT `SCHEMA_NAME` ";
        $expectedSql .= "FROM `INFORMATION_SCHEMA`.`SCHEMATA` ";
        $expectedSql .= "WHERE TRUE ";
        $expectedSql .= "ORDER BY `SCHEMA_NAME` ";
        $expectedSql .= "LIMIT $pos, $limit";

        // It would have been better to mock _getWhereClause method
        // but strangely, mocking private methods is not supported in PHPUnit
        $node = NodeFactory::getInstance();

        $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface')
            ->disableOriginalConstructor()
            ->getMock();
        $dbi->expects($this->once())
            ->method('fetchResult')
            ->with($expectedSql);
        $dbi->expects($this->any())->method('escapeString')
            ->will($this->returnArgument(0));

        $GLOBALS['dbi'] = $dbi;
        $node->getData('', $pos);
    }

    /**
     * Tests getData() method when DisableIS is true and navigation tree
     * grouping enabled.
     *
     * @return void
     * @test
     */
    public function testGetDataWithDisabledISAndGroupingEnabled()
    {
        $pos = 0;
        $limit = 10;
        $GLOBALS['cfg']['Server']['DisableIS'] = true;
        $GLOBALS['dbs_to_test'] = false;
        $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true;
        $GLOBALS['cfg']['FirstLevelNavigationItems'] = $limit;
        $GLOBALS['cfg']['NavigationTreeDbSeparator'] = '_';

        $node = NodeFactory::getInstance();

        $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface')
            ->disableOriginalConstructor()
            ->getMock();
        $dbi->expects($this->once())
            ->method('tryQuery')
            ->with("SHOW DATABASES WHERE TRUE AND `Database` LIKE '%db%' ")
            ->will($this->returnValue(true));
        $dbi->expects($this->exactly(3))
            ->method('fetchArray')
            ->willReturnOnConsecutiveCalls(
                array(
                    '0' => 'db'
                ),
                array(
                    '0' => 'aa_db'
                ),
                false
            );

        $dbi->expects($this->once())
            ->method('fetchResult')
            ->with(
                "SHOW DATABASES WHERE TRUE AND `Database` LIKE '%db%' AND ("
                . " LOCATE('db_', CONCAT(`Database`, '_')) = 1"
                . " OR LOCATE('aa_', CONCAT(`Database`, '_')) = 1 )"
            );
        $dbi->expects($this->any())->method('escapeString')
            ->will($this->returnArgument(0));

        $GLOBALS['dbi'] = $dbi;
        $node->getData('', $pos, 'db');
    }

    /**
     * Tests the getPresence method when DisableIS is false and navigation tree
     * grouping enabled.
     *
     * @return void
     * @test
     */
    public function testGetPresenceWithEnabledISAndGroupingEnabled()
    {
        $GLOBALS['cfg']['Server']['DisableIS'] = false;
        $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true;
        $GLOBALS['cfg']['NavigationTreeDbSeparator'] = '_';

        $query = "SELECT COUNT(*) ";
        $query .= "FROM ( ";
        $query .= "SELECT DISTINCT SUBSTRING_INDEX(SCHEMA_NAME, '_', 1) ";
        $query .= "DB_first_level ";
        $query .= "FROM INFORMATION_SCHEMA.SCHEMATA ";
        $query .= "WHERE TRUE ";
        $query .= ") t ";

        // It would have been better to mock _getWhereClause method
        // but strangely, mocking private methods is not supported in PHPUnit
        $node = NodeFactory::getInstance();

        $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface')
            ->disableOriginalConstructor()
            ->getMock();
        $dbi->expects($this->once())
            ->method('fetchValue')
            ->with($query);
        $GLOBALS['dbi'] = $dbi;
        $node->getPresence();
    }

    /**
     * Tests the getPresence method when DisableIS is false and navigation tree
     * grouping disabled.
     *
     * @return void
     * @test
     */
    public function testGetPresenceWithEnabledISAndGroupingDisabled()
    {
        $GLOBALS['cfg']['Server']['DisableIS'] = false;
        $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = false;

        $query = "SELECT COUNT(*) ";
        $query .= "FROM INFORMATION_SCHEMA.SCHEMATA ";
        $query .= "WHERE TRUE ";

        $node = NodeFactory::getInstance();
        $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface')
            ->disableOriginalConstructor()
            ->getMock();
        $dbi->expects($this->once())
            ->method('fetchValue')
            ->with($query);
        $GLOBALS['dbi'] = $dbi;
        $node->getPresence();
    }

    /**
     * Tests the getPresence method when DisableIS is true
     *
     * @return void
     * @test
     */
    public function testGetPresenceWithDisabledIS()
    {
        $GLOBALS['cfg']['Server']['DisableIS'] = true;
        $GLOBALS['dbs_to_test'] = false;
        $GLOBALS['cfg']['NavigationTreeEnableGrouping'] = true;

        $node = NodeFactory::getInstance();

        // test with no search clause
        $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface')
            ->disableOriginalConstructor()
            ->getMock();
        $dbi->expects($this->once())
            ->method('tryQuery')
            ->with("SHOW DATABASES WHERE TRUE ");
        $dbi->expects($this->any())->method('escapeString')
            ->will($this->returnArgument(0));

        $GLOBALS['dbi'] = $dbi;
        $node->getPresence();

        // test with a search clause
        $dbi = $this->getMockBuilder('PMA\libraries\DatabaseInterface')
            ->disableOriginalConstructor()
            ->getMock();
        $dbi->expects($this->once())
            ->method('tryQuery')
            ->with("SHOW DATABASES WHERE TRUE AND `Database` LIKE '%dbname%' ");
        $dbi->expects($this->any())->method('escapeString')
            ->will($this->returnArgument(0));

        $GLOBALS['dbi'] = $dbi;
        $node->getPresence('', 'dbname');
    }
}
