Skip to content

Commit c21c6fe

Browse files
committed
Add tests
These were created with the help of GPT-5.2. Disclaimer: I don't have the experience to judge the quality or validity of the results.
1 parent 950cf6d commit c21c6fe

1 file changed

Lines changed: 187 additions & 0 deletions

File tree

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<?php
2+
3+
/**
4+
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
5+
*
6+
* Copyright (C) 2019 - 2025 Jan Böhmer (https://github.com/jbtronics)
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as published
10+
* by the Free Software Foundation, either version 3 of the License, or
11+
* (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
*/
21+
22+
namespace App\Tests\DataTables\Filters;
23+
24+
use App\DataTables\Filters\PartSearchFilter;
25+
use App\Settings\BehaviorSettings\SearchSettings;
26+
use Doctrine\Common\Collections\ArrayCollection;
27+
use Doctrine\DBAL\ParameterType;
28+
use Doctrine\ORM\Query\Expr;
29+
use Doctrine\ORM\Query\Expr\Comparison;
30+
use Doctrine\ORM\Query\Expr\Orx;
31+
use Doctrine\ORM\Query\Parameter;
32+
use Doctrine\ORM\QueryBuilder;
33+
use PHPUnit\Framework\TestCase;
34+
35+
final class PartSearchFilterTest extends TestCase
36+
{
37+
private function makeSearchSettings(
38+
bool $enableAdvancedSearch = false,
39+
int $searchTokenLimit = 3,
40+
bool $escapeSQLWildcards = true,
41+
): SearchSettings {
42+
$settings = $this->createMock(SearchSettings::class);
43+
$settings->enableAdvancedSearch = $enableAdvancedSearch;
44+
$settings->searchTokenLimit = $searchTokenLimit;
45+
$settings->escapeSQLWildcards = $escapeSQLWildcards;
46+
47+
return $settings;
48+
}
49+
50+
public function testApplyReturnsEarlyWhenKeywordEmpty(): void
51+
{
52+
$filter = new PartSearchFilter('', $this->makeSearchSettings());
53+
54+
$qb = $this->createMock(QueryBuilder::class);
55+
$qb->expects($this->never())->method('andWhere');
56+
$qb->expects($this->never())->method('setParameter');
57+
58+
$filter->apply($qb);
59+
}
60+
61+
public function testApplyReturnsEarlyWhenNothingToSearchForAndNoExactIdSearch(): void
62+
{
63+
$filter = (new PartSearchFilter('foo', $this->makeSearchSettings()))
64+
->setName(false)
65+
->setCategory(false)
66+
->setDescription(false)
67+
->setComment(false)
68+
->setTags(false)
69+
->setStorelocation(false)
70+
->setOrdernr(false)
71+
->setMpn(false)
72+
->setSupplier(false)
73+
->setManufacturer(false)
74+
->setFootprint(false)
75+
->setIPN(false)
76+
->setDbId(false);
77+
78+
$qb = $this->createMock(QueryBuilder::class);
79+
$qb->expects($this->never())->method('andWhere');
80+
$qb->expects($this->never())->method('setParameter');
81+
82+
$filter->apply($qb);
83+
}
84+
85+
public function testApplyUsesRegexExpressionAndRawParameterWhenRegexEnabled(): void
86+
{
87+
$filter = (new PartSearchFilter('foo.*bar', $this->makeSearchSettings()))
88+
->setRegex(true);
89+
90+
$expr = $this->createStub(Expr::class);
91+
92+
$qb = $this->createMock(QueryBuilder::class);
93+
$qb->method('expr')->willReturn($expr);
94+
95+
$qb->expects($this->never())->method('setParameter');
96+
97+
// In PR #1406 the filter uses setParameters(ArrayCollection<Parameter>) instead of setParameter() in regex mode.
98+
$qb->expects($this->once())
99+
->method('setParameters')
100+
->with($this->callback(function ($params): bool {
101+
$this->assertInstanceOf(\Doctrine\Common\Collections\ArrayCollection::class, $params);
102+
103+
/** @var \Doctrine\ORM\Query\Parameter|null $p */
104+
$p = $params->get('search_query');
105+
$this->assertNotNull($p);
106+
$this->assertSame('foo.*bar', $p->getValue());
107+
108+
return true;
109+
}));
110+
111+
// We don't assert the exact expression object (Doctrine internals), only that a WHERE is added.
112+
$qb->expects($this->once())->method('andWhere');
113+
114+
$filter->apply($qb);
115+
}
116+
117+
public function testApplyEscapesSqlWildcardsAndWrapsLikeParameterWhenRegexDisabled(): void
118+
{
119+
$filter = (new PartSearchFilter('10%_off', $this->makeSearchSettings(escapeSQLWildcards: true)))
120+
->setRegex(false);
121+
122+
$expr = $this->createMock(Expr::class);
123+
$expr->method('orX')->willReturn(new Orx());
124+
125+
$qb = $this->createMock(QueryBuilder::class);
126+
$qb->method('expr')->willReturn($expr);
127+
128+
$qb->expects($this->once())
129+
->method('setParameter')
130+
->with('search_query', '%10\%\_off%');
131+
132+
$qb->expects($this->once())
133+
->method('andWhere')
134+
->with($this->isInstanceOf(Orx::class));
135+
136+
$filter->apply($qb);
137+
}
138+
139+
public function testApplyAddsExactIdExpressionWhenDbIdSearchEnabledAndKeywordNumeric(): void
140+
{
141+
$filter = (new PartSearchFilter('123', $this->makeSearchSettings()))
142+
->setDbId(true);
143+
144+
$expr = $this->createMock(Expr::class);
145+
$expr->expects($this->once())
146+
->method('eq')
147+
->with('part.id', ':id_exact')
148+
->willReturn(new Comparison('part.id', '=', ':id_exact'));
149+
150+
$expr->method('orX')->willReturn(new Orx());
151+
152+
$qb = $this->createMock(QueryBuilder::class);
153+
$qb->method('expr')->willReturn($expr);
154+
155+
$qb->expects($this->once())
156+
->method('setParameter')
157+
->with('id_exact', 123, ParameterType::INTEGER);
158+
159+
$qb->expects($this->once())
160+
->method('andWhere')
161+
->with($this->isInstanceOf(Orx::class));
162+
163+
$filter->apply($qb);
164+
}
165+
166+
public function testApplyDoesNotAddExactIdExpressionWhenKeywordNotNumeric(): void
167+
{
168+
$filter = (new PartSearchFilter('123abc', $this->makeSearchSettings()))
169+
->setDbId(true);
170+
171+
$expr = $this->createMock(Expr::class);
172+
$expr->expects($this->never())->method('eq');
173+
$expr->method('orX')->willReturn(new Orx());
174+
175+
$qb = $this->createMock(QueryBuilder::class);
176+
$qb->method('expr')->willReturn($expr);
177+
178+
// It should still set the search_query parameter for LIKE (default regex=false)
179+
$qb->expects($this->once())
180+
->method('setParameter')
181+
->with('search_query', '%123abc%');
182+
183+
$qb->expects($this->once())->method('andWhere');
184+
185+
$filter->apply($qb);
186+
}
187+
}

0 commit comments

Comments
 (0)