PageRenderTime 99ms CodeModel.GetById 61ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 1ms

/OData Producer for PHP/Tests/UriProcessor/QueryProcessor/ExpressionParser/PHPExpressionProviderTest.php

#
PHP | 692 lines | 539 code | 79 blank | 74 comment | 2 complexity | a17a17f8991c52c0b66174f430debf66 MD5 | raw file
  1<?php
  2require_once 'PHPUnit\Framework\Assert.php';
  3require_once 'PHPUnit\Framework\Test.php';
  4require_once 'PHPUnit\Framework\SelfDescribing.php';
  5require_once 'PHPUnit\Framework\TestCase.php';
  6require_once 'PHPUnit\Framework\TestSuite.php';
  7require_once 'ODataProducer\Common\ClassAutoLoader.php';
  8require_once (dirname(__FILE__) . "\..\..\..\Resources\NorthWindMetadata.php");
  9use ODataProducer\Providers\Metadata\Type\Int32;
 10use ODataProducer\Providers\Metadata\Type\Int64;
 11use ODataProducer\Providers\Metadata\Type\Double;
 12use ODataProducer\Providers\Metadata\Type\Single;
 13use ODataProducer\Providers\Metadata\Type\Decimal;
 14use ODataProducer\Providers\Metadata\Type\DateTime;
 15use ODataProducer\Providers\Metadata\Type\Binary;
 16use ODataProducer\Providers\Metadata\Type\String;
 17use ODataProducer\Providers\Metadata\Type\Navigation;
 18use ODataProducer\Providers\Metadata\Type\Boolean;
 19use ODataProducer\Providers\Metadata\Type\Null1;
 20use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\Expressions\PropertyAccessExpression;
 21use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\Expressions\ConstantExpression;
 22use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\Expressions\ArithmeticExpression;
 23use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\Expressions\LogicalExpression;
 24use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\Expressions\RelationalExpression;
 25use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\Expressions\FunctionCallExpression;
 26use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\Expressions\UnaryExpression;
 27use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\Expressions\ExpressionType;
 28use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\ExpressionParser2;
 29use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\ExpressionProcessor;
 30use ODataProducer\UriProcessor\QueryProcessor\ExpressionParser\PHPExpressionProvider;
 31use ODataProducer\Common\ODataException;
 32ODataProducer\Common\ClassAutoLoader::register();
 33class PHPExpressionProviderTest1 extends PHPUnit_Framework_TestCase
 34{
 35    private $_northWindMetadata;
 36    
 37    protected function setUp()
 38    {        
 39         $this->_northWindMetadata = CreateNorthWindMetadata3::Create();
 40    }
 41    
 42    /**     
 43     * Test null checks are propagated properly
 44     */
 45    public function testNullabilityChecking()
 46    {
 47        try {
 48            //Relational EQUAL expression with left child as arithmetic expression, the null check should propagte from AE to LE level
 49            $odataUriExpression = 'Customer/Address/LineNumber add 4 eq 8';
 50            $parser = new ExpressionParser2($odataUriExpression,
 51                            $this->_northWindMetadata->resolveResourceSet('Orders')->getResourceType(),
 52            		        null);
 53            $expressionTree = $parser->parseFilter();
 54            $expressionProcessor = new ExpressionProcessor($expressionTree, new PHPExpressionProvider('$lt'));
 55            $actualPHPExpression = $expressionProcessor->processExpression();
 56            $expectedPHPExpression = '(((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && (($lt->Customer->Address->LineNumber + 4) == 8))';
 57            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
 58            
 59            //Relational EQUAL expression with both children as arithmetic expression, the null check should propagte from AE to LE level
 60            $odataUriExpression = 'Customer/Address/LineNumber add Customer/Address/LineNumber2 eq 8';
 61            $parser->resetParser($odataUriExpression);
 62            $expressionProcessor->setExpression($parser->parseFilter());
 63            $actualPHPExpression = $expressionProcessor->processExpression();        
 64            $expectedPHPExpression = '((((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && !(is_null($lt->Customer->Address->LineNumber2))) && (($lt->Customer->Address->LineNumber + $lt->Customer->Address->LineNumber2) == 8))';
 65            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
 66            
 67            //Logical AND expression with both child as relational expression, with left relational expressions having arithmetic expression
 68            //(with nullability check) as children, null check should propagate from AE to RE to LE.
 69            $odataUriExpression = 'Customer/Address/LineNumber add 2 eq 4 and 6 mul 7 eq 42';
 70            $parser->resetParser($odataUriExpression);            
 71            $expressionProcessor->setExpression($parser->parseFilter());
 72            $actualPHPExpression = $expressionProcessor->processExpression();
 73            $expectedPHPExpression = '(((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && ((($lt->Customer->Address->LineNumber + 2) == 4) && ((6 * 7) == 42)))';                        
 74            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
 75            
 76            //Logical AND expression with both child as relational expression, with right relational expressions having arithmetic expressions
 77            //(with nullability check) as children, null check should propagate from AE to RE to LE.
 78            $odataUriExpression = '6 mul 7 eq 42 and Customer/Address/LineNumber add 2 eq 4';
 79            $parser->resetParser($odataUriExpression);            
 80            $expressionProcessor->setExpression($parser->parseFilter());
 81            $actualPHPExpression = $expressionProcessor->processExpression();
 82            $expectedPHPExpression = '(((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && (((6 * 7) == 42) && (($lt->Customer->Address->LineNumber + 2) == 4)))';                        
 83            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
 84            
 85            //Logical AND expression with both child as relational expression, with right and left relational expressions having arithmetic expressions
 86            //(with nullability check) as children, null check should propagate from both AE to RE to LE.
 87            $odataUriExpression = 'Customer/Address/LineNumber add 2 eq 4 and Customer/Address/LineNumber2 sub 2 ne 6';
 88            $parser->resetParser($odataUriExpression);
 89            $expressionProcessor->setExpression($parser->parseFilter());
 90            $actualPHPExpression = $expressionProcessor->processExpression();
 91            $expectedPHPExpression = '((((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && !(is_null($lt->Customer->Address->LineNumber2))) && ((($lt->Customer->Address->LineNumber + 2) == 4) && (($lt->Customer->Address->LineNumber2 - 2) != 6)))';
 92            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
 93            
 94            //Logical OR expression with both child as relational expression, with left relational expressions having arithmetic expressions
 95            //(with nullability check) as children, null check should propagate from AE to RE only not to LE.
 96            $odataUriExpression = 'Customer/Address/LineNumber add 2 eq 4 or 6 mul 7 eq 42';
 97            $parser->resetParser($odataUriExpression);            
 98            $expressionProcessor->setExpression($parser->parseFilter());
 99            $actualPHPExpression = $expressionProcessor->processExpression();
100            $expectedPHPExpression = '((((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && (($lt->Customer->Address->LineNumber + 2) == 4)) || ((6 * 7) == 42))';
101            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
102            
103            //Logical OR expression with both child as relational expression, with right relational expressions having arithmetic expressions
104            //(with nullability check) as children, null check should propagate from AE to RE only not to LE.
105            $odataUriExpression = '6 mul 7 eq 42 or Customer/Address/LineNumber add 2 eq 4';
106            $parser->resetParser($odataUriExpression);            
107            $expressionProcessor->setExpression($parser->parseFilter());
108            $actualPHPExpression = $expressionProcessor->processExpression();                        
109            $expectedPHPExpression = '(((6 * 7) == 42) || (((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && (($lt->Customer->Address->LineNumber + 2) == 4)))';
110            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
111            
112            //Logical OR expression with both child as relational expression, both having relational expression (candidate for nullability check) as children, 
113            //null check should navigate from AE to RE only not to LE.
114            $odataUriExpression = 'Customer/Address/LineNumber add 2 eq 4 or Customer/Address/LineNumber2 sub 2 ne 6';
115            $parser->resetParser($odataUriExpression);
116            $expressionProcessor->setExpression($parser->parseFilter());
117            $actualPHPExpression = $expressionProcessor->processExpression();
118            $expectedPHPExpression = '((((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && (($lt->Customer->Address->LineNumber + 2) == 4)) || (((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber2))) && (($lt->Customer->Address->LineNumber2 - 2) != 6)))';
119            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
120            
121            //Relational expression as root
122            $odataUriExpression = 'Customer/Address/Address2/IsPrimary eq true';
123            $parser->resetParser($odataUriExpression);
124            $expressionProcessor->setExpression($parser->parseFilter());
125            $actualPHPExpression = $expressionProcessor->processExpression();
126            $expectedPHPExpression = '((((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->Address2))) && !(is_null($lt->Customer->Address->Address2->IsPrimary))) && ($lt->Customer->Address->Address2->IsPrimary == true))';
127            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
128            
129            //Logical AND expression without relational expression
130            $odataUriExpression = 'Customer/Address/Address2/IsPrimary and Customer/Address/IsValid';
131            $parser->resetParser($odataUriExpression);
132            $expressionProcessor->setExpression($parser->parseFilter());
133            $actualPHPExpression = $expressionProcessor->processExpression();  
134            $expectedPHPExpression = '(((((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->Address2))) && !(is_null($lt->Customer->Address->Address2->IsPrimary))) && !(is_null($lt->Customer->Address->IsValid))) && ($lt->Customer->Address->Address2->IsPrimary && $lt->Customer->Address->IsValid))';
135            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
136            
137            //Logical OR expression without relational expression
138            $odataUriExpression = 'Customer/Address/Address2/IsPrimary or Customer/Address/IsValid';
139            $parser->resetParser($odataUriExpression);
140            $expressionProcessor->setExpression($parser->parseFilter());
141            $actualPHPExpression = $expressionProcessor->processExpression();  
142            $expectedPHPExpression = '(((((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->Address2))) && !(is_null($lt->Customer->Address->Address2->IsPrimary))) && $lt->Customer->Address->Address2->IsPrimary) || (((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->IsValid))) && $lt->Customer->Address->IsValid))';
143            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
144            
145            $odataUriExpression = 'Customer/Address/Address2/IsPrimary le Customer/Address/IsValid';
146            $parser->resetParser($odataUriExpression);
147            $expressionProcessor->setExpression($parser->parseFilter());
148            $actualPHPExpression = $expressionProcessor->processExpression();
149            $expectedPHPExpression = '(((((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->Address2))) && !(is_null($lt->Customer->Address->Address2->IsPrimary))) && !(is_null($lt->Customer->Address->IsValid))) && ($lt->Customer->Address->Address2->IsPrimary <= $lt->Customer->Address->IsValid))';
150            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
151            
152            //Relational expression with child as logical expression
153            $odataUriExpression = '(Customer/Address/IsValid and true) eq false';
154            $parser->resetParser($odataUriExpression);
155            $expressionProcessor->setExpression($parser->parseFilter());
156            $actualPHPExpression = $expressionProcessor->processExpression();
157            $expectedPHPExpression = '(((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->IsValid))) && (($lt->Customer->Address->IsValid && true) == false))';
158            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
159            
160            //Nullability check for property
161            $odataUriExpression = 'Customer/Address/IsValid eq null';
162            $parser->resetParser($odataUriExpression);
163            $expressionProcessor->setExpression($parser->parseFilter());
164            $actualPHPExpression = $expressionProcessor->processExpression();      
165            $expectedPHPExpression = '((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && is_null($lt->Customer->Address->IsValid))';
166            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
167            
168            //Property access expression as root
169            $odataUriExpression = 'Customer/Address/IsValid';
170            $parser->resetParser($odataUriExpression);
171            $expressionProcessor->setExpression($parser->parseFilter());
172            $actualPHPExpression = $expressionProcessor->processExpression();
173            $expectedPHPExpression = '(((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->IsValid))) && $lt->Customer->Address->IsValid)';
174            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
175            
176            //Unary NOT with Relational expressons as child
177            $odataUriExpression = 'not(Customer/Address/LineNumber eq 4)';
178            $parser->resetParser($odataUriExpression);
179            $expressionProcessor->setExpression($parser->parseFilter());
180            $actualPHPExpression = $expressionProcessor->processExpression();
181            $expectedPHPExpression = '(((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && !(($lt->Customer->Address->LineNumber == 4)))';
182            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
183            
184            //Unary NOT with Logical AND expressons as child
185            $odataUriExpression = 'not(Customer/Address/LineNumber add 2 eq 4 and true)';
186            $parser->resetParser($odataUriExpression);
187            $expressionProcessor->setExpression($parser->parseFilter());
188            $actualPHPExpression = $expressionProcessor->processExpression();
189            $expectedPHPExpression = '(((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && !(((($lt->Customer->Address->LineNumber + 2) == 4) && true)))';
190            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
191            
192           //Unary NOT with Logical OR expressons as child
193            $odataUriExpression = 'not(Customer/Address/LineNumber add 2 eq 4 or true)';
194            $parser->resetParser($odataUriExpression);
195            $expressionProcessor->setExpression($parser->parseFilter());
196            $actualPHPExpression = $expressionProcessor->processExpression();
197            $expectedPHPExpression = '!(((((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->LineNumber))) && (($lt->Customer->Address->LineNumber + 2) == 4)) || true))';
198            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
199            
200            //Logical AND with not as child
201            $odataUriExpression = 'not(Customer/Address/IsValid) and true';
202            $parser->resetParser($odataUriExpression);
203            $expressionProcessor->setExpression($parser->parseFilter());
204            $actualPHPExpression = $expressionProcessor->processExpression();
205            $expectedPHPExpression = '(((!(is_null($lt->Customer)) && !(is_null($lt->Customer->Address))) && !(is_null($lt->Customer->Address->IsValid))) && (!($lt->Customer->Address->IsValid) && true))';
206            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
207            
208        }catch (ODataException $exception) {
209            $this->fail('An unexpected ODataException has been raised.' . $exception->getMessage());
210        }
211    }
212    
213    /**     
214     * Test the possible string operators defined for filter option 
215     */
216    public function testStringFunctions()
217    {
218        try {            
219            $odataUriExpression = 'CustomerID ge \'ALFKI\'';
220            $parser = new ExpressionParser2($odataUriExpression,
221                            $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(),
222            		        null);
223            $expressionTree = $parser->parseFilter();
224            $expressionProcessor = new ExpressionProcessor($expressionTree, new PHPExpressionProvider('$lt'));
225            $actualPHPExpression = $expressionProcessor->processExpression();
226            $expectedPHPExpression = '(!(is_null($lt->CustomerID)) && (strcmp($lt->CustomerID, \'ALFKI\') >= 0))';
227            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
228            
229            $odataUriExpression = 'endswith(CustomerID, \'KI\')';
230            $parser->resetParser($odataUriExpression);
231            $expressionProcessor->setExpression($parser->parseFilter());
232            $actualPHPExpression = $expressionProcessor->processExpression();
233            $expectedPHPExpression = '(!(is_null($lt->CustomerID)) && (strcmp(substr($lt->CustomerID, strlen($lt->CustomerID) - strlen(\'KI\')), \'KI\') === 0))';
234            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
235            
236            $odataUriExpression = 'indexof(CustomerID, \'LFK\') eq 2';
237            $parser->resetParser($odataUriExpression);
238            $expressionProcessor->setExpression($parser->parseFilter());
239            $actualPHPExpression = $expressionProcessor->processExpression();
240            $expectedPHPExpression = '(!(is_null($lt->CustomerID)) && (strpos($lt->CustomerID, \'LFK\') == 2))';
241            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
242            
243            $odataUriExpression = 'replace(CustomerID, \'LFK\', \'RTT\') eq \'ARTTI\'';
244            $parser->resetParser($odataUriExpression);
245            $expressionProcessor->setExpression($parser->parseFilter());
246            $actualPHPExpression = $expressionProcessor->processExpression();
247            $expectedPHPExpression = '(!(is_null($lt->CustomerID)) && (strcmp(str_replace(\'LFK\', \'RTT\', $lt->CustomerID), \'ARTTI\') == 0))';
248            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
249            
250            $odataUriExpression = 'startswith(CustomerID, \'AL\')';
251            $parser->resetParser($odataUriExpression);
252            $expressionProcessor->setExpression($parser->parseFilter());
253            $actualPHPExpression = $expressionProcessor->processExpression();
254            $expectedPHPExpression = '(!(is_null($lt->CustomerID)) && (strpos($lt->CustomerID, \'AL\') === 0))';
255            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
256            
257            $odataUriExpression = 'tolower(\'PeRsIsTeNt\') eq \'persistent\'';
258            $parser->resetParser($odataUriExpression);
259            $expressionProcessor->setExpression($parser->parseFilter());
260            $actualPHPExpression = $expressionProcessor->processExpression();            
261            $expectedPHPExpression = '(strcmp(strtolower(\'PeRsIsTeNt\'), \'persistent\') == 0)';
262            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
263            
264            $odataUriExpression = 'toupper(\'mICRosoFT\') eq \'MICROSOFT\'';
265            $parser->resetParser($odataUriExpression);
266            $expressionProcessor->setExpression($parser->parseFilter());
267            $actualPHPExpression = $expressionProcessor->processExpression();            
268            $expectedPHPExpression = '(strcmp(strtoupper(\'mICRosoFT\'), \'MICROSOFT\') == 0)';
269            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
270            
271            $odataUriExpression = 'trim(\'  ODataPHP Producer   \') eq null';
272            $parser->resetParser($odataUriExpression);
273            $expressionProcessor->setExpression($parser->parseFilter());
274            $actualPHPExpression = $expressionProcessor->processExpression();            
275            $expectedPHPExpression = 'is_null(trim(\'  ODataPHP Producer   \'))';
276            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
277            
278            $odataUriExpression = 'substring(\'Red_Black_Tree\', 3) ne \'Black_Tree\'';
279            $parser->resetParser($odataUriExpression);
280            $expressionProcessor->setExpression($parser->parseFilter());
281            $actualPHPExpression = $expressionProcessor->processExpression();           
282            $expectedPHPExpression = '(strcmp(substr(\'Red_Black_Tree\', 3), \'Black_Tree\') != 0)';
283            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
284            
285            $odataUriExpression = 'substring(\'Red_Black_Tree\', 3, 5) ne \'Black\'';
286            $parser->resetParser($odataUriExpression);
287            $expressionProcessor->setExpression($parser->parseFilter());
288            $actualPHPExpression = $expressionProcessor->processExpression();           
289            $expectedPHPExpression = '(strcmp(substr(\'Red_Black_Tree\', 3, 5), \'Black\') != 0)';
290            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
291            
292            $odataUriExpression = 'substringof(CustomerID, \'MRR\')';
293            $parser->resetParser($odataUriExpression);
294            $expressionProcessor->setExpression($parser->parseFilter());
295            $actualPHPExpression = $expressionProcessor->processExpression();
296            $expectedPHPExpression = '(!(is_null($lt->CustomerID)) && (strpos(\'MRR\', $lt->CustomerID) !== false))'; 
297            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
298            
299            $odataUriExpression = 'length(\'Red_Black_Tree\') eq 8';
300            $parser->resetParser($odataUriExpression);
301            $expressionProcessor->setExpression($parser->parseFilter());
302            $actualPHPExpression = $expressionProcessor->processExpression();            
303            $expectedPHPExpression = '(strlen(\'Red_Black_Tree\') == 8)'; 
304            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
305            
306             
307        } catch (ODataException $exception) {
308            $this->fail('An unexpected ODataException has been raised.' . $exception->getMessage());
309        }
310    }
311    
312    /**     
313     * Test the possible datetime operators defined for filter option 
314     */
315    public function testDateTimeFunctions()
316    {
317        try {            
318            $odataUriExpression = 'OrderDate eq datetime\'2010-12-08\'';
319            $parser = new ExpressionParser2($odataUriExpression,
320                            $this->_northWindMetadata->resolveResourceSet('Orders')->getResourceType(),
321            		        null);
322            $expressionTree = $parser->parseFilter();
323            $expressionProcessor = new ExpressionProcessor($expressionTree, new PHPExpressionProvider('$lt'));
324            $actualPHPExpression = $expressionProcessor->processExpression();            
325            $expectedPHPExpression = '(!(is_null($lt->OrderDate)) && (ODataProducer\Providers\Metadata\Type\DateTime::dateTimeCmp($lt->OrderDate, \'2010-12-08\') == 0))';            
326            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
327            
328            $odataUriExpression = 'OrderDate gt DeliveryDate';
329            $parser->resetParser($odataUriExpression);
330            $expressionProcessor->setExpression($parser->parseFilter());
331            $actualPHPExpression = $expressionProcessor->processExpression();
332            $expectedPHPExpression = '((!(is_null($lt->OrderDate)) && !(is_null($lt->DeliveryDate))) && (ODataProducer\Providers\Metadata\Type\DateTime::dateTimeCmp($lt->OrderDate, $lt->DeliveryDate) > 0))';
333            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
334            
335            $odataUriExpression = 'OrderDate eq null';
336            $parser->resetParser($odataUriExpression);
337            $expressionProcessor->setExpression($parser->parseFilter());
338            $actualPHPExpression = $expressionProcessor->processExpression();
339            $expectedPHPExpression = 'is_null($lt->OrderDate)';
340            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
341            
342            $odataUriExpression = 'OrderDate eq null eq true';
343            $parser->resetParser($odataUriExpression);
344            $expressionProcessor->setExpression($parser->parseFilter());
345            $actualPHPExpression = $expressionProcessor->processExpression();            
346            $expectedPHPExpression = '(is_null($lt->OrderDate) == true)';
347            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
348            
349            $odataUriExpression = 'year(OrderDate) eq 2010';
350            $parser->resetParser($odataUriExpression);
351            $expressionProcessor->setExpression($parser->parseFilter());
352            $actualPHPExpression = $expressionProcessor->processExpression();
353            $expectedPHPExpression = '(!(is_null($lt->OrderDate)) && (ODataProducer\Providers\Metadata\Type\DateTime::year($lt->OrderDate) == 2010))';
354            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
355            
356            $odataUriExpression = 'month(OrderDate) eq month(DeliveryDate)';
357            $parser->resetParser($odataUriExpression);
358            $expressionProcessor->setExpression($parser->parseFilter());
359            $actualPHPExpression = $expressionProcessor->processExpression();
360            $expectedPHPExpression = '((!(is_null($lt->OrderDate)) && !(is_null($lt->DeliveryDate))) && (ODataProducer\Providers\Metadata\Type\DateTime::month($lt->OrderDate) == ODataProducer\Providers\Metadata\Type\DateTime::month($lt->DeliveryDate)))';
361            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
362            
363            $odataUriExpression = 'month(OrderDate) eq 12 and day(OrderDate) eq 22';
364            $parser->resetParser($odataUriExpression);
365            $expressionProcessor->setExpression($parser->parseFilter());
366            $actualPHPExpression = $expressionProcessor->processExpression();
367            $expectedPHPExpression = '(!(is_null($lt->OrderDate)) && ((ODataProducer\Providers\Metadata\Type\DateTime::month($lt->OrderDate) == 12) && (ODataProducer\Providers\Metadata\Type\DateTime::day($lt->OrderDate) == 22)))';            
368            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
369            
370        } catch (ODataException $exception) {
371            $this->fail('An unexpected ODataException has been raised.' . $exception->getMessage());
372        }
373    }
374    
375    /**     
376     * Test guid opertor (guid comparison)
377     */
378    public function testGuidFunctions()
379    {
380        try {            
381            $odataUriExpression = 'Customer/CustomerGuid eq guid\'05b242e752eb46bd8f0e6568b72cd9a5\'';
382            $parser = new ExpressionParser2($odataUriExpression,
383                            $this->_northWindMetadata->resolveResourceSet('Orders')->getResourceType(),
384            		        null);
385            $expressionTree = $parser->parseFilter();
386            $expressionProcessor = new ExpressionProcessor($expressionTree, new PHPExpressionProvider('$lt'));
387            $actualPHPExpression = $expressionProcessor->processExpression();
388            $expectedPHPExpression = '((!(is_null($lt->Customer)) && !(is_null($lt->Customer->CustomerGuid))) && (ODataProducer\Providers\Metadata\Type\Guid::guidEqual($lt->Customer->CustomerGuid, \'05b242e752eb46bd8f0e6568b72cd9a5\') == true))';           
389            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
390        } catch (ODataException $exception) {
391            $this->fail('An unexpected ODataException has been raised.' . $exception->getMessage());
392        }
393    }
394    
395    /**     
396     * Test the possilbe math functions defined for filter option
397     */
398    public function testMathFunctions()
399    {
400        try {            
401            $odataUriExpression = 'round(Price) eq 200.60';
402            $parser = new ExpressionParser2($odataUriExpression,
403                            $this->_northWindMetadata->resolveResourceSet('Orders')->getResourceType(),
404            		        null);
405            $expressionTree = $parser->parseFilter();
406            $expressionProcessor = new ExpressionProcessor($expressionTree, new PHPExpressionProvider('$lt'));
407            $actualPHPExpression = $expressionProcessor->processExpression();            
408            $expectedPHPExpression = '(!(is_null($lt->Price)) && (round($lt->Price) == 200.60))';           
409            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
410            
411            $odataUriExpression = 'ceiling(floor(Price) add 5) eq 345.90';
412            $parser->resetParser($odataUriExpression);
413            $expressionProcessor->setExpression($parser->parseFilter());
414            $actualPHPExpression = $expressionProcessor->processExpression();            
415            $expectedPHPExpression = '(!(is_null($lt->Price)) && (ceil((floor($lt->Price) + 5)) == 345.90))';            
416            $this->AssertEquals($actualPHPExpression, $expectedPHPExpression);
417            
418        } catch (ODataException $exception) {
419            $this->fail('An unexpected ODataException has been raised.' . $exception->getMessage());
420        }
421    }
422    
423    /**     
424     * Test expression provider using real data
425     */
426    public function testAnonymousFunction()
427    {
428        try {
429            //Creates test data
430            $data = $this->createTestData();
431            //Query for Customers with 'L' as second letter of CustomerID
432            $result = $this->executeExpression('indexof(CustomerID, \'L\') eq 1', 
433                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
434                                                $data['Customers']);
435            $this->AssertEquals(count($result), 1);
436            $this->AssertEquals($result[0]->CustomerID, 'ALFKI');
437            
438            //Query for Customers with country as Germany
439            $result = $this->executeExpression('Country eq \'Germany\'', 
440                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
441                                                $data['Customers']);
442            $this->AssertEquals(count($result), 2);
443            $this->AssertEquals($result[0]->Country, 'Germany');
444            $this->AssertEquals($result[1]->Country, 'Germany');
445            
446            //Query for Customers with no address
447            $result = $this->executeExpression('Address eq null', 
448                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
449                                                $data['Customers']);
450            $this->AssertEquals(count($result), 1);
451            $this->AssertEquals($result[0]->CustomerGuid, '15b242e7-52eb-46bd-8f0e-6568b72cd9a6');
452            
453            //Query for Customers with non-primary address
454            $result = $this->executeExpression('Address/Address2/IsPrimary eq false', 
455                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
456                                                $data['Customers']);
457            $this->AssertEquals(count($result), 1);
458            $this->AssertEquals($result[0]->CustomerName, 'Ann Devon');
459            
460            //Query for Customers with ID 'ALFKI' or 'EASTC'
461            $result = $this->executeExpression('CustomerID eq \'ALFKI\' or CustomerID eq \'EASTC\'', 
462                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
463                                                $data['Customers']);
464            $this->AssertEquals(count($result), 2);
465            $this->AssertEquals($result[0]->CustomerID, 'ALFKI');
466            $this->AssertEquals($result[1]->CustomerID, 'EASTC');
467
468            //Query for Customers with an expression which evaluates to false
469            $result = $this->executeExpression('1 add 2 eq 5', 
470                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
471                                                $data['Customers']);
472            $this->AssertEquals(count($result), 0);
473            
474            //Query for all Orders
475            $result = $this->executeExpression('true', 
476                                                $this->_northWindMetadata->resolveResourceSet('Orders')->getResourceType(), 
477                                                $data['Orders']);
478            $this->AssertEquals(count($result), 5);
479            
480            //Query for Order with ShipName as 'Speedy Express'
481            $result = $this->executeExpression('ShipName eq \'Speedy Express\'',
482                                                $this->_northWindMetadata->resolveResourceSet('Orders')->getResourceType(), 
483                                                $data['Orders']);
484            $this->AssertEquals(count($result), 2);
485            foreach($result as $order) {
486                $this->AssertEquals($order->ShipName, 'Speedy Express');
487            }
488            
489            //Query for Order with CustomerID as 'DUMON'
490            $result = $this->executeExpression('Customer/CustomerID eq \'DUMON\'',
491                                                $this->_northWindMetadata->resolveResourceSet('Orders')->getResourceType(), 
492                                                $data['Orders']);
493            $this->AssertEquals(count($result), 3);
494            
495            //Query for Orders with year of order as 1999 or 1995
496            $result = $this->executeExpression('year(OrderDate) eq 1999 or year(OrderDate) add 4 eq 1999',
497                                                $this->_northWindMetadata->resolveResourceSet('Orders')->getResourceType(), 
498                                                $data['Orders']);
499            foreach($result as $order) {
500                $this->assertContains($order->OrderDate, array(1999, 1995));
501            }
502            
503            //Query for Orders with date greater than 2000-11-11
504            $result = $this->executeExpression('OrderDate ge datetime\'2000-11-11\'',
505                                                $this->_northWindMetadata->resolveResourceSet('Orders')->getResourceType(), 
506                                                $data['Orders']);
507            foreach($result as $order) {                
508                $this->assertGreaterThanOrEqual(0, ODataProducer\Providers\Metadata\Type\DateTime::dateTimeCmp($order->OrderDate, '2000-11-11'));
509            }
510            
511            //Query for Customer using different flavours of guid
512            $result = $this->executeExpression('CustomerGuid eq guid\'15b242e7-52eb-46bd-8f0e-6568b72cd9a6\'', 
513                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
514                                                $data['Customers']); 
515            $this->AssertEquals(count($result), 1);
516            $customer1 = $result[0];
517            
518            $result = $this->executeExpression('CustomerGuid eq guid\'{15b242e7-52eb-46bd-8f0e-6568b72cd9a6}\'', 
519                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
520                                                $data['Customers']); 
521            $this->AssertEquals(count($result), 1);
522            $customer2 = $result[0];
523            
524            $result = $this->executeExpression('CustomerGuid eq guid\'(15b242e7-52eb-46bd-8f0e-6568b72cd9a6)\'', 
525                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
526                                                $data['Customers']); 
527            $this->AssertEquals(count($result), 1);
528            $customer3 = $result[0];
529            
530            $result = $this->executeExpression('CustomerGuid eq guid\'15b242e752eb46bd8f0e6568b72cd9a6\'', 
531                                                $this->_northWindMetadata->resolveResourceSet('Customers')->getResourceType(), 
532                                                $data['Customers']); 
533            $this->AssertEquals(count($result), 1);
534            $customer4 = $result[0];
535            $this->AssertEquals($customer1->CustomerID, $customer2->CustomerID);
536            $this->AssertEquals($customer3->CustomerID, $customer4->CustomerID);
537            $this->AssertEquals($customer1->CustomerID, $customer4->CustomerID);
538            
539        } catch (ODataException $exception) {
540            $this->fail('An unexpected ODataException has been raised(' . $exception->getMessage() .')');
541        }
542    }
543    
544    /**
545     * Parse the astoria filter expression, generate the same expression as PHP expression,
546     * retrieve only the entries which satisifes this expression.
547     * 
548     * @param string         $astoriaFilter
549     * @param ResourceType    $resourceType
550     * @param array<objects> $entries
551     * 
552     * @return array<objects>
553     */
554    private function executeExpression($astoriaFilter, $resourceType, $entries)
555    {
556        try {
557            //Parse the Astoria filter query option to expression tree
558            $parser = new ExpressionParser2($astoriaFilter, $resourceType, null);
559            $expressionTree = $parser->parseFilter();
560            //emit the PHP expression corrosponds to Astoria filter query
561            $expressionProcessor = new ExpressionProcessor($expressionTree, new PHPExpressionProvider('$lt'));
562            $phpExpression = $expressionProcessor->processExpression();
563            //create an anonymous function with the generated PHP expression in if condition
564            $fun = create_function('$lt', 'if(' . $phpExpression . ') { return true; } else { return false;}');
565            $result = array();
566            foreach($entries as $lt) {
567                //Filter out only the entries which satisifies the condition
568                if($fun($lt)) {
569                   $result[] = $lt;
570                }
571            }
572
573            return $result;
574            
575        } catch (ODataException $exception) {
576            $this->fail('An unexpected ODataException has been raised.' . $exception->getMessage());
577        }
578    }
579    
580    /**
581     * Prepare test data.
582     * 
583     * @return array<key, array<objects>>
584     */
585    private function createTestData()
586    {
587        $customers = array();
588        $orders = array();
589
590        $customer = $this->createCustomer('ALFKI', 
591                        '05b242e7-52eb-46bd-8f0e-6568b72cd9a5', 
592                    	'Alfreds Futterkiste', 
593                        $this->createAddress('AF34', 12, 15, 'Obere Str. 57', true, true), 
594                		'Germany', 1);
595        $customers[] = $customer;                
596        $order = $this->createOrder(123, '2000-12-12', '2000-12-12', 'Speedy Express', 23, 4, 100.44);
597        $orders[] = $order;
598        $this->setCustomerOrder($customer, $order);
599        $this->setOrderCustomer($order, $customer);
600        $order = $this->createOrder(124, '1990-07-12', '1990-10-12', 'United Package', 100, 3, 200.44);
601        $orders[] = $order;
602        $this->setCustomerOrder($customer, $order);
603        $this->setOrderCustomer($order, $customer);
604
605        $customer = $this->createCustomer('DUMON', 
606                        '15b242e7-52eb-46bd-8f0e-6568b72cd9a6', 
607                    	'Janine Labrune', 
608                        null, //Address is null
609                		'France', 4);
610        $customers[] = $customer;                
611        $order = $this->createOrder(125, '1995-05-05', '1995-05-09', 'Federal Shipping', 100, 1, 800);
612        $orders[] = $order;
613        $this->setCustomerOrder($customer, $order);
614        $this->setOrderCustomer($order, $customer);
615        $order = $this->createOrder(126, '1999-07-16', '1999-08-20', 'Speedy Express', 80, 2, 150);
616        $orders[] = $order;
617        $this->setCustomerOrder($customer, $order);
618        $this->setOrderCustomer($order, $customer);
619        $order = $this->createOrder(127, '2008-08-16', '2009-08-22', 'United Package', 88, 6, 50);
620        $orders[] = $order;
621        $this->setCustomerOrder($customer, $order);
622        $this->setOrderCustomer($order, $customer);
623
624
625        $customer = $this->createCustomer('EASTC', 
626                            '15b242e7-52eb-46bd-8f0e-6568b72cd9a7', 
627                        	'Ann Devon', 
628                            $this->createAddress('FF45', 15, 16, '35 King George', true, false), 
629                        	'Germany', 3);
630        $customers[] = $customer;                
631        return array('Customers' => $customers, 'Orders' => $orders);
632    }
633
634    private function createAddress($houseNumber, $lineNumber, $lineNumber2, $streetName, $isValid, $isPrimary)
635    {
636        $address = new Address4();
637        $address->Address2 = new Address2();
638        $address->Address2->IsPrimary = $isPrimary;
639        $address->HouseNumber = $houseNumber;
640        $address->IsValid = $isValid;
641        $address->LineNumber = $lineNumber;
642        $address->LineNumber2 = $lineNumber2;
643        $address->StreetName = $streetName;
644        return $address;
645    }
646
647    private function createCustomer($customerID, $customerGuid, $customerName, $address, $country, $rating)
648    {
649        $customer = new Customer2();
650        $customer->CustomerID = $customerID;
651        $customer->CustomerGuid = $customerGuid;
652        $customer->CustomerName = $customerName;
653        $customer->Address = $address;
654        $customer->Country = $country;
655        $customer->Rating = $rating;
656        $customer->Orders = null;
657        return $customer;
658    }
659
660    private function createOrder($orderID, $orderDate, $deliveryDate, $shipName, $itemCount, $qualityRate, $price)
661    {
662        $order = new Order2();
663        $order->Customer = null;
664        $order->DeliveryDate = $deliveryDate;
665        $order->ItemCount = $itemCount;
666        $order->OrderDate = $orderDate;
667        $order->ShipName = $shipName;
668        $order->QualityRate = $qualityRate;
669        $order->Price = $price;
670        return $order;
671    }
672
673    private function setCustomerOrder($customer, $order)
674    {
675        if (is_null($customer->Orders)) {
676            $customer->Orders = array();
677        }
678    
679        $customer->Orders[] = $order;
680    }
681
682
683    private function setOrderCustomer($order, $customer)
684    {    
685        $order->Customer = $customer;
686    }
687    
688    protected function tearDown()
689    {
690    }
691}
692?>