createMock(\medoo::class); $mockDb->expects($this->never())->method('get'); $repository = new ShopStatusRepository($mockDb); $this->assertNull($repository->find(-1)); } public function testFindReturnsNullWhenNotFound(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->once()) ->method('get') ->with('pp_shop_statuses', '*', ['id' => 99]) ->willReturn(null); $repository = new ShopStatusRepository($mockDb); $this->assertNull($repository->find(99)); } public function testFindReturnsStatusWithIdZero(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->once()) ->method('get') ->with('pp_shop_statuses', '*', ['id' => 0]) ->willReturn([ 'id' => '0', 'status' => 'zamówienie złożone', 'color' => '#ff0000', 'o' => '0', 'apilo_status_id' => '5', ]); $repository = new ShopStatusRepository($mockDb); $result = $repository->find(0); $this->assertIsArray($result); $this->assertSame(0, $result['id']); $this->assertSame('zamówienie złożone', $result['status']); $this->assertSame('#ff0000', $result['color']); $this->assertSame(0, $result['o']); $this->assertSame(5, $result['apilo_status_id']); } public function testFindNormalizesNullApiloStatusId(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->once()) ->method('get') ->with('pp_shop_statuses', '*', ['id' => 1]) ->willReturn([ 'id' => '1', 'status' => 'zamówienie opłacone', 'color' => '', 'o' => '1', 'apilo_status_id' => null, ]); $repository = new ShopStatusRepository($mockDb); $result = $repository->find(1); $this->assertIsArray($result); $this->assertSame(1, $result['id']); $this->assertNull($result['apilo_status_id']); } public function testSaveUpdatesColorAndApiloStatusId(): 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_statuses', $table); $updateRow = $row; $updateWhere = $where; return true; }); $repository = new ShopStatusRepository($mockDb); $id = $repository->save(3, [ 'color' => ' #00ff00 ', 'apilo_status_id' => '12', ]); $this->assertSame(3, $id); $this->assertSame('#00ff00', $updateRow['color']); $this->assertSame(12, $updateRow['apilo_status_id']); $this->assertSame(['id' => 3], $updateWhere); } public function testSaveWithIdZeroWorks(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->once()) ->method('update') ->with('pp_shop_statuses', $this->anything(), ['id' => 0]); $repository = new ShopStatusRepository($mockDb); $id = $repository->save(0, ['color' => '#aabbcc']); $this->assertSame(0, $id); } public function testSaveWithEmptyApiloStatusIdSetsNull(): void { $mockDb = $this->createMock(\medoo::class); $updateRow = null; $mockDb->expects($this->once()) ->method('update') ->willReturnCallback(function ($table, $row) use (&$updateRow) { $updateRow = $row; }); $repository = new ShopStatusRepository($mockDb); $repository->save(1, ['color' => '#000', 'apilo_status_id' => '']); $this->assertNull($updateRow['apilo_status_id']); } public function testSaveRejectsNegativeId(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->never())->method('update'); $repository = new ShopStatusRepository($mockDb); $this->assertSame(0, $repository->save(-1, ['color' => '#fff'])); } public function testGetApiloStatusIdReturnsValue(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->once()) ->method('get') ->with('pp_shop_statuses', 'apilo_status_id', ['id' => 4]) ->willReturn(15); $repository = new ShopStatusRepository($mockDb); $this->assertSame(15, $repository->getApiloStatusId(4)); } public function testGetApiloStatusIdReturnsNullWhenNotSet(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->once()) ->method('get') ->willReturn(null); $repository = new ShopStatusRepository($mockDb); $this->assertNull($repository->getApiloStatusId(4)); } public function testGetByIntegrationStatusIdForApilo(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->once()) ->method('get') ->with('pp_shop_statuses', 'id', ['apilo_status_id' => 15]) ->willReturn(4); $repository = new ShopStatusRepository($mockDb); $this->assertSame(4, $repository->getByIntegrationStatusId('apilo', 15)); } public function testGetByIntegrationStatusIdReturnsNullForUnknownIntegration(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->never())->method('get'); $repository = new ShopStatusRepository($mockDb); $this->assertNull($repository->getByIntegrationStatusId('unknown', 1)); } public function testAllStatusesReturnsOrderedList(): void { $mockDb = $this->createMock(\medoo::class); $mockDb->expects($this->once()) ->method('select') ->with('pp_shop_statuses', ['id', 'status'], ['ORDER' => ['o' => 'ASC']]) ->willReturn([ ['id' => 0, 'status' => 'złożone'], ['id' => 1, 'status' => 'opłacone'], ]); $repository = new ShopStatusRepository($mockDb); $result = $repository->allStatuses(); $this->assertSame([0 => 'złożone', 1 => 'opłacone'], $result); } 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 [[2]]; } }; } return new class { public function fetchAll() { return [[ 'id' => 0, 'status' => 'złożone', 'color' => '#fff', 'o' => 0, 'apilo_status_id' => null, ]]; } }; }); $repository = new ShopStatusRepository($mockDb); $result = $repository->listForAdmin( [], 'status DESC; DROP TABLE pp_shop_statuses; --', 'DESC; DELETE FROM pp_users; --', 1, 999 ); $this->assertCount(2, $queries); $dataSql = $queries[1]['sql']; $this->assertMatchesRegularExpression('/ORDER BY\s+ss\.o\s+ASC,\s+ss\.id\s+ASC/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); } }