<?php declare(strict_types=1);
/**
 * Banker
 *
 * A Caching library implementing psr/cache (PSR 6) and psr/simple-cache (PSR 16)
 *
 * PHP version 8+
 *
 * @package     Banker
 * @author      Timothy J. Warren <tim@timshomepage.net>
 * @copyright   2016 - 2021  Timothy J. Warren
 * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
 * @version     5.0.0
 * @link        https://git.timshomepage.net/timw4mail/banker
 */
namespace Aviat\Banker\Tests\Driver;

use Aviat\Banker\Driver\DriverInterface;
use Aviat\Banker\Exception\InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use TypeError;

class DriverTestBase extends TestCase {

	protected DriverInterface $driver;

	public function testGetSet(): void
	{
		$this->driver->set('foo', 'bar');
		$this->assertTrue($this->driver->exists('foo'));
		$this->assertEquals('bar', $this->driver->get('foo'));

		$bar = [
			'foo' => [
				'apple' => 'orange'
			],
			'bar' => 'baz'
		];

		$this->assertTrue($this->driver->set('bar', $bar));
		$this->assertEquals($bar, $this->driver->get('bar'));
	}

	public function testGetMultipleOnBadKey(): void
	{
		$actual = $this->driver->getMultiple(['x','y']);
		$this->assertEquals([], $actual);
	}

	public function testGetMultiple(): void
	{
		$this->driver->set('foo', ['bar']);
		$this->driver->set('bar', (object) [
			'foo' => [
				'bar' => 'baz'
			]
		]);

		// Intentionally set the same key with different values
		$this->driver->set('baz', 34);
		$this->driver->set('baz', 42);

		$expected = [
			'foo' => ['bar'],
			'bar' => (object) [
				'foo' => [
					'bar' => 'baz'
				]
			],
		];

		$actual = $this->driver->getMultiple(['foo', 'bar']);

		$this->assertEquals($expected, $actual);
	}

	public function testSetMultiple(): void
	{
		$data = [
			'foo' => [
				'apple' => 'orange'
			],
			'bar' => 'baz',
			'baz' => 123456,
			'a' => [1, 2, 3],
			'b' => false,
			'c' => true,
			'd' => null,
		];

		$this->assertTrue($this->driver->setMultiple($data));
		$this->assertEquals($data, $this->driver->getMultiple(array_keys($data)));
	}

	public function testSetMultipleInvalidKey(): void
	{
		$this->expectException(InvalidArgumentException::class);
		$data = [
			128 => 0,
			0x123 => 1,
		];

		$this->driver->setMultiple($data);
	}

	public function testSetMultipleExpires(): void
	{
		$data = [
			'foo' => [
				'apple' => 'orange'
			],
			'bar' => 'baz',
			'baz' => 123456,
			'a' => [1, 2, 3],
			'b' => false,
			'c' => true,
			'd' => null,
		];

		$this->assertTrue($this->driver->setMultiple($data, 30));
		$this->assertEquals($data, $this->driver->getMultiple(array_keys($data)));
	}

	public function testSetWithExpires(): void
	{
		$this->driver->set('foo', 'bar', 30);
		$this->assertEquals('bar', $this->driver->get('foo'));
	}

	public function testSetInvalidKey(): void
	{
		$this->expectException(\TypeError::class);
		$this->driver->set(0x12, 'foo');
	}

	public function testDelete(): void
	{
		$this->driver->set('a1', 'b2');
		$this->assertTrue($this->driver->exists('a1'));

		$this->assertTrue($this->driver->delete('a1'));

		$this->assertFalse($this->driver->exists('a1'));
	}

	public function testDeleteMultiple(): void
	{
		$this->driver->set('a', 1);
		$this->driver->set('b', 2);

		$this->assertTrue($this->driver->exists('a'));
		$this->assertTrue($this->driver->exists('b'));

		$this->assertTrue($this->driver->deleteMultiple(['a', 'b']));

		$this->assertFalse($this->driver->exists('a'));
		$this->assertFalse($this->driver->exists('b'));
	}

	public function testDeleteMultipleBadKey(): void
	{
		$this->assertFalse($this->driver->exists('foo'));
		$this->assertFalse($this->driver->exists('bar'));

		$this->assertFalse($this->driver->deleteMultiple(['foo', 'bar']));
	}

	public function testExpiresAt(): void
	{
		$this->driver->set('abc', 'def');
		$result = $this->driver->expiresAt('abc', 30);
		$this->assertTrue($result);
	}

	public function testExpiresAtBadKey(): void
	{
		$result = $this->driver->expiresAt('q', 30);
		$this->assertFalse($result);
	}
}