418 lines
14 KiB
PHP
418 lines
14 KiB
PHP
<?php
|
|
namespace Tests\Unit\Domain\Coupon;
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
use Domain\Coupon\CouponRepository;
|
|
|
|
class CouponRepositoryTest extends TestCase
|
|
{
|
|
public function testFindReturnsDefaultCouponForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$repository = new CouponRepository($mockDb);
|
|
|
|
$result = $repository->find(0);
|
|
|
|
$this->assertIsArray($result);
|
|
$this->assertSame(0, (int)$result['id']);
|
|
$this->assertSame(1, (int)$result['status']);
|
|
$this->assertSame(1, (int)$result['one_time']);
|
|
$this->assertSame([], $result['categories']);
|
|
}
|
|
|
|
public function testFindNormalizesCouponData(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_coupon', '*', ['id' => 15])
|
|
->willReturn([
|
|
'id' => '15',
|
|
'name' => 'KOD15',
|
|
'status' => '1',
|
|
'send' => 0,
|
|
'used' => '1',
|
|
'type' => '1',
|
|
'amount' => '15.00',
|
|
'one_time' => '0',
|
|
'include_discounted_product' => '1',
|
|
'categories' => '[4,6,6]',
|
|
'used_count' => '3',
|
|
]);
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$result = $repository->find(15);
|
|
|
|
$this->assertSame(15, (int)$result['id']);
|
|
$this->assertSame(1, (int)$result['status']);
|
|
$this->assertSame(0, (int)$result['send']);
|
|
$this->assertSame(1, (int)$result['used']);
|
|
$this->assertSame(0, (int)$result['one_time']);
|
|
$this->assertSame(1, (int)$result['include_discounted_product']);
|
|
$this->assertSame([4, 6], $result['categories']);
|
|
$this->assertSame(3, (int)$result['used_count']);
|
|
}
|
|
|
|
public function testSaveInsertsCouponAndReturnsId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$insertRow = null;
|
|
|
|
$mockDb->expects($this->once())
|
|
->method('insert')
|
|
->willReturnCallback(function ($table, $row) use (&$insertRow) {
|
|
$this->assertSame('pp_shop_coupon', $table);
|
|
$insertRow = $row;
|
|
});
|
|
|
|
$mockDb->expects($this->once())
|
|
->method('id')
|
|
->willReturn(321);
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$id = $repository->save([
|
|
'name' => ' KOD25 ',
|
|
'status' => 'on',
|
|
'send' => '1',
|
|
'used' => 0,
|
|
'type' => 1,
|
|
'amount' => '25,50',
|
|
'one_time' => 'on',
|
|
'include_discounted_product' => 'on',
|
|
'categories' => [1, '2', 'abc', 2],
|
|
]);
|
|
|
|
$this->assertSame(321, $id);
|
|
$this->assertIsArray($insertRow);
|
|
$this->assertSame('KOD25', $insertRow['name'] ?? '');
|
|
$this->assertSame(1, (int)($insertRow['status'] ?? 0));
|
|
$this->assertSame(1, (int)($insertRow['send'] ?? 0));
|
|
$this->assertSame(0, (int)($insertRow['used'] ?? 1));
|
|
$this->assertSame('25.50', $insertRow['amount'] ?? null);
|
|
$this->assertSame('[1,2]', $insertRow['categories'] ?? null);
|
|
}
|
|
|
|
public function testSaveUpdatesCouponAndReturnsId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$updateRow = null;
|
|
$updateWhere = null;
|
|
|
|
$mockDb->expects($this->once())
|
|
->method('update')
|
|
->willReturnCallback(function ($table, $row, $where) use (&$updateRow, &$updateWhere) {
|
|
$this->assertSame('pp_shop_coupon', $table);
|
|
$updateRow = $row;
|
|
$updateWhere = $where;
|
|
return true;
|
|
});
|
|
|
|
$mockDb->expects($this->never())->method('insert');
|
|
$mockDb->expects($this->never())->method('id');
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$id = $repository->save([
|
|
'id' => 77,
|
|
'name' => 'KOD77',
|
|
'status' => '0',
|
|
'send' => 'off',
|
|
'used' => '0',
|
|
'type' => 1,
|
|
'amount' => '',
|
|
'one_time' => '0',
|
|
'include_discounted_product' => 0,
|
|
'categories' => '',
|
|
]);
|
|
|
|
$this->assertSame(77, $id);
|
|
$this->assertIsArray($updateRow);
|
|
$this->assertArrayHasKey('amount', $updateRow);
|
|
$this->assertArrayHasKey('categories', $updateRow);
|
|
$this->assertNull($updateRow['amount']);
|
|
$this->assertNull($updateRow['categories']);
|
|
$this->assertSame(0, (int)($updateRow['status'] ?? 1));
|
|
$this->assertSame(['id' => 77], $updateWhere);
|
|
}
|
|
|
|
public function testDeleteReturnsFalseForInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('delete');
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$this->assertFalse($repository->delete(0));
|
|
}
|
|
|
|
public function testDeleteReturnsTrueWhenDatabaseDeleteSucceeds(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('delete')
|
|
->with('pp_shop_coupon', ['id' => 55])
|
|
->willReturn(true);
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$this->assertTrue($repository->delete(55));
|
|
}
|
|
|
|
public function testListForAdminWhitelistsSortAndDirection(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$queries = [];
|
|
|
|
$mockDb->method('query')
|
|
->willReturnCallback(function ($sql, $params = []) use (&$queries) {
|
|
$queries[] = ['sql' => $sql, 'params' => $params];
|
|
|
|
if (strpos($sql, 'COUNT(0)') !== false) {
|
|
return new class {
|
|
public function fetchAll()
|
|
{
|
|
return [[1]];
|
|
}
|
|
};
|
|
}
|
|
|
|
return new class {
|
|
public function fetchAll()
|
|
{
|
|
return [[
|
|
'id' => 1,
|
|
'name' => 'KOD',
|
|
'status' => 1,
|
|
'used' => 0,
|
|
'type' => 1,
|
|
'amount' => '10',
|
|
'one_time' => 1,
|
|
'send' => 0,
|
|
'include_discounted_product' => 0,
|
|
'categories' => '[3,5]',
|
|
'date_used' => null,
|
|
'used_count' => 7,
|
|
]];
|
|
}
|
|
};
|
|
});
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$result = $repository->listForAdmin(
|
|
[],
|
|
'date_used DESC; DROP TABLE pp_shop_coupon; --',
|
|
'DESC; DELETE FROM pp_users; --',
|
|
1,
|
|
999
|
|
);
|
|
|
|
$this->assertCount(2, $queries);
|
|
$dataSql = $queries[1]['sql'];
|
|
|
|
$this->assertMatchesRegularExpression('/ORDER BY\s+sc\.name\s+ASC,\s+sc\.id\s+DESC/i', $dataSql);
|
|
$this->assertStringNotContainsString('DROP TABLE', $dataSql);
|
|
$this->assertStringNotContainsString('DELETE FROM pp_users', $dataSql);
|
|
$this->assertMatchesRegularExpression('/LIMIT\s+100\s+OFFSET\s+0/i', $dataSql);
|
|
|
|
$this->assertSame([3, 5], $result['items'][0]['categories']);
|
|
}
|
|
|
|
public function testCategoriesTreeReturnsHierarchy(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
|
|
$mockDb->method('select')
|
|
->willReturnCallback(function ($table, $columns, $where) {
|
|
if ($table === 'pp_shop_categories' && array_key_exists('parent_id', $where)) {
|
|
if ($where['parent_id'] === null) {
|
|
return [['id' => 10]];
|
|
}
|
|
if ((int)$where['parent_id'] === 10) {
|
|
return [['id' => 11]];
|
|
}
|
|
return [];
|
|
}
|
|
|
|
if ($table === 'pp_shop_categories_langs') {
|
|
if ((int)$where['category_id'] === 10) {
|
|
return [['lang_id' => 'pl', 'title' => 'Kategoria A']];
|
|
}
|
|
if ((int)$where['category_id'] === 11) {
|
|
return [['lang_id' => 'pl', 'title' => 'Podkategoria A1']];
|
|
}
|
|
return [];
|
|
}
|
|
|
|
if ($table === 'pp_langs') {
|
|
return [['id' => 'pl', 'start' => 1, 'o' => 1]];
|
|
}
|
|
|
|
return [];
|
|
});
|
|
|
|
$mockDb->method('get')
|
|
->willReturnCallback(function ($table, $columns, $where) {
|
|
if ($table === 'pp_shop_categories') {
|
|
$id = (int)$where['id'];
|
|
return ['id' => $id, 'status' => 1];
|
|
}
|
|
return null;
|
|
});
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$tree = $repository->categoriesTree(null);
|
|
|
|
$this->assertCount(1, $tree);
|
|
$this->assertSame(10, (int)$tree[0]['id']);
|
|
$this->assertSame('Kategoria A', $tree[0]['title']);
|
|
$this->assertCount(1, $tree[0]['subcategories']);
|
|
$this->assertSame(11, (int)$tree[0]['subcategories'][0]['id']);
|
|
}
|
|
|
|
public function testFindByNameReturnsObjectWhenFound(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->with('pp_shop_coupon', '*', ['name' => 'RABAT10'])
|
|
->willReturn([
|
|
'id' => '5',
|
|
'name' => 'RABAT10',
|
|
'status' => '1',
|
|
'used' => '0',
|
|
'type' => '1',
|
|
'amount' => '10.00',
|
|
'one_time' => '1',
|
|
'include_discounted_product' => '0',
|
|
'categories' => '[1,2]',
|
|
'used_count' => '0',
|
|
]);
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$result = $repository->findByName('RABAT10');
|
|
|
|
$this->assertIsObject($result);
|
|
$this->assertSame(5, $result->id);
|
|
$this->assertSame('RABAT10', $result->name);
|
|
$this->assertSame(1, $result->status);
|
|
$this->assertSame(0, $result->used);
|
|
$this->assertSame(1, $result->type);
|
|
$this->assertSame('10.00', $result->amount);
|
|
$this->assertSame(1, $result->one_time);
|
|
$this->assertSame(0, $result->include_discounted_product);
|
|
$this->assertSame('[1,2]', $result->categories);
|
|
$this->assertSame(0, $result->used_count);
|
|
}
|
|
|
|
public function testFindByNameReturnsNullWhenNotFound(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('get')
|
|
->willReturn(null);
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$this->assertNull($repository->findByName('NIEISTNIEJACY'));
|
|
}
|
|
|
|
public function testFindByNameReturnsNullForEmptyName(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('get');
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$this->assertNull($repository->findByName(''));
|
|
$this->assertNull($repository->findByName(' '));
|
|
}
|
|
|
|
public function testIsAvailableReturnsTrueForActiveCoupon(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$repository = new CouponRepository($mockDb);
|
|
|
|
$coupon = (object)['id' => 1, 'status' => 1, 'used' => 0];
|
|
$this->assertTrue($repository->isAvailable($coupon));
|
|
}
|
|
|
|
public function testIsAvailableReturnsFalseForUsedCoupon(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$repository = new CouponRepository($mockDb);
|
|
|
|
$coupon = (object)['id' => 1, 'status' => 1, 'used' => 1];
|
|
$this->assertFalse($repository->isAvailable($coupon));
|
|
}
|
|
|
|
public function testIsAvailableReturnsFalseForInactiveCoupon(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$repository = new CouponRepository($mockDb);
|
|
|
|
$coupon = (object)['id' => 1, 'status' => 0, 'used' => 0];
|
|
$this->assertFalse($repository->isAvailable($coupon));
|
|
}
|
|
|
|
public function testIsAvailableReturnsFalseForNullCoupon(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$repository = new CouponRepository($mockDb);
|
|
|
|
$this->assertFalse($repository->isAvailable(null));
|
|
}
|
|
|
|
public function testIsAvailableWorksWithArray(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$repository = new CouponRepository($mockDb);
|
|
|
|
$this->assertTrue($repository->isAvailable(['id' => 1, 'status' => 1, 'used' => 0]));
|
|
$this->assertFalse($repository->isAvailable(['id' => 0, 'status' => 1, 'used' => 0]));
|
|
}
|
|
|
|
public function testMarkAsUsedCallsUpdate(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('update')
|
|
->willReturnCallback(function ($table, $row, $where) {
|
|
$this->assertSame('pp_shop_coupon', $table);
|
|
$this->assertSame(1, $row['used']);
|
|
$this->assertArrayHasKey('date_used', $row);
|
|
$this->assertSame(['id' => 10], $where);
|
|
});
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$repository->markAsUsed(10);
|
|
}
|
|
|
|
public function testMarkAsUsedSkipsInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('update');
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$repository->markAsUsed(0);
|
|
}
|
|
|
|
public function testIncrementUsedCountCallsUpdate(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->once())
|
|
->method('update')
|
|
->willReturnCallback(function ($table, $row, $where) {
|
|
$this->assertSame('pp_shop_coupon', $table);
|
|
$this->assertSame(1, $row['used_count[+]']);
|
|
$this->assertSame(['id' => 7], $where);
|
|
});
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$repository->incrementUsedCount(7);
|
|
}
|
|
|
|
public function testIncrementUsedCountSkipsInvalidId(): void
|
|
{
|
|
$mockDb = $this->createMock(\medoo::class);
|
|
$mockDb->expects($this->never())->method('update');
|
|
|
|
$repository = new CouponRepository($mockDb);
|
|
$repository->incrementUsedCount(0);
|
|
}
|
|
}
|