ver. 0.272 - ShopProductSets refactor + update package

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 10:21:29 +01:00
parent 67b0a2bb6a
commit ca445d40d9
23 changed files with 993 additions and 297 deletions

View File

@@ -0,0 +1,185 @@
<?php
namespace Tests\Unit\Domain\ProductSet;
use PHPUnit\Framework\TestCase;
use Domain\ProductSet\ProductSetRepository;
class ProductSetRepositoryTest extends TestCase
{
public function testFindReturnsDefaultSetForInvalidId(): void
{
$mockDb = $this->createMock(\medoo::class);
$repository = new ProductSetRepository($mockDb);
$result = $repository->find(0);
$this->assertIsArray($result);
$this->assertSame(0, $result['id']);
$this->assertSame('', $result['name']);
$this->assertSame(1, $result['status']);
$this->assertSame([], $result['products']);
}
public function testFindNormalizesSetData(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('get')
->with('pp_shop_product_sets', '*', ['id' => 5])
->willReturn([
'id' => '5',
'name' => 'Komplet A',
'status' => '1',
]);
$mockDb->expects($this->once())
->method('select')
->with('pp_shop_product_sets_products', 'product_id', ['set_id' => 5])
->willReturn(['10', '20', '30']);
$repository = new ProductSetRepository($mockDb);
$result = $repository->find(5);
$this->assertSame(5, $result['id']);
$this->assertSame('Komplet A', $result['name']);
$this->assertSame(1, $result['status']);
$this->assertSame([10, 20, 30], $result['products']);
}
public function testSaveInsertsNewSetAndSyncsProducts(): void
{
$mockDb = $this->createMock(\medoo::class);
$insertCalls = [];
$deleteCalls = [];
$mockDb->method('insert')
->willReturnCallback(function ($table, $row) use (&$insertCalls) {
$insertCalls[] = ['table' => $table, 'row' => $row];
});
$mockDb->expects($this->once())
->method('id')
->willReturn(42);
$mockDb->method('delete')
->willReturnCallback(function ($table, $where) use (&$deleteCalls) {
$deleteCalls[] = ['table' => $table, 'where' => $where];
return true;
});
$repository = new ProductSetRepository($mockDb);
$id = $repository->save(0, 'Nowy komplet', 1, [10, 20, 20]);
$this->assertSame(42, $id);
$this->assertSame('pp_shop_product_sets', $insertCalls[0]['table']);
$this->assertSame('Nowy komplet', $insertCalls[0]['row']['name']);
$this->assertSame(1, $insertCalls[0]['row']['status']);
// Sync: delete old + insert 2 unique products (10, 20)
$this->assertSame('pp_shop_product_sets_products', $deleteCalls[0]['table']);
$this->assertSame(['set_id' => 42], $deleteCalls[0]['where']);
$productInserts = array_filter($insertCalls, fn($c) => $c['table'] === 'pp_shop_product_sets_products');
$this->assertCount(2, $productInserts);
}
public function testSaveUpdatesExistingSet(): void
{
$mockDb = $this->createMock(\medoo::class);
$updateRow = null;
$mockDb->expects($this->once())
->method('update')
->willReturnCallback(function ($table, $row, $where) use (&$updateRow) {
$this->assertSame('pp_shop_product_sets', $table);
$this->assertSame(['id' => 7], $where);
$updateRow = $row;
return true;
});
$mockDb->expects($this->never())->method('id');
$mockDb->method('delete')->willReturn(true);
$mockDb->method('insert')->willReturn(null);
$repository = new ProductSetRepository($mockDb);
$id = $repository->save(7, 'Zaktualizowany', 0, [15]);
$this->assertSame(7, $id);
$this->assertSame('Zaktualizowany', $updateRow['name']);
$this->assertSame(0, $updateRow['status']);
}
public function testDeleteReturnsFalseForInvalidId(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->never())->method('delete');
$repository = new ProductSetRepository($mockDb);
$this->assertFalse($repository->delete(0));
}
public function testListForAdminWhitelistsSortAndPagination(): 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' => 'Test',
'status' => 1,
]];
}
};
});
$repository = new ProductSetRepository($mockDb);
$result = $repository->listForAdmin(
[],
'name DESC; DROP TABLE pp_shop_product_sets; --',
'DESC; DELETE FROM pp_users; --',
1,
999
);
$this->assertCount(2, $queries);
$dataSql = $queries[1]['sql'];
$this->assertMatchesRegularExpression('/ORDER BY\s+ps\.name\s+ASC,\s+ps\.id\s+DESC/i', $dataSql);
$this->assertStringNotContainsString('DROP TABLE', $dataSql);
$this->assertMatchesRegularExpression('/LIMIT\s+100\s+OFFSET\s+0/i', $dataSql);
}
public function testAllSetsReturnsFormattedList(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('select')
->with('pp_shop_product_sets', ['id', 'name'], ['ORDER' => ['name' => 'ASC']])
->willReturn([
['id' => '1', 'name' => 'Komplet A'],
['id' => '2', 'name' => 'Komplet B'],
]);
$repository = new ProductSetRepository($mockDb);
$result = $repository->allSets();
$this->assertCount(2, $result);
$this->assertSame(1, $result[0]['id']);
$this->assertSame('Komplet A', $result[0]['name']);
$this->assertSame(2, $result[1]['id']);
}
}