]> git.openstreetmap.org Git - nominatim.git/blob - test/php/Nominatim/DBTest.php
improve typing for @compiles constructs
[nominatim.git] / test / php / Nominatim / DBTest.php
1 <?php
2 /**
3  * SPDX-License-Identifier: GPL-2.0-only
4  *
5  * This file is part of Nominatim. (https://nominatim.org)
6  *
7  * Copyright (C) 2022 by the Nominatim developer community.
8  * For a full list of authors see the git log.
9  */
10
11 namespace Nominatim;
12
13 require_once(CONST_LibDir.'/lib.php');
14 require_once(CONST_LibDir.'/DB.php');
15
16 // subclassing so we can set the protected connection variable
17 class NominatimSubClassedDB extends \Nominatim\DB
18 {
19     public function setConnection($oConnection)
20     {
21         $this->connection = $oConnection;
22     }
23 }
24
25 // phpcs:ignore PSR1.Classes.ClassDeclaration.MultipleClasses
26 class DBTest extends \PHPUnit\Framework\TestCase
27 {
28     public function testReusingConnection()
29     {
30         $oDB = new NominatimSubClassedDB('');
31         $oDB->setConnection('anything');
32         $this->assertTrue($oDB->connect());
33     }
34
35     public function testCheckConnection()
36     {
37         $oDB = new \Nominatim\DB('');
38         $this->assertFalse($oDB->checkConnection());
39     }
40
41     public function testErrorHandling()
42     {
43         $this->expectException(DatabaseError::class);
44         $this->expectExceptionMessage('Failed to establish database connection');
45
46         $oDB = new \Nominatim\DB('pgsql:dbname=abc');
47         $oDB->connect();
48     }
49
50     public function testErrorHandling2()
51     {
52         $this->expectException(DatabaseError::class);
53         $this->expectExceptionMessage('Database query failed');
54
55         $oPDOStub = $this->getMockBuilder(PDO::class)
56                          ->setMethods(array('query', 'quote'))
57                          ->getMock();
58
59         $oPDOStub->method('query')
60                  ->will($this->returnCallback(function ($sVal) {
61                     return "'$sVal'";
62                  }));
63
64         $oPDOStub->method('query')
65                  ->will($this->returnCallback(function () {
66                      throw new \PDOException('ERROR:  syntax error at or near "FROM"');
67                  }));
68
69         $oDB = new NominatimSubClassedDB('');
70         $oDB->setConnection($oPDOStub);
71         $oDB->getOne('SELECT name FROM');
72     }
73
74     public function testGetPostgresVersion()
75     {
76         $oDBStub = $this->getMockBuilder(\Nominatim\DB::class)
77                         ->disableOriginalConstructor()
78                         ->setMethods(array('getOne'))
79                         ->getMock();
80
81         $oDBStub->method('getOne')
82                 ->willReturn('100006');
83
84         $this->assertEquals(10, $oDBStub->getPostgresVersion());
85     }
86
87     public function testGetPostgisVersion()
88     {
89         $oDBStub = $this->getMockBuilder(\Nominatim\DB::class)
90                         ->disableOriginalConstructor()
91                         ->setMethods(array('getOne'))
92                         ->getMock();
93
94         $oDBStub->method('getOne')
95                 ->willReturn('2.4.4');
96
97         $this->assertEquals(2.4, $oDBStub->getPostgisVersion());
98     }
99
100     public function testParseDSN()
101     {
102         $this->assertEquals(
103             array(),
104             \Nominatim\DB::parseDSN('')
105         );
106         $this->assertEquals(
107             array(
108              'database' => 'db1',
109              'hostspec' => 'machine1'
110             ),
111             \Nominatim\DB::parseDSN('pgsql:dbname=db1;host=machine1')
112         );
113         $this->assertEquals(
114             array(
115              'database' => 'db1',
116              'hostspec' => 'machine1',
117              'port' => '1234',
118              'username' => 'john',
119              'password' => 'secret'
120             ),
121             \Nominatim\DB::parseDSN('pgsql:dbname=db1;host=machine1;port=1234;user=john;password=secret')
122         );
123     }
124
125     public function testGenerateDSN()
126     {
127         $this->assertEquals(
128             'pgsql:',
129             \Nominatim\DB::generateDSN(array())
130         );
131         $this->assertEquals(
132             'pgsql:host=machine1;dbname=db1',
133             \Nominatim\DB::generateDSN(\Nominatim\DB::parseDSN('pgsql:host=machine1;dbname=db1'))
134         );
135     }
136
137     public function testAgainstDatabase()
138     {
139         $unit_test_dsn = getenv('UNIT_TEST_DSN') != false ?
140                             getenv('UNIT_TEST_DSN') :
141                             'pgsql:dbname=nominatim_unit_tests';
142
143         ## Create the database.
144         {
145             $aDSNParsed = \Nominatim\DB::parseDSN($unit_test_dsn);
146             $sDbname = $aDSNParsed['database'];
147             $aDSNParsed['database'] = 'postgres';
148
149             $oDB = new \Nominatim\DB(\Nominatim\DB::generateDSN($aDSNParsed));
150             $oDB->connect();
151             $oDB->exec('DROP DATABASE IF EXISTS ' . $sDbname);
152             $oDB->exec('CREATE DATABASE ' . $sDbname);
153         }
154
155         $oDB = new \Nominatim\DB($unit_test_dsn);
156         $oDB->connect();
157
158         $this->assertTrue(
159             $oDB->checkConnection($sDbname)
160         );
161
162         # Tables, Indices
163         {
164             $oDB->exec('CREATE TABLE table1 (id integer, city varchar, country varchar)');
165
166             $this->assertTrue($oDB->tableExists('table1'));
167             $this->assertFalse($oDB->tableExists('table99'));
168             $this->assertFalse($oDB->tableExists(null));
169         }
170
171         # select queries
172         {
173             $oDB->exec(
174                 "INSERT INTO table1 VALUES (1, 'Berlin', 'Germany'), (2, 'Paris', 'France')"
175             );
176
177             $this->assertEquals(
178                 array(
179                     array('city' => 'Berlin'),
180                     array('city' => 'Paris')
181                 ),
182                 $oDB->getAll('SELECT city FROM table1')
183             );
184             $this->assertEquals(
185                 array(),
186                 $oDB->getAll('SELECT city FROM table1 WHERE id=999')
187             );
188
189
190             $this->assertEquals(
191                 array('id' => 1, 'city' => 'Berlin', 'country' => 'Germany'),
192                 $oDB->getRow('SELECT * FROM table1 WHERE id=1')
193             );
194             $this->assertEquals(
195                 false,
196                 $oDB->getRow('SELECT * FROM table1 WHERE id=999')
197             );
198
199
200             $this->assertEquals(
201                 array('Berlin', 'Paris'),
202                 $oDB->getCol('SELECT city FROM table1')
203             );
204             $this->assertEquals(
205                 array(),
206                 $oDB->getCol('SELECT city FROM table1 WHERE id=999')
207             );
208
209             $this->assertEquals(
210                 'Berlin',
211                 $oDB->getOne('SELECT city FROM table1 WHERE id=1')
212             );
213             $this->assertEquals(
214                 null,
215                 $oDB->getOne('SELECT city FROM table1 WHERE id=999')
216             );
217
218             $this->assertEquals(
219                 array('Berlin' => 'Germany', 'Paris' => 'France'),
220                 $oDB->getAssoc('SELECT city, country FROM table1')
221             );
222             $this->assertEquals(
223                 array(),
224                 $oDB->getAssoc('SELECT city, country FROM table1 WHERE id=999')
225             );
226         }
227     }
228 }