<?php
// DbBackendsTest.php
// Created: 2021-04-28
// Updated: 2025-01-18

declare(strict_types=1);

use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Attributes\{CoversClass,UsesClass};
use Index\Db\DbBackends;
use Index\Db\MariaDb\MariaDbBackend;
use Index\Db\NullDb\NullDbConnection;
use Index\Db\Sqlite\SqliteBackend;

#[CoversClass(DbBackends::class)]
#[CoversClass(NullDbConnection::class)]
#[CoversClass(MariaDbBackend::class)]
#[CoversClass(SqliteBackend::class)]
final class DbBackendsTest extends TestCase {
    public function testDSN(): void {
        $nullDbConn1 = DbBackends::create('null:');
        $this->assertInstanceOf(NullDbConnection::class, $nullDbConn1);

        $maria = new MariaDbBackend;
        $sqlite = new SqliteBackend;

        // flashii style misuzu connections details
        $mci1 = $maria->parseDsn('mariadb://flashii:TiFGzCTxzx0n2HYzmNZpa98j255X7W4B@:unix:/flashii/misuzu?socket=/var/run/mysqld/mysqld.sock&charset=utf8mb4&init=SET SESSION time_zone = \'+00:00\', sql_mode = \'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\'');

        $this->assertTrue($mci1->unixSocket);
        $this->assertEquals('/var/run/mysqld/mysqld.sock', (string)$mci1->endPoint);
        $this->assertEquals('', $mci1->host);
        $this->assertEquals(-1, $mci1->port);
        $this->assertEquals('/var/run/mysqld/mysqld.sock', $mci1->unixSocketPath);
        $this->assertEquals('flashii', $mci1->userName);
        $this->assertEquals('TiFGzCTxzx0n2HYzmNZpa98j255X7W4B', $mci1->password);
        $this->assertEquals('flashii_misuzu', $mci1->dbName);
        $this->assertEquals('utf8mb4', $mci1->charSet);
        $this->assertEquals('SET SESSION time_zone = \'+00:00\', sql_mode = \'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\'', $mci1->initCommand);
        $this->assertNull($mci1->keyPath);
        $this->assertNull($mci1->certPath);
        $this->assertNull($mci1->certAuthPath);
        $this->assertNull($mci1->trustedCertsPath);
        $this->assertNull($mci1->cipherAlgos);
        $this->assertTrue($mci1->verifyCert);
        $this->assertFalse($mci1->useCompression);

        // generic ipv4
        $mci2 = $maria->parseDsn('mariadb://username:password@127.0.0.1/database');
        $this->assertEquals('127.0.0.1', (string)$mci2->endPoint);
        $this->assertEquals('127.0.0.1', $mci2->host);
        $this->assertEquals(3306, $mci2->port);
        $this->assertEquals('', $mci2->unixSocketPath);
        $this->assertEquals('username', $mci2->userName);
        $this->assertEquals('password', $mci2->password);
        $this->assertEquals('database', $mci2->dbName);
        $this->assertNull($mci2->charSet);
        $this->assertNull($mci2->charSet);
        $this->assertNull($mci2->keyPath);
        $this->assertNull($mci2->certPath);
        $this->assertNull($mci2->certAuthPath);
        $this->assertNull($mci2->trustedCertsPath);
        $this->assertNull($mci2->cipherAlgos);
        $this->assertTrue($mci2->verifyCert);
        $this->assertFalse($mci2->useCompression);

        // generic ipv6 with port
        $mci3 = $maria->parseDsn('mysql://username:password@[::1]:9001/database');
        $this->assertEquals('[::1]:9001', (string)$mci3->endPoint);
        $this->assertEquals('::1', $mci3->host);
        $this->assertEquals(9001, $mci3->port);
        $this->assertEquals('', $mci3->unixSocketPath);
        $this->assertEquals('username', $mci3->userName);
        $this->assertEquals('password', $mci3->password);
        $this->assertEquals('database', $mci3->dbName);
        $this->assertNull($mci3->charSet);
        $this->assertNull($mci3->initCommand);
        $this->assertNull($mci3->keyPath);
        $this->assertNull($mci3->certPath);
        $this->assertNull($mci3->certAuthPath);
        $this->assertNull($mci3->trustedCertsPath);
        $this->assertNull($mci3->cipherAlgos);
        $this->assertTrue($mci3->verifyCert);
        $this->assertFalse($mci3->useCompression);

        // sqlite normal
        $sql1 = $sqlite->parseDsn('sqlite:/path/to/database.db?key=ebwOKzGkLYIxDGXk&openOnly');
        $this->assertEquals('/path/to/database.db', $sql1->fileName);
        $this->assertEquals('ebwOKzGkLYIxDGXk', $sql1->encryptionKey);
        $this->assertFalse($sql1->readOnly);
        $this->assertFalse($sql1->create);

        // sqlite temp file
        $sql1 = $sqlite->parseDsn('sqlite:?key=Y63vrCttK8bEdPUIXVCOiLQKIgdbUn8V&readOnly');
        $this->assertEquals('', $sql1->fileName);
        $this->assertEquals('Y63vrCttK8bEdPUIXVCOiLQKIgdbUn8V', $sql1->encryptionKey);
        $this->assertTrue($sql1->readOnly);
        $this->assertTrue($sql1->create);

        // sqlite memory
        $sql1 = $sqlite->parseDsn('sqlite::memory:');
        $this->assertEquals(':memory:', $sql1->fileName);
        $this->assertEquals('', $sql1->encryptionKey);
        $this->assertFalse($sql1->readOnly);
        $this->assertTrue($sql1->create);
    }
}