3  * SPDX-License-Identifier: GPL-2.0-only
 
   5  * This file is part of Nominatim. (https://nominatim.org)
 
   7  * Copyright (C) 2022 by the Nominatim developer community.
 
   8  * For a full list of authors see the git log.
 
  13 require_once(CONST_LibDir.'/lib.php');
 
  14 require_once(CONST_LibDir.'/DB.php');
 
  16 // subclassing so we can set the protected connection variable
 
  17 class NominatimSubClassedDB extends \Nominatim\DB
 
  19     public function setConnection($oConnection)
 
  21         $this->connection = $oConnection;
 
  25 // phpcs:ignore PSR1.Classes.ClassDeclaration.MultipleClasses
 
  26 class DBTest extends \PHPUnit\Framework\TestCase
 
  28     public function testReusingConnection()
 
  30         $oDB = new NominatimSubClassedDB('');
 
  31         $oDB->setConnection('anything');
 
  32         $this->assertTrue($oDB->connect());
 
  35     public function testCheckConnection()
 
  37         $oDB = new \Nominatim\DB('');
 
  38         $this->assertFalse($oDB->checkConnection());
 
  41     public function testErrorHandling()
 
  43         $this->expectException(DatabaseError::class);
 
  44         $this->expectExceptionMessage('Failed to establish database connection');
 
  46         $oDB = new \Nominatim\DB('pgsql:dbname=abc');
 
  50     public function testErrorHandling2()
 
  52         $this->expectException(DatabaseError::class);
 
  53         $this->expectExceptionMessage('Database query failed');
 
  55         $oPDOStub = $this->getMockBuilder(PDO::class)
 
  56                          ->setMethods(array('query', 'quote'))
 
  59         $oPDOStub->method('query')
 
  60                  ->will($this->returnCallback(function ($sVal) {
 
  64         $oPDOStub->method('query')
 
  65                  ->will($this->returnCallback(function () {
 
  66                      throw new \PDOException('ERROR:  syntax error at or near "FROM"');
 
  69         $oDB = new NominatimSubClassedDB('');
 
  70         $oDB->setConnection($oPDOStub);
 
  71         $oDB->getOne('SELECT name FROM');
 
  74     public function testGetPostgresVersion()
 
  76         $oDBStub = $this->getMockBuilder(\Nominatim\DB::class)
 
  77                         ->disableOriginalConstructor()
 
  78                         ->setMethods(array('getOne'))
 
  81         $oDBStub->method('getOne')
 
  82                 ->willReturn('100006');
 
  84         $this->assertEquals(10, $oDBStub->getPostgresVersion());
 
  87     public function testGetPostgisVersion()
 
  89         $oDBStub = $this->getMockBuilder(\Nominatim\DB::class)
 
  90                         ->disableOriginalConstructor()
 
  91                         ->setMethods(array('getOne'))
 
  94         $oDBStub->method('getOne')
 
  95                 ->willReturn('2.4.4');
 
  97         $this->assertEquals(2.4, $oDBStub->getPostgisVersion());
 
 100     public function testParseDSN()
 
 104             \Nominatim\DB::parseDSN('')
 
 109              'hostspec' => 'machine1'
 
 111             \Nominatim\DB::parseDSN('pgsql:dbname=db1;host=machine1')
 
 116              'hostspec' => 'machine1',
 
 118              'username' => 'john',
 
 119              'password' => 'secret'
 
 121             \Nominatim\DB::parseDSN('pgsql:dbname=db1;host=machine1;port=1234;user=john;password=secret')
 
 125     public function testGenerateDSN()
 
 129             \Nominatim\DB::generateDSN(array())
 
 132             'pgsql:host=machine1;dbname=db1',
 
 133             \Nominatim\DB::generateDSN(\Nominatim\DB::parseDSN('pgsql:host=machine1;dbname=db1'))
 
 137     public function testAgainstDatabase()
 
 139         $unit_test_dsn = getenv('UNIT_TEST_DSN') != false ?
 
 140                             getenv('UNIT_TEST_DSN') :
 
 141                             'pgsql:dbname=nominatim_unit_tests';
 
 143         ## Create the database.
 
 145             $aDSNParsed = \Nominatim\DB::parseDSN($unit_test_dsn);
 
 146             $sDbname = $aDSNParsed['database'];
 
 147             $aDSNParsed['database'] = 'postgres';
 
 149             $oDB = new \Nominatim\DB(\Nominatim\DB::generateDSN($aDSNParsed));
 
 151             $oDB->exec('DROP DATABASE IF EXISTS ' . $sDbname);
 
 152             $oDB->exec('CREATE DATABASE ' . $sDbname);
 
 155         $oDB = new \Nominatim\DB($unit_test_dsn);
 
 159             $oDB->checkConnection($sDbname)
 
 164             $oDB->exec('CREATE TABLE table1 (id integer, city varchar, country varchar)');
 
 166             $this->assertTrue($oDB->tableExists('table1'));
 
 167             $this->assertFalse($oDB->tableExists('table99'));
 
 168             $this->assertFalse($oDB->tableExists(null));
 
 174                 "INSERT INTO table1 VALUES (1, 'Berlin', 'Germany'), (2, 'Paris', 'France')"
 
 179                     array('city' => 'Berlin'),
 
 180                     array('city' => 'Paris')
 
 182                 $oDB->getAll('SELECT city FROM table1')
 
 186                 $oDB->getAll('SELECT city FROM table1 WHERE id=999')
 
 191                 array('id' => 1, 'city' => 'Berlin', 'country' => 'Germany'),
 
 192                 $oDB->getRow('SELECT * FROM table1 WHERE id=1')
 
 196                 $oDB->getRow('SELECT * FROM table1 WHERE id=999')
 
 201                 array('Berlin', 'Paris'),
 
 202                 $oDB->getCol('SELECT city FROM table1')
 
 206                 $oDB->getCol('SELECT city FROM table1 WHERE id=999')
 
 211                 $oDB->getOne('SELECT city FROM table1 WHERE id=1')
 
 215                 $oDB->getOne('SELECT city FROM table1 WHERE id=999')
 
 219                 array('Berlin' => 'Germany', 'Paris' => 'France'),
 
 220                 $oDB->getAssoc('SELECT city, country FROM table1')
 
 224                 $oDB->getAssoc('SELECT city, country FROM table1 WHERE id=999')