Completed
Push — master ( 9eea1d...6105f5 )
by Lucas
07:27
created

RqlTranslatorTest::testDateSearchNode()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 40
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 40
rs 8.8571
cc 1
eloc 22
nc 1
nop 0
1
<?php
2
/**
3
 * translator tests
4
 */
5
6
namespace Graviton\RestBundle\Service;
7
8
use Graviton\Rql\Node\SearchNode;
9
use Xiag\Rql\Parser\Node\Query\LogicOperator\AndNode;
10
use Xiag\Rql\Parser\Node\Query\LogicOperator\OrNode;
11
use Xiag\Rql\Parser\Node\Query\ScalarOperator\EqNode;
12
use Xiag\Rql\Parser\Node\Query\ScalarOperator\GeNode;
13
use Xiag\Rql\Parser\Node\Query\ScalarOperator\LeNode;
14
use Xiag\Rql\Parser\Node\Query\ScalarOperator\LikeNode;
15
use Xiag\Rql\Parser\Query;
16
17
/**
18
 * Class RqlTranslatorTest
19
 * @package Graviton\RestBundle\Service
20
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
21
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
22
 * @link     http://swisscom.ch
23
 */
24
class RqlTranslatorTest extends \PHPUnit_Framework_TestCase
25
{
26
    /** @var  RqlTranslator */
27
    protected $sut;
28
29
    /**
30
     * PHPUnit set up
31
     *
32
     * @return void
33
     */
34
    protected function setUp()
35
    {
36
        $this->sut = new RqlTranslator();
37
    }
38
39
    /**
40
     * Test for correct node translation with search terms
41
     *
42
     * @return void
43
     */
44 View Code Duplication
    public function testSearchNodeTranslation()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
45
    {
46
        $searchNode = new SearchNode(array('searchTerm1', 'searchTerm2'));
47
48
        $resultingOrNode = $this->sut->translateSearchNode($searchNode, array('testField'));
49
50
        $this->assertTrue($resultingOrNode instanceof OrNode);
51
        $this->assertEquals(2, sizeof($resultingOrNode->getQueries()));
0 ignored issues
show
Bug introduced by
The method getQueries does only exist in Xiag\Rql\Parser\Node\Query\LogicOperator\OrNode, but not in Graviton\Rql\Node\Search...y\ScalarOperator\EqNode.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
52
    }
53
54
    /**
55
     * test for correct not translation without searches
56
     *
57
     * @return void
58
     */
59 View Code Duplication
    public function testEmptySearch()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
60
    {
61
        $searchNode = new SearchNode();
62
63
        $resultingOrNode = $this->sut->translateSearchNode($searchNode, array('testField'));
64
65
        $this->assertTrue($resultingOrNode instanceof SearchNode);
66
        $this->assertEquals(0, sizeof($resultingOrNode->getSearchTerms()));
0 ignored issues
show
Bug introduced by
The method getSearchTerms does only exist in Graviton\Rql\Node\SearchNode, but not in Xiag\Rql\Parser\Node\Que...y\ScalarOperator\EqNode.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
67
    }
68
69
    /**
70
     * Test correct translation with already existing queries
71
     *
72
     * @return void
73
     */
74
    public function testQueryTranslation()
75
    {
76
        // Construct scenario:
77
        $query = new Query();
78
        $andQuery = new AndNode();
79
        $andQuery->addQuery(new LikeNode("firstName", "TestFirstName"));
80
        $andQuery->addQuery(new LikeNode("lastName", "TestLastName"));
81
        $andQuery->addQuery(new SearchNode(array("searchTerm1", "searchTerm2")));
82
        $query->setQuery($andQuery);
83
84
        $searchFields = array('field1', 'field2');
85
86
        /** @var Query $resultQuery */
87
        $resultQuery = $this->sut->translateSearchQuery($query, $searchFields);
88
89
        /** @var AndNode $resultInnerQuery */
90
        $resultInnerQuery = $resultQuery->getQuery();
91
92
        $this->assertTrue($resultInnerQuery instanceof AndNode);
93
        $this->assertEquals(3, sizeof($resultInnerQuery->getQueries()));
94
95
        $subNodes = $resultInnerQuery->getQueries();
96
97
        $this->assertTrue($subNodes[0] instanceof LikeNode);
98
        $this->assertTrue($subNodes[1] instanceof LikeNode);
99
        $this->assertTrue($subNodes[2] instanceof OrNode);
100
101
    }
102
103
    /**
104
     * Test for correct translations with numeric fields
105
     *
106
     * @return void
107
     */
108
    public function testNumericSearchNode()
109
    {
110
        // Construct scenario:
111
        $query = new Query();
112
        $andQuery = new AndNode();
113
        $andQuery->addQuery(new LikeNode("lastName", "TestLastName"));
114
        $andQuery->addQuery(new SearchNode(array(10023)));
115
        $query->setQuery($andQuery);
116
117
        $searchFields = array('field1');
118
119
        /** @var Query $resultQuery */
120
        $resultQuery = $this->sut->translateSearchQuery($query, $searchFields);
121
122
        /** @var AndNode $resultInnerQuery */
123
        $resultInnerQuery = $resultQuery->getQuery();
124
125
        $this->assertTrue($resultInnerQuery instanceof AndNode);
126
        $this->assertEquals(2, sizeof($resultInnerQuery->getQueries()));
127
128
        $subNodes = $resultInnerQuery->getQueries();
129
130
        $this->assertTrue($subNodes[0] instanceof LikeNode);
131
        $this->assertTrue($subNodes[1] instanceof OrNode);
132
133
        /** @var OrNode $searchOrNode */
134
        $searchOrNode = $subNodes[1];
135
136
        $orSubNotes = $searchOrNode->getQueries();
137
138
        $this->assertTrue($orSubNotes[0] instanceof LikeNode);
139
        $this->assertTrue($orSubNotes[1] instanceof EqNode);
140
    }
141
142
    /**
143
     * Test for correct translations with dates
144
     *
145
     * @return void
146
     */
147
    public function testDateSearchNode()
148
    {
149
        // Construct scenario:
150
        $query = new Query();
151
        $andQuery = new AndNode();
152
        $andQuery->addQuery(new LikeNode("lastName", "TestLastName"));
153
        $andQuery->addQuery(new SearchNode(array('29.12.1981')));
154
        $query->setQuery($andQuery);
155
156
        $searchFields = array('field1');
157
158
        /** @var Query $resultQuery */
159
        $resultQuery = $this->sut->translateSearchQuery($query, $searchFields);
160
161
        /** @var AndNode $resultInnerQuery */
162
        $resultInnerQuery = $resultQuery->getQuery();
163
164
        $this->assertTrue($resultInnerQuery instanceof AndNode);
165
        $this->assertEquals(2, sizeof($resultInnerQuery->getQueries()));
166
167
        $subNodes = $resultInnerQuery->getQueries();
168
169
        $this->assertTrue($subNodes[0] instanceof LikeNode);
170
        $this->assertTrue($subNodes[1] instanceof OrNode);
171
172
        /** @var OrNode $searchOrNode */
173
        $searchOrNode = $subNodes[1];
174
175
        $orSubNotes = $searchOrNode->getQueries();
176
177
        $this->assertTrue($orSubNotes[0] instanceof LikeNode);
178
        $this->assertTrue($orSubNotes[1] instanceof AndNode);
179
180
        /** @var AndNode $searchOrNode */
181
        $dateAndNode = $orSubNotes[1];
182
        $dateAndSubNodes = $dateAndNode->getQueries();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Xiag\Rql\Parser\Node\AbstractQueryNode as the method getQueries() does only exist in the following sub-classes of Xiag\Rql\Parser\Node\AbstractQueryNode: Xiag\Rql\Parser\Node\Que...stractLogicOperatorNode, Xiag\Rql\Parser\Node\Query\LogicOperator\AndNode, Xiag\Rql\Parser\Node\Query\LogicOperator\NotNode, Xiag\Rql\Parser\Node\Query\LogicOperator\OrNode. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
183
184
        $this->assertTrue($dateAndSubNodes[0] instanceof GeNode);
185
        $this->assertTrue($dateAndSubNodes[1] instanceof LeNode);
186
    }
187
}
188