mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-01-13 21:59:34 +00:00
Merge branch 'master' into bulk-edit-tags
This commit is contained in:
commit
7df3e8e634
421 changed files with 39491 additions and 16789 deletions
|
|
@ -23,15 +23,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\API;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\UserSystem\User;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class APIDocsAvailabilityTest extends WebTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider urlProvider
|
||||
*/
|
||||
#[DataProvider('urlProvider')]
|
||||
public function testDocAvailabilityForLoggedInUser(string $url): void
|
||||
{
|
||||
self::ensureKernelShutdown();
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class CurrencyEndpointTest extends CrudEndpointTestCase
|
|||
{
|
||||
$this->_testGetCollection();
|
||||
self::assertJsonContains([
|
||||
'hydra:totalItems' => 0,
|
||||
'hydra:totalItems' => 4, //The 4 currencies from our fixtures
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ class CurrencyEndpointTest extends CrudEndpointTestCase
|
|||
{
|
||||
$this->_testPostItem([
|
||||
'name' => 'Test API',
|
||||
'iso_code' => 'USD',
|
||||
'iso_code' => 'CAD',
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -61,4 +61,4 @@ class CurrencyEndpointTest extends CrudEndpointTestCase
|
|||
{
|
||||
$this->_testDeleteItem(5);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,20 +22,19 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Generator;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* This test just ensures that different pages are available (do not throw an exception).
|
||||
*
|
||||
* @group DB
|
||||
* @group slow
|
||||
*/
|
||||
#[Group('DB')]
|
||||
#[Group('slow')]
|
||||
class ApplicationAvailabilityFunctionalTest extends WebTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider urlProvider
|
||||
*/
|
||||
#[DataProvider('urlProvider')]
|
||||
public function testPageIsSuccessful(string $url): void
|
||||
{
|
||||
//We have localized routes
|
||||
|
|
@ -54,7 +53,7 @@ class ApplicationAvailabilityFunctionalTest extends WebTestCase
|
|||
$this->assertTrue($client->getResponse()->isSuccessful(), 'Request not successful. Status code is '.$client->getResponse()->getStatusCode() . ' for URL '.$url);
|
||||
}
|
||||
|
||||
public function urlProvider(): ?Generator
|
||||
public static function urlProvider(): ?Generator
|
||||
{
|
||||
//Homepage
|
||||
yield ['/'];
|
||||
|
|
|
|||
|
|
@ -22,19 +22,19 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
abstract class AbstractAdminControllerTest extends WebTestCase
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
abstract class AbstractAdminController extends WebTestCase
|
||||
{
|
||||
protected static string $base_path = 'not_valid';
|
||||
protected static string $entity_class = 'not valid';
|
||||
|
||||
public function readDataProvider(): \Iterator
|
||||
public static function readDataProvider(): \Iterator
|
||||
{
|
||||
yield ['noread', false];
|
||||
yield ['anonymous', true];
|
||||
|
|
@ -43,10 +43,10 @@ abstract class AbstractAdminControllerTest extends WebTestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @dataProvider readDataProvider
|
||||
* @group slow
|
||||
* Tests if you can access the /new part which is used to list all entities. Checks if permissions are working
|
||||
*/
|
||||
#[DataProvider('readDataProvider')]
|
||||
#[Group('slow')]
|
||||
public function testListEntries(string $user, bool $read): void
|
||||
{
|
||||
static::ensureKernelShutdown();
|
||||
|
|
@ -72,10 +72,13 @@ abstract class AbstractAdminControllerTest extends WebTestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @dataProvider readDataProvider
|
||||
* @group slow
|
||||
* Tests if it is possible to access a specific entity. Checks if permissions are working.
|
||||
* @param string $user
|
||||
* @param bool $read
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('readDataProvider')]
|
||||
#[Group('slow')]
|
||||
public function testReadEntity(string $user, bool $read): void
|
||||
{
|
||||
//Test read access
|
||||
|
|
@ -96,7 +99,7 @@ abstract class AbstractAdminControllerTest extends WebTestCase
|
|||
$this->assertSame($read, !$client->getResponse()->isForbidden(), 'Permission Checking not working!');
|
||||
}
|
||||
|
||||
public function deleteDataProvider(): \Iterator
|
||||
public static function deleteDataProvider(): \Iterator
|
||||
{
|
||||
yield ['noread', false];
|
||||
yield ['anonymous', false];
|
||||
|
|
@ -106,10 +109,9 @@ abstract class AbstractAdminControllerTest extends WebTestCase
|
|||
|
||||
/**
|
||||
* Tests if deleting an entity is working.
|
||||
*
|
||||
* @group slow
|
||||
* @dataProvider deleteDataProvider
|
||||
*/
|
||||
#[DataProvider('deleteDataProvider')]
|
||||
#[Group('slow')]
|
||||
public function testDeleteEntity(string $user, bool $delete): void
|
||||
{
|
||||
//Test read access
|
||||
|
|
@ -22,13 +22,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class AttachmentTypeControllerTest extends AbstractAdminControllerTest
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class AttachmentTypeController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/attachment_type';
|
||||
protected static string $entity_class = AttachmentType::class;
|
||||
|
|
@ -22,13 +22,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Parts\Category;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class CategoryControllerTest extends AbstractAdminControllerTest
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class CategoryController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/category';
|
||||
protected static string $entity_class = Category::class;
|
||||
35
tests/Controller/AdminPages/CurrencyController.php
Normal file
35
tests/Controller/AdminPages/CurrencyController.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2020 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use App\Entity\PriceInformations\Currency;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Parts\Manufacturer;
|
||||
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class CurrencyController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/currency';
|
||||
protected static string $entity_class = Currency::class;
|
||||
}
|
||||
|
|
@ -22,13 +22,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Parts\Footprint;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class FootprintControllerTest extends AbstractAdminControllerTest
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class FootprintController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/footprint';
|
||||
protected static string $entity_class = Footprint::class;
|
||||
|
|
@ -41,20 +41,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\LabelSystem\LabelProfile;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
|
||||
class LabelProfileControllerTest extends AbstractAdminControllerTest
|
||||
class LabelProfileController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/label_profile';
|
||||
protected static string $entity_class = LabelProfile::class;
|
||||
|
||||
/**
|
||||
* Tests if deleting an entity is working.
|
||||
*
|
||||
* @group slow
|
||||
* @dataProvider deleteDataProvider
|
||||
*/
|
||||
#[DataProvider('deleteDataProvider')]
|
||||
#[Group('slow')]
|
||||
public function testDeleteEntity(string $user, bool $delete): void
|
||||
{
|
||||
//Test read access
|
||||
|
|
@ -22,13 +22,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Parts\Manufacturer;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class ManufacturerControllerTest extends AbstractAdminControllerTest
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class ManufacturerController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/manufacturer';
|
||||
protected static string $entity_class = Manufacturer::class;
|
||||
|
|
@ -22,13 +22,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Parts\MeasurementUnit;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class MeasurementUnitControllerTest extends AbstractAdminControllerTest
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class MeasurementUnitController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/measurement_unit';
|
||||
protected static string $entity_class = MeasurementUnit::class;
|
||||
|
|
@ -23,13 +23,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\ProjectSystem\Project;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class ProjectControllerTest extends AbstractAdminControllerTest
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class ProjectController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/project';
|
||||
protected static string $entity_class = Project::class;
|
||||
|
|
@ -22,13 +22,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Parts\StorageLocation;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class StorelocationControllerTest extends AbstractAdminControllerTest
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class StorelocationController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/store_location';
|
||||
protected static string $entity_class = StorageLocation::class;
|
||||
|
|
@ -22,13 +22,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller\AdminPages;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Parts\Supplier;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class SupplierControllerTest extends AbstractAdminControllerTest
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class SupplierController extends AbstractAdminController
|
||||
{
|
||||
protected static string $base_path = '/en/supplier';
|
||||
protected static string $entity_class = Supplier::class;
|
||||
889
tests/Controller/BulkInfoProviderImportControllerTest.php
Normal file
889
tests/Controller/BulkInfoProviderImportControllerTest.php
Normal file
|
|
@ -0,0 +1,889 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Entity\InfoProviderSystem\BulkImportJobStatus;
|
||||
use App\Entity\InfoProviderSystem\BulkInfoProviderImportJob;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultsDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchResponseDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class BulkInfoProviderImportControllerTest extends WebTestCase
|
||||
{
|
||||
public function testStep1WithoutIds(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step1');
|
||||
|
||||
self::assertResponseRedirects();
|
||||
}
|
||||
|
||||
public function testStep1WithInvalidIds(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step1?ids=999999,888888');
|
||||
|
||||
self::assertResponseRedirects();
|
||||
}
|
||||
|
||||
public function testManagePage(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/manage');
|
||||
|
||||
// Follow any redirects (like locale redirects)
|
||||
if ($client->getResponse()->isRedirect()) {
|
||||
$client->followRedirect();
|
||||
}
|
||||
|
||||
self::assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
}
|
||||
|
||||
public function testAccessControlForStep1(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step1?ids=1');
|
||||
self::assertResponseRedirects();
|
||||
|
||||
$this->loginAsUser($client, 'noread');
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step1?ids=1');
|
||||
|
||||
// Follow redirects if any, then check for 403 or final response
|
||||
if ($client->getResponse()->isRedirect()) {
|
||||
$client->followRedirect();
|
||||
}
|
||||
|
||||
// The user might get redirected to an error page instead of direct 403
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->getStatusCode() === Response::HTTP_FORBIDDEN ||
|
||||
$client->getResponse()->getStatusCode() === Response::HTTP_OK
|
||||
);
|
||||
}
|
||||
|
||||
public function testAccessControlForManage(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/manage');
|
||||
self::assertResponseRedirects();
|
||||
|
||||
$this->loginAsUser($client, 'noread');
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/manage');
|
||||
|
||||
// Follow redirects if any, then check for 403 or final response
|
||||
if ($client->getResponse()->isRedirect()) {
|
||||
$client->followRedirect();
|
||||
}
|
||||
|
||||
// The user might get redirected to an error page instead of direct 403
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->getStatusCode() === Response::HTTP_FORBIDDEN ||
|
||||
$client->getResponse()->getStatusCode() === Response::HTTP_OK
|
||||
);
|
||||
}
|
||||
|
||||
public function testStep2TemplateRendering(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = static::getContainer()->get('doctrine')->getManager();
|
||||
|
||||
// Use an existing part from test fixtures (ID 1 should exist)
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
// Get the admin user for the createdBy field
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped('Admin user not found in fixtures');
|
||||
}
|
||||
|
||||
// Create a test job with search results that include source_field and source_keyword
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
$job->addPart($part);
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
|
||||
$searchResults = new BulkSearchResponseDTO(partResults: [
|
||||
new BulkSearchPartResultsDTO(part: $part,
|
||||
searchResults: [new BulkSearchPartResultDTO(
|
||||
searchResult: new SearchResultDTO(provider_key: 'test_provider', provider_id: 'TEST123', name: 'Test Component', description: 'Test component description', manufacturer: 'Test Manufacturer', mpn: 'TEST-MPN-123', provider_url: 'https://example.com/test', preview_image_url: null,),
|
||||
sourceField: 'test_field',
|
||||
sourceKeyword: 'test_keyword',
|
||||
localPart: null,
|
||||
)]
|
||||
)
|
||||
]);
|
||||
|
||||
$job->setSearchResults($searchResults);
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
// Test that step2 renders correctly with the search results
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step2/' . $job->getId());
|
||||
|
||||
// Follow any redirects (like locale redirects)
|
||||
if ($client->getResponse()->isRedirect()) {
|
||||
$client->followRedirect();
|
||||
}
|
||||
|
||||
self::assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
|
||||
// Verify the template rendered the source_field and source_keyword correctly
|
||||
$content = $client->getResponse()->getContent();
|
||||
$this->assertStringContainsString('test_field', $content);
|
||||
$this->assertStringContainsString('test_keyword', $content);
|
||||
|
||||
// Clean up - find by ID to avoid detached entity issues
|
||||
$jobId = $job->getId();
|
||||
$entityManager->clear(); // Clear all entities
|
||||
$jobToRemove = $entityManager->find(BulkInfoProviderImportJob::class, $jobId);
|
||||
if ($jobToRemove) {
|
||||
$entityManager->remove($jobToRemove);
|
||||
$entityManager->flush();
|
||||
}
|
||||
}
|
||||
|
||||
public function testStep1WithValidIds(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step1?ids=' . $part->getId());
|
||||
|
||||
if ($client->getResponse()->isRedirect()) {
|
||||
$client->followRedirect();
|
||||
}
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
}
|
||||
|
||||
|
||||
public function testDeleteJobWithValidJob(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = self::getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped('Admin user not found in fixtures');
|
||||
}
|
||||
|
||||
// Get a test part
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
// Create a completed job
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
$job->addPart($part);
|
||||
$job->setStatus(BulkImportJobStatus::COMPLETED);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('DELETE', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/delete');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$response = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertTrue($response['success']);
|
||||
}
|
||||
|
||||
public function testDeleteJobWithNonExistentJob(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$client->request('DELETE', '/en/tools/bulk_info_provider_import/job/999999/delete');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
|
||||
$response = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertArrayHasKey('error', $response);
|
||||
}
|
||||
|
||||
public function testDeleteJobWithActiveJob(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = self::getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped('Admin user not found in fixtures');
|
||||
}
|
||||
|
||||
// Get test parts
|
||||
$parts = $this->getTestParts($entityManager, [1]);
|
||||
|
||||
// Create an active job
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
foreach ($parts as $part) {
|
||||
$job->addPart($part);
|
||||
}
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('DELETE', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/delete');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_BAD_REQUEST);
|
||||
$response = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertArrayHasKey('error', $response);
|
||||
|
||||
// Clean up
|
||||
$entityManager->remove($job);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
public function testStopJobWithValidJob(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = self::getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped('Admin user not found in fixtures');
|
||||
}
|
||||
|
||||
// Get test parts
|
||||
$parts = $this->getTestParts($entityManager, [1]);
|
||||
|
||||
// Create an active job
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
foreach ($parts as $part) {
|
||||
$job->addPart($part);
|
||||
}
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/stop');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$response = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertTrue($response['success']);
|
||||
|
||||
// Clean up
|
||||
$entityManager->remove($job);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
public function testStopJobWithNonExistentJob(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/999999/stop');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
|
||||
$response = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertArrayHasKey('error', $response);
|
||||
}
|
||||
|
||||
public function testMarkPartCompleted(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped('Admin user not found in fixtures');
|
||||
}
|
||||
|
||||
// Get test parts
|
||||
$parts = $this->getTestParts($entityManager, [1, 2]);
|
||||
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
foreach ($parts as $part) {
|
||||
$job->addPart($part);
|
||||
}
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/part/1/mark-completed');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$response = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertTrue($response['success']);
|
||||
$this->assertArrayHasKey('progress', $response);
|
||||
$this->assertArrayHasKey('completed_count', $response);
|
||||
|
||||
// Clean up
|
||||
$entityManager->remove($job);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
public function testMarkPartSkipped(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped('Admin user not found in fixtures');
|
||||
}
|
||||
|
||||
// Get test parts
|
||||
$parts = $this->getTestParts($entityManager, [1, 2]);
|
||||
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
foreach ($parts as $part) {
|
||||
$job->addPart($part);
|
||||
}
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/part/1/mark-skipped', [
|
||||
'reason' => 'Test skip reason'
|
||||
]);
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$response = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertTrue($response['success']);
|
||||
$this->assertArrayHasKey('skipped_count', $response);
|
||||
|
||||
// Clean up
|
||||
$entityManager->remove($job);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
public function testMarkPartPending(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped('Admin user not found in fixtures');
|
||||
}
|
||||
|
||||
// Get test parts
|
||||
$parts = $this->getTestParts($entityManager, [1]);
|
||||
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
foreach ($parts as $part) {
|
||||
$job->addPart($part);
|
||||
}
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/part/1/mark-pending');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$response = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertTrue($response['success']);
|
||||
|
||||
// Clean up
|
||||
$entityManager->remove($job);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
public function testStep2WithNonExistentJob(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step2/999999');
|
||||
|
||||
$this->assertResponseRedirects();
|
||||
}
|
||||
|
||||
public function testStep2WithUnauthorizedAccess(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$admin = $userRepository->findOneBy(['name' => 'admin']);
|
||||
$readonly = $userRepository->findOneBy(['name' => 'noread']);
|
||||
|
||||
if (!$admin || !$readonly) {
|
||||
$this->markTestSkipped('Required test users not found in fixtures');
|
||||
}
|
||||
|
||||
// Get test parts
|
||||
$parts = $this->getTestParts($entityManager, [1]);
|
||||
|
||||
// Create job as admin
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($admin);
|
||||
foreach ($parts as $part) {
|
||||
$job->addPart($part);
|
||||
}
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
// Try to access as readonly user
|
||||
$this->loginAsUser($client, 'noread');
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step2/' . $job->getId());
|
||||
|
||||
$this->assertResponseRedirects();
|
||||
|
||||
// Clean up
|
||||
$entityManager->remove($job);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
public function testJobAccessControlForDelete(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$admin = $userRepository->findOneBy(['name' => 'admin']);
|
||||
$readonly = $userRepository->findOneBy(['name' => 'noread']);
|
||||
|
||||
if (!$admin || !$readonly) {
|
||||
$this->markTestSkipped('Required test users not found in fixtures');
|
||||
}
|
||||
|
||||
// Get test parts
|
||||
$parts = $this->getTestParts($entityManager, [1]);
|
||||
|
||||
// Create job as readonly user
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($readonly);
|
||||
foreach ($parts as $part) {
|
||||
$job->addPart($part);
|
||||
}
|
||||
$job->setStatus(BulkImportJobStatus::COMPLETED);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
// Try to delete as admin (should fail due to ownership)
|
||||
$client->request('DELETE', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/delete');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
|
||||
|
||||
// Clean up
|
||||
$entityManager->remove($job);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
private function loginAsUser($client, string $username): void
|
||||
{
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => $username]);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped("User {$username} not found");
|
||||
}
|
||||
|
||||
$client->loginUser($user);
|
||||
}
|
||||
|
||||
private function getTestParts($entityManager, array $ids): array
|
||||
{
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$parts = [];
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$part = $partRepository->find($id);
|
||||
if (!$part) {
|
||||
$this->markTestSkipped("Test part with ID {$id} not found in fixtures");
|
||||
}
|
||||
$parts[] = $part;
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
public function testStep1Form(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step1?ids=' . $part->getId());
|
||||
|
||||
if ($client->getResponse()->isRedirect()) {
|
||||
$client->followRedirect();
|
||||
}
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$this->assertStringContainsString('Bulk Info Provider Import', $client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function testStep1FormSubmissionWithErrors(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/step1?ids=' . $part->getId());
|
||||
|
||||
if ($client->getResponse()->isRedirect()) {
|
||||
$client->followRedirect();
|
||||
}
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$this->assertStringContainsString('Bulk Info Provider Import', $client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function testBulkInfoProviderServiceKeywordExtraction(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
// Test that the service can extract keywords from parts
|
||||
$bulkService = $client->getContainer()->get(\App\Services\InfoProviderSystem\BulkInfoProviderService::class);
|
||||
|
||||
// Create field mappings to verify the service works
|
||||
$fieldMappings = [
|
||||
new \App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO('name', ['test'], 1),
|
||||
new \App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO('mpn', ['test'], 2)
|
||||
];
|
||||
|
||||
// The service may return an empty result or throw when no results are found
|
||||
try {
|
||||
$result = $bulkService->performBulkSearch([$part], $fieldMappings, false);
|
||||
$this->assertInstanceOf(\App\Services\InfoProviderSystem\DTOs\BulkSearchResponseDTO::class, $result);
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->assertStringContainsString('No search results found', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testManagePageWithJobCleanup(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped('Admin user not found in fixtures');
|
||||
}
|
||||
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
$job->addPart($part);
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('GET', '/tools/bulk_info_provider_import/manage');
|
||||
|
||||
if ($client->getResponse()->isRedirect()) {
|
||||
$client->followRedirect();
|
||||
}
|
||||
|
||||
self::assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
|
||||
// Find job from database to avoid detached entity errors
|
||||
$jobId = $job->getId();
|
||||
$entityManager->clear();
|
||||
$persistedJob = $entityManager->find(BulkInfoProviderImportJob::class, $jobId);
|
||||
if ($persistedJob) {
|
||||
$entityManager->remove($persistedJob);
|
||||
$entityManager->flush();
|
||||
}
|
||||
}
|
||||
|
||||
public function testBulkInfoProviderServiceSupplierPartNumberExtraction(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
// Test that the service can handle supplier part number fields
|
||||
$bulkService = $client->getContainer()->get(\App\Services\InfoProviderSystem\BulkInfoProviderService::class);
|
||||
|
||||
// Create field mappings with supplier SPN field mapping
|
||||
$fieldMappings = [
|
||||
new \App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO('invalid_field', ['test'], 1),
|
||||
new \App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO('test_supplier_spn', ['test'], 2)
|
||||
];
|
||||
|
||||
// The service should be able to process the request and throw an exception when no results are found
|
||||
try {
|
||||
$bulkService->performBulkSearch([$part], $fieldMappings, false);
|
||||
$this->fail('Expected RuntimeException to be thrown when no search results are found');
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->assertStringContainsString('No search results found', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testBulkInfoProviderServiceBatchProcessing(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
// Test that the service can handle batch processing
|
||||
$bulkService = $client->getContainer()->get(\App\Services\InfoProviderSystem\BulkInfoProviderService::class);
|
||||
|
||||
// Create field mappings with multiple keywords
|
||||
$fieldMappings = [
|
||||
new \App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO('empty', ['test'], 1)
|
||||
];
|
||||
|
||||
// The service should be able to process the request and throw an exception when no results are found
|
||||
try {
|
||||
$response = $bulkService->performBulkSearch([$part], $fieldMappings, false);
|
||||
$this->fail('Expected RuntimeException to be thrown when no search results are found');
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->assertStringContainsString('No search results found', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testBulkInfoProviderServicePrefetchDetails(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
// Test that the service can handle prefetch details
|
||||
$bulkService = $client->getContainer()->get(\App\Services\InfoProviderSystem\BulkInfoProviderService::class);
|
||||
|
||||
// Create empty search results to test prefetch method
|
||||
$searchResults = new BulkSearchResponseDTO([
|
||||
new BulkSearchPartResultsDTO(part: $part, searchResults: [], errors: [])
|
||||
]);
|
||||
|
||||
// The prefetch method should not throw any errors
|
||||
$bulkService->prefetchDetailsForResults($searchResults);
|
||||
|
||||
// If we get here, the method executed successfully
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function testJobAccessControlForStopAndMarkOperations(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$admin = $userRepository->findOneBy(['name' => 'admin']);
|
||||
$readonly = $userRepository->findOneBy(['name' => 'noread']);
|
||||
|
||||
if (!$admin || !$readonly) {
|
||||
$this->markTestSkipped('Required test users not found in fixtures');
|
||||
}
|
||||
|
||||
$parts = $this->getTestParts($entityManager, [1]);
|
||||
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($readonly);
|
||||
foreach ($parts as $part) {
|
||||
$job->addPart($part);
|
||||
}
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/stop');
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/part/1/mark-completed');
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/part/1/mark-skipped', [
|
||||
'reason' => 'Test reason'
|
||||
]);
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/part/1/mark-pending');
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
|
||||
|
||||
// Find job from database to avoid detached entity errors
|
||||
$jobId = $job->getId();
|
||||
$entityManager->clear();
|
||||
$persistedJob = $entityManager->find(BulkInfoProviderImportJob::class, $jobId);
|
||||
if ($persistedJob) {
|
||||
$entityManager->remove($persistedJob);
|
||||
$entityManager->flush();
|
||||
}
|
||||
}
|
||||
|
||||
public function testOperationsOnCompletedJob(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped('Admin user not found in fixtures');
|
||||
}
|
||||
|
||||
$parts = $this->getTestParts($entityManager, [1]);
|
||||
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
foreach ($parts as $part) {
|
||||
$job->addPart($part);
|
||||
}
|
||||
$job->setStatus(BulkImportJobStatus::COMPLETED);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('POST', '/en/tools/bulk_info_provider_import/job/' . $job->getId() . '/stop');
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_BAD_REQUEST);
|
||||
$response = json_decode($client->getResponse()->getContent(), true);
|
||||
$this->assertArrayHasKey('error', $response);
|
||||
|
||||
$entityManager->remove($job);
|
||||
$entityManager->flush();
|
||||
}
|
||||
}
|
||||
334
tests/Controller/PartControllerTest.php
Normal file
334
tests/Controller/PartControllerTest.php
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Entity\InfoProviderSystem\BulkImportJobStatus;
|
||||
use App\Entity\InfoProviderSystem\BulkInfoProviderImportJob;
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Entity\Parts\Footprint;
|
||||
use App\Entity\Parts\Manufacturer;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\Parts\StorageLocation;
|
||||
use App\Entity\Parts\Supplier;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchResponseDTO;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class PartControllerTest extends WebTestCase
|
||||
{
|
||||
public function testShowPart(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/en/part/' . $part->getId());
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
}
|
||||
|
||||
public function testShowPartWithTimestamp(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$timestamp = time();
|
||||
$client->request('GET', "/en/part/{$part->getId()}/info/{$timestamp}");
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
}
|
||||
|
||||
public function testEditPart(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/en/part/' . $part->getId() . '/edit');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$this->assertSelectorExists('form[name="part_base"]');
|
||||
}
|
||||
|
||||
public function testEditPartWithBulkJob(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => 'admin']);
|
||||
|
||||
if (!$part || !$user) {
|
||||
$this->markTestSkipped('Required test data not found in fixtures');
|
||||
}
|
||||
|
||||
// Create a bulk job
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
$job->setCreatedBy($user);
|
||||
$job->setPartIds([$part->getId()]);
|
||||
$job->setStatus(BulkImportJobStatus::IN_PROGRESS);
|
||||
$job->setSearchResults(new BulkSearchResponseDTO([]));
|
||||
|
||||
$entityManager->persist($job);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('GET', '/en/part/' . $part->getId() . '/edit?jobId=' . $job->getId());
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
|
||||
// Clean up
|
||||
$entityManager->remove($job);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function testNewPart(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$client->request('GET', '/en/part/new');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$this->assertSelectorExists('form[name="part_base"]');
|
||||
}
|
||||
|
||||
public function testNewPartWithCategory(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$categoryRepository = $entityManager->getRepository(Category::class);
|
||||
$category = $categoryRepository->find(1);
|
||||
|
||||
if (!$category) {
|
||||
$this->markTestSkipped('Test category with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/en/part/new?category=' . $category->getId());
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
}
|
||||
|
||||
public function testNewPartWithFootprint(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$footprintRepository = $entityManager->getRepository(Footprint::class);
|
||||
$footprint = $footprintRepository->find(1);
|
||||
|
||||
if (!$footprint) {
|
||||
$this->markTestSkipped('Test footprint with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/en/part/new?footprint=' . $footprint->getId());
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
}
|
||||
|
||||
public function testNewPartWithManufacturer(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$manufacturerRepository = $entityManager->getRepository(Manufacturer::class);
|
||||
$manufacturer = $manufacturerRepository->find(1);
|
||||
|
||||
if (!$manufacturer) {
|
||||
$this->markTestSkipped('Test manufacturer with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/en/part/new?manufacturer=' . $manufacturer->getId());
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
}
|
||||
|
||||
public function testNewPartWithStorageLocation(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$storageLocationRepository = $entityManager->getRepository(StorageLocation::class);
|
||||
$storageLocation = $storageLocationRepository->find(1);
|
||||
|
||||
if (!$storageLocation) {
|
||||
$this->markTestSkipped('Test storage location with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/en/part/new?storelocation=' . $storageLocation->getId());
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
}
|
||||
|
||||
public function testNewPartWithSupplier(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$supplierRepository = $entityManager->getRepository(Supplier::class);
|
||||
$supplier = $supplierRepository->find(1);
|
||||
|
||||
if (!$supplier) {
|
||||
$this->markTestSkipped('Test supplier with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/en/part/new?supplier=' . $supplier->getId());
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
}
|
||||
|
||||
public function testClonePart(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/en/part/' . $part->getId() . '/clone');
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$this->assertSelectorExists('form[name="part_base"]');
|
||||
}
|
||||
|
||||
public function testMergeParts(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'admin');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$categoryRepository = $entityManager->getRepository(Category::class);
|
||||
$category = $categoryRepository->find(1);
|
||||
|
||||
if (!$category) {
|
||||
$this->markTestSkipped('Test category with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
// Create two test parts
|
||||
$targetPart = new Part();
|
||||
$targetPart->setName('Target Part');
|
||||
$targetPart->setCategory($category);
|
||||
|
||||
$otherPart = new Part();
|
||||
$otherPart->setName('Other Part');
|
||||
$otherPart->setCategory($category);
|
||||
|
||||
$entityManager->persist($targetPart);
|
||||
$entityManager->persist($otherPart);
|
||||
$entityManager->flush();
|
||||
|
||||
$client->request('GET', "/en/part/{$targetPart->getId()}/merge/{$otherPart->getId()}");
|
||||
|
||||
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
|
||||
$this->assertSelectorExists('form[name="part_base"]');
|
||||
|
||||
// Clean up
|
||||
$entityManager->remove($targetPart);
|
||||
$entityManager->remove($otherPart);
|
||||
$entityManager->flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public function testAccessControlForUnauthorizedUser(): void
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->loginAsUser($client, 'noread');
|
||||
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$partRepository = $entityManager->getRepository(Part::class);
|
||||
$part = $partRepository->find(1);
|
||||
|
||||
if (!$part) {
|
||||
$this->markTestSkipped('Test part with ID 1 not found in fixtures');
|
||||
}
|
||||
|
||||
$client->request('GET', '/en/part/' . $part->getId());
|
||||
|
||||
// Should either be forbidden or redirected to error page
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->getStatusCode() === Response::HTTP_FORBIDDEN ||
|
||||
$client->getResponse()->isRedirect()
|
||||
);
|
||||
}
|
||||
|
||||
private function loginAsUser($client, string $username): void
|
||||
{
|
||||
$entityManager = $client->getContainer()->get('doctrine')->getManager();
|
||||
$userRepository = $entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['name' => $username]);
|
||||
|
||||
if (!$user) {
|
||||
$this->markTestSkipped("User {$username} not found");
|
||||
}
|
||||
|
||||
$client->loginUser($user);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -22,16 +22,17 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Depends;
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Repository\UserRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
#[Group('slow')]
|
||||
#[Group('DB')]
|
||||
class RedirectControllerTest extends WebTestCase
|
||||
{
|
||||
protected EntityManagerInterface $em;
|
||||
|
|
@ -50,7 +51,7 @@ class RedirectControllerTest extends WebTestCase
|
|||
$this->userRepo = $this->em->getRepository(User::class);
|
||||
}
|
||||
|
||||
public function urlMatchDataProvider(): \Iterator
|
||||
public static function urlMatchDataProvider(): \Iterator
|
||||
{
|
||||
yield ['/', true];
|
||||
yield ['/part/2/info', true];
|
||||
|
|
@ -64,10 +65,9 @@ class RedirectControllerTest extends WebTestCase
|
|||
|
||||
/**
|
||||
* Test if a certain request to an url will be redirected.
|
||||
*
|
||||
* @dataProvider urlMatchDataProvider
|
||||
* @group slow
|
||||
*/
|
||||
#[DataProvider('urlMatchDataProvider')]
|
||||
#[Group('slow')]
|
||||
public function testUrlMatch($url, $expect_redirect): void
|
||||
{
|
||||
//$client = static::createClient();
|
||||
|
|
@ -79,7 +79,7 @@ class RedirectControllerTest extends WebTestCase
|
|||
$this->assertSame($expect_redirect, $response->isRedirect());
|
||||
}
|
||||
|
||||
public function urlAddLocaleDataProvider(): \Iterator
|
||||
public static function urlAddLocaleDataProvider(): \Iterator
|
||||
{
|
||||
//User locale, original target, redirect target
|
||||
yield ['de', '/', '/de/'];
|
||||
|
|
@ -97,11 +97,10 @@ class RedirectControllerTest extends WebTestCase
|
|||
|
||||
/**
|
||||
* Test if the user is redirected to the localized version of a page, based on his settings.
|
||||
*
|
||||
* @dataProvider urlAddLocaleDataProvider
|
||||
* @group slow
|
||||
* @depends testUrlMatch
|
||||
*/
|
||||
#[Depends('testUrlMatch')]
|
||||
#[DataProvider('urlAddLocaleDataProvider')]
|
||||
#[Group('slow')]
|
||||
public function testAddLocale(?string $user_locale, string $input_path, string $redirect_path): void
|
||||
{
|
||||
//Redirect path is absolute
|
||||
|
|
@ -121,10 +120,9 @@ class RedirectControllerTest extends WebTestCase
|
|||
/**
|
||||
* Test if the user is redirected to the localized version of a page, based on his settings.
|
||||
* We simulate the situation of a reverse proxy here, by adding a prefix to the path.
|
||||
*
|
||||
* @dataProvider urlAddLocaleDataProvider
|
||||
* @group slow
|
||||
*/
|
||||
#[DataProvider('urlAddLocaleDataProvider')]
|
||||
#[Group('slow')]
|
||||
public function testAddLocaleReverseProxy(?string $user_locale, string $input_path, string $redirect_path): void
|
||||
{
|
||||
//Input path remains unchanged, as this is what the server receives from the proxy
|
||||
|
|
@ -147,10 +145,9 @@ class RedirectControllerTest extends WebTestCase
|
|||
/**
|
||||
* Test if the user is redirected to the localized version of a page, based on his settings.
|
||||
* We simulate the situation of serving Part-DB in a subfolder here.
|
||||
*
|
||||
* @dataProvider urlAddLocaleDataProvider
|
||||
* @group slow
|
||||
*/
|
||||
#[DataProvider('urlAddLocaleDataProvider')]
|
||||
#[Group('slow')]
|
||||
public function testAddLocaleSubfolder(?string $user_locale, string $input_path, string $redirect_path): void
|
||||
{
|
||||
//Prefix our path with the proxy prefix
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace App\Tests\DataTables\Filters\Constraints;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\DataTables\Filters\Constraints\FilterTrait;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
|
|
@ -40,7 +41,7 @@ class FilterTraitTest extends TestCase
|
|||
$this->assertFalse($this->useHaving);
|
||||
}
|
||||
|
||||
public function isAggregateFunctionStringDataProvider(): iterable
|
||||
public static function isAggregateFunctionStringDataProvider(): iterable
|
||||
{
|
||||
yield [false, 'parts.test'];
|
||||
yield [false, 'attachments.test'];
|
||||
|
|
@ -48,12 +49,10 @@ class FilterTraitTest extends TestCase
|
|||
yield [true, 'MAX(attachments.value)'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider isAggregateFunctionStringDataProvider
|
||||
*/
|
||||
#[DataProvider('isAggregateFunctionStringDataProvider')]
|
||||
public function testIsAggregateFunctionString(bool $expected, string $input): void
|
||||
{
|
||||
$this->assertEquals($expected, $this->isAggregateFunctionString($input));
|
||||
$this->assertSame($expected, $this->isAggregateFunctionString($input));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,250 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\DataTables\Filters\Constraints\Part;
|
||||
|
||||
use App\DataTables\Filters\Constraints\Part\BulkImportJobStatusConstraint;
|
||||
use App\Entity\InfoProviderSystem\BulkInfoProviderImportJobPart;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BulkImportJobStatusConstraintTest extends TestCase
|
||||
{
|
||||
private BulkImportJobStatusConstraint $constraint;
|
||||
private QueryBuilder $queryBuilder;
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->constraint = new BulkImportJobStatusConstraint();
|
||||
$this->entityManager = $this->createMock(EntityManagerInterface::class);
|
||||
$this->queryBuilder = $this->createMock(QueryBuilder::class);
|
||||
|
||||
$this->queryBuilder->method('getEntityManager')
|
||||
->willReturn($this->entityManager);
|
||||
}
|
||||
|
||||
public function testConstructor(): void
|
||||
{
|
||||
$this->assertEquals([], $this->constraint->getValue());
|
||||
$this->assertEmpty($this->constraint->getOperator());
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
}
|
||||
|
||||
public function testGetAndSetValues(): void
|
||||
{
|
||||
$values = ['pending', 'in_progress'];
|
||||
$this->constraint->setValue($values);
|
||||
|
||||
$this->assertEquals($values, $this->constraint->getValue());
|
||||
}
|
||||
|
||||
public function testGetAndSetOperator(): void
|
||||
{
|
||||
$operator = 'ANY';
|
||||
$this->constraint->setOperator($operator);
|
||||
|
||||
$this->assertEquals($operator, $this->constraint->getOperator());
|
||||
}
|
||||
|
||||
public function testIsEnabledWithEmptyValues(): void
|
||||
{
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
}
|
||||
|
||||
public function testIsEnabledWithNullOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending']);
|
||||
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
}
|
||||
|
||||
public function testIsEnabledWithValuesAndOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending']);
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$this->assertTrue($this->constraint->isEnabled());
|
||||
}
|
||||
|
||||
public function testApplyWithEmptyValues(): void
|
||||
{
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$this->queryBuilder->expects($this->never())
|
||||
->method('andWhere');
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testApplyWithNullOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending']);
|
||||
|
||||
$this->queryBuilder->expects($this->never())
|
||||
->method('andWhere');
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testApplyWithAnyOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending', 'in_progress']);
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
$subQueryBuilder->method('select')->willReturnSelf();
|
||||
$subQueryBuilder->method('from')->willReturnSelf();
|
||||
$subQueryBuilder->method('join')->willReturnSelf();
|
||||
$subQueryBuilder->method('where')->willReturnSelf();
|
||||
$subQueryBuilder->method('andWhere')->willReturnSelf();
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
$this->queryBuilder->expects($this->once())
|
||||
->method('andWhere')
|
||||
->with('EXISTS (EXISTS_SUBQUERY_DQL)');
|
||||
|
||||
$this->queryBuilder->expects($this->once())
|
||||
->method('setParameter')
|
||||
->with('job_status_values', ['pending', 'in_progress']);
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testApplyWithNoneOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['completed']);
|
||||
$this->constraint->setOperator('NONE');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
$subQueryBuilder->method('select')->willReturnSelf();
|
||||
$subQueryBuilder->method('from')->willReturnSelf();
|
||||
$subQueryBuilder->method('join')->willReturnSelf();
|
||||
$subQueryBuilder->method('where')->willReturnSelf();
|
||||
$subQueryBuilder->method('andWhere')->willReturnSelf();
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
$this->queryBuilder->expects($this->once())
|
||||
->method('andWhere')
|
||||
->with('NOT EXISTS (EXISTS_SUBQUERY_DQL)');
|
||||
|
||||
$this->queryBuilder->expects($this->once())
|
||||
->method('setParameter')
|
||||
->with('job_status_values', ['completed']);
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testApplyWithUnsupportedOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending']);
|
||||
$this->constraint->setOperator('UNKNOWN');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
$subQueryBuilder->method('select')->willReturnSelf();
|
||||
$subQueryBuilder->method('from')->willReturnSelf();
|
||||
$subQueryBuilder->method('join')->willReturnSelf();
|
||||
$subQueryBuilder->method('where')->willReturnSelf();
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
// Should not call andWhere for unsupported operator
|
||||
$this->queryBuilder->expects($this->never())
|
||||
->method('andWhere');
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testSubqueryStructure(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending']);
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('select')
|
||||
->with('1')
|
||||
->willReturnSelf();
|
||||
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('from')
|
||||
->with(BulkInfoProviderImportJobPart::class, 'bip_status')
|
||||
->willReturnSelf();
|
||||
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('join')
|
||||
->with('bip_status.job', 'job_status')
|
||||
->willReturnSelf();
|
||||
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('where')
|
||||
->with('bip_status.part = part.id')
|
||||
->willReturnSelf();
|
||||
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('andWhere')
|
||||
->with('job_status.status IN (:job_status_values)')
|
||||
->willReturnSelf();
|
||||
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
$this->queryBuilder->method('andWhere');
|
||||
$this->queryBuilder->method('setParameter');
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testValuesAndOperatorMutation(): void
|
||||
{
|
||||
// Test that values and operator can be changed after creation
|
||||
$this->constraint->setValue(['pending']);
|
||||
$this->constraint->setOperator('ANY');
|
||||
$this->assertTrue($this->constraint->isEnabled());
|
||||
|
||||
$this->constraint->setValue([]);
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
|
||||
$this->constraint->setValue(['completed']);
|
||||
$this->assertTrue($this->constraint->isEnabled());
|
||||
|
||||
$this->constraint->setOperator('');
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
|
||||
$this->constraint->setOperator('NONE');
|
||||
$this->assertTrue($this->constraint->isEnabled());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\DataTables\Filters\Constraints\Part;
|
||||
|
||||
use App\DataTables\Filters\Constraints\Part\BulkImportPartStatusConstraint;
|
||||
use App\Entity\InfoProviderSystem\BulkInfoProviderImportJobPart;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BulkImportPartStatusConstraintTest extends TestCase
|
||||
{
|
||||
private BulkImportPartStatusConstraint $constraint;
|
||||
private QueryBuilder $queryBuilder;
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->constraint = new BulkImportPartStatusConstraint();
|
||||
$this->entityManager = $this->createMock(EntityManagerInterface::class);
|
||||
$this->queryBuilder = $this->createMock(QueryBuilder::class);
|
||||
|
||||
$this->queryBuilder->method('getEntityManager')
|
||||
->willReturn($this->entityManager);
|
||||
}
|
||||
|
||||
public function testConstructor(): void
|
||||
{
|
||||
$this->assertEquals([], $this->constraint->getValue());
|
||||
$this->assertEmpty($this->constraint->getOperator());
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
}
|
||||
|
||||
public function testGetAndSetValues(): void
|
||||
{
|
||||
$values = ['pending', 'completed', 'skipped'];
|
||||
$this->constraint->setValue($values);
|
||||
|
||||
$this->assertEquals($values, $this->constraint->getValue());
|
||||
}
|
||||
|
||||
public function testGetAndSetOperator(): void
|
||||
{
|
||||
$operator = 'ANY';
|
||||
$this->constraint->setOperator($operator);
|
||||
|
||||
$this->assertEquals($operator, $this->constraint->getOperator());
|
||||
}
|
||||
|
||||
public function testIsEnabledWithEmptyValues(): void
|
||||
{
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
}
|
||||
|
||||
public function testIsEnabledWithNullOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending']);
|
||||
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
}
|
||||
|
||||
public function testIsEnabledWithValuesAndOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending']);
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$this->assertTrue($this->constraint->isEnabled());
|
||||
}
|
||||
|
||||
public function testApplyWithEmptyValues(): void
|
||||
{
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$this->queryBuilder->expects($this->never())
|
||||
->method('andWhere');
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testApplyWithNullOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending']);
|
||||
|
||||
$this->queryBuilder->expects($this->never())
|
||||
->method('andWhere');
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testApplyWithAnyOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending', 'completed']);
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
$subQueryBuilder->method('select')->willReturnSelf();
|
||||
$subQueryBuilder->method('from')->willReturnSelf();
|
||||
$subQueryBuilder->method('where')->willReturnSelf();
|
||||
$subQueryBuilder->method('andWhere')->willReturnSelf();
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
$this->queryBuilder->expects($this->once())
|
||||
->method('andWhere')
|
||||
->with('EXISTS (EXISTS_SUBQUERY_DQL)');
|
||||
|
||||
$this->queryBuilder->expects($this->once())
|
||||
->method('setParameter')
|
||||
->with('part_status_values', ['pending', 'completed']);
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testApplyWithNoneOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['failed']);
|
||||
$this->constraint->setOperator('NONE');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
$subQueryBuilder->method('select')->willReturnSelf();
|
||||
$subQueryBuilder->method('from')->willReturnSelf();
|
||||
$subQueryBuilder->method('where')->willReturnSelf();
|
||||
$subQueryBuilder->method('andWhere')->willReturnSelf();
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
$this->queryBuilder->expects($this->once())
|
||||
->method('andWhere')
|
||||
->with('NOT EXISTS (EXISTS_SUBQUERY_DQL)');
|
||||
|
||||
$this->queryBuilder->expects($this->once())
|
||||
->method('setParameter')
|
||||
->with('part_status_values', ['failed']);
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testApplyWithUnsupportedOperator(): void
|
||||
{
|
||||
$this->constraint->setValue(['pending']);
|
||||
$this->constraint->setOperator('UNKNOWN');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
$subQueryBuilder->method('select')->willReturnSelf();
|
||||
$subQueryBuilder->method('from')->willReturnSelf();
|
||||
$subQueryBuilder->method('where')->willReturnSelf();
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
// Should not call andWhere for unsupported operator
|
||||
$this->queryBuilder->expects($this->never())
|
||||
->method('andWhere');
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testSubqueryStructure(): void
|
||||
{
|
||||
$this->constraint->setValue(['completed', 'skipped']);
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('select')
|
||||
->with('1')
|
||||
->willReturnSelf();
|
||||
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('from')
|
||||
->with(BulkInfoProviderImportJobPart::class, 'bip_part_status')
|
||||
->willReturnSelf();
|
||||
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('where')
|
||||
->with('bip_part_status.part = part.id')
|
||||
->willReturnSelf();
|
||||
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('andWhere')
|
||||
->with('bip_part_status.status IN (:part_status_values)')
|
||||
->willReturnSelf();
|
||||
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
$this->queryBuilder->method('andWhere');
|
||||
$this->queryBuilder->method('setParameter');
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testValuesAndOperatorMutation(): void
|
||||
{
|
||||
// Test that values and operator can be changed after creation
|
||||
$this->constraint->setValue(['pending']);
|
||||
$this->constraint->setOperator('ANY');
|
||||
$this->assertTrue($this->constraint->isEnabled());
|
||||
|
||||
$this->constraint->setValue([]);
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
|
||||
$this->constraint->setValue(['completed', 'skipped']);
|
||||
$this->assertTrue($this->constraint->isEnabled());
|
||||
|
||||
$this->constraint->setOperator("");
|
||||
$this->assertFalse($this->constraint->isEnabled());
|
||||
|
||||
$this->constraint->setOperator('NONE');
|
||||
$this->assertTrue($this->constraint->isEnabled());
|
||||
}
|
||||
|
||||
public function testDifferentFromJobStatusConstraint(): void
|
||||
{
|
||||
// This constraint should work differently from BulkImportJobStatusConstraint
|
||||
// It queries the part status directly, not the job status
|
||||
$this->constraint->setValue(['pending']);
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
$subQueryBuilder->method('select')->willReturnSelf();
|
||||
$subQueryBuilder->method('from')->willReturnSelf();
|
||||
$subQueryBuilder->method('where')->willReturnSelf();
|
||||
$subQueryBuilder->method('andWhere')->willReturnSelf();
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
// Should use different alias than job status constraint
|
||||
$subQueryBuilder->expects($this->once())
|
||||
->method('from')
|
||||
->with(BulkInfoProviderImportJobPart::class, 'bip_part_status');
|
||||
|
||||
// Should not join with job table like job status constraint does
|
||||
$subQueryBuilder->expects($this->never())
|
||||
->method('join');
|
||||
|
||||
$this->queryBuilder->method('andWhere');
|
||||
$this->queryBuilder->method('setParameter');
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
}
|
||||
|
||||
public function testMultipleStatusValues(): void
|
||||
{
|
||||
$statusValues = ['pending', 'completed', 'skipped', 'failed'];
|
||||
$this->constraint->setValue($statusValues);
|
||||
$this->constraint->setOperator('ANY');
|
||||
|
||||
$subQueryBuilder = $this->createMock(QueryBuilder::class);
|
||||
$subQueryBuilder->method('select')->willReturnSelf();
|
||||
$subQueryBuilder->method('from')->willReturnSelf();
|
||||
$subQueryBuilder->method('where')->willReturnSelf();
|
||||
$subQueryBuilder->method('andWhere')->willReturnSelf();
|
||||
$subQueryBuilder->method('getDQL')->willReturn('EXISTS_SUBQUERY_DQL');
|
||||
|
||||
$this->entityManager->method('createQueryBuilder')
|
||||
->willReturn($subQueryBuilder);
|
||||
|
||||
$this->queryBuilder->expects($this->once())
|
||||
->method('setParameter')
|
||||
->with('part_status_values', $statusValues);
|
||||
|
||||
$this->constraint->apply($this->queryBuilder);
|
||||
|
||||
$this->assertEquals($statusValues, $this->constraint->getValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -41,13 +41,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class DatatablesAvailabilityTest extends WebTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider urlProvider
|
||||
*/
|
||||
#[DataProvider('urlProvider')]
|
||||
public function testDataTable(string $url, ?array $ordering = null): void
|
||||
{
|
||||
//We have localized routes
|
||||
|
|
@ -80,7 +79,7 @@ class DatatablesAvailabilityTest extends WebTestCase
|
|||
$this->assertJson($client->getResponse()->getContent());
|
||||
}
|
||||
|
||||
public function urlProvider(): ?\Generator
|
||||
public static function urlProvider(): ?\Generator
|
||||
{
|
||||
//Part lists
|
||||
yield ['/category/1/parts'];
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace App\Tests\Doctrine;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Doctrine\Middleware\SQLiteRegexExtensionMiddlewareDriver;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class SQLiteRegexMiddlewareTest extends TestCase
|
||||
{
|
||||
|
||||
public function regexpDataProvider(): \Generator
|
||||
public static function regexpDataProvider(): \Generator
|
||||
{
|
||||
yield [1, 'a', 'a'];
|
||||
yield [0, 'a', 'b'];
|
||||
|
|
@ -41,15 +42,13 @@ class SQLiteRegexMiddlewareTest extends TestCase
|
|||
yield [1, '^a\d+$', 'a123'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider regexpDataProvider
|
||||
*/
|
||||
#[DataProvider('regexpDataProvider')]
|
||||
public function testRegexp(int $expected, string $pattern, string $value): void
|
||||
{
|
||||
$this->assertSame($expected, SQLiteRegexExtensionMiddlewareDriver::regexp($pattern, $value));
|
||||
}
|
||||
|
||||
public function fieldDataProvider(): \Generator
|
||||
public static function fieldDataProvider(): \Generator
|
||||
{
|
||||
|
||||
// Null cases
|
||||
|
|
@ -73,17 +72,13 @@ class SQLiteRegexMiddlewareTest extends TestCase
|
|||
yield [6, 'c', ['b', 'a', 'b', 'a', 'b', 'c']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider fieldDataProvider
|
||||
*/
|
||||
#[DataProvider('fieldDataProvider')]
|
||||
public function testField(int $expected, string|int|null $value, array $array): void
|
||||
{
|
||||
$this->assertSame($expected, SQLiteRegexExtensionMiddlewareDriver::field($value, ...$array));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider fieldDataProvider
|
||||
*/
|
||||
#[DataProvider('fieldDataProvider')]
|
||||
public function testField2(int $expected, string|int|null $value, array $array): void
|
||||
{
|
||||
//Should be the same as field, but with the array comma imploded
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Entity\Attachments;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Depends;
|
||||
use App\Entity\Attachments\Attachment;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
use App\Entity\Attachments\AttachmentTypeAttachment;
|
||||
|
|
@ -73,7 +75,7 @@ class AttachmentTest extends TestCase
|
|||
$this->assertEmpty($attachment->getFilename());
|
||||
}
|
||||
|
||||
public function subClassesDataProvider(): \Iterator
|
||||
public static function subClassesDataProvider(): \Iterator
|
||||
{
|
||||
yield [AttachmentTypeAttachment::class, AttachmentType::class];
|
||||
yield [CategoryAttachment::class, Category::class];
|
||||
|
|
@ -89,9 +91,7 @@ class AttachmentTest extends TestCase
|
|||
yield [UserAttachment::class, User::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider subClassesDataProvider
|
||||
*/
|
||||
#[DataProvider('subClassesDataProvider')]
|
||||
public function testSetElement(string $attachment_class, string $allowed_class): void
|
||||
{
|
||||
/** @var Attachment $attachment */
|
||||
|
|
@ -106,10 +106,9 @@ class AttachmentTest extends TestCase
|
|||
/**
|
||||
* Test that all attachment subclasses like PartAttachment or similar returns an exception, when a not allowed
|
||||
* element is passed.
|
||||
*
|
||||
* @dataProvider subClassesDataProvider
|
||||
* @depends testSetElement
|
||||
*/
|
||||
#[Depends('testSetElement')]
|
||||
#[DataProvider('subClassesDataProvider')]
|
||||
public function testSetElementExceptionOnSubClasses(string $attachment_class, string $allowed_class): void
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
|
|
@ -135,9 +134,7 @@ class AttachmentTest extends TestCase
|
|||
yield [null, 'test.txt', null, null];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider extensionDataProvider
|
||||
*/
|
||||
#[DataProvider('extensionDataProvider')]
|
||||
public function testGetExtension(?string $internal_path, ?string $external_path, ?string $originalFilename, ?string $expected): void
|
||||
{
|
||||
$attachment = new PartAttachment();
|
||||
|
|
@ -162,9 +159,7 @@ class AttachmentTest extends TestCase
|
|||
yield ['%SECURE%/foo.txt/test', 'https://test.de/picture.jpeg', false];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider pictureDataProvider
|
||||
*/
|
||||
#[DataProvider('pictureDataProvider')]
|
||||
public function testIsPicture(?string $internal_path, ?string $external_path, bool $expected): void
|
||||
{
|
||||
$attachment = new PartAttachment();
|
||||
|
|
@ -184,9 +179,7 @@ class AttachmentTest extends TestCase
|
|||
yield ['%FOOTPRINTS%/foo/bar.txt', true];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider builtinDataProvider
|
||||
*/
|
||||
#[DataProvider('builtinDataProvider')]
|
||||
public function testIsBuiltIn(?string $path, $expected): void
|
||||
{
|
||||
$attachment = new PartAttachment();
|
||||
|
|
@ -201,9 +194,7 @@ class AttachmentTest extends TestCase
|
|||
yield ['https://foo.bar/test?txt=test', 'foo.bar'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider hostDataProvider
|
||||
*/
|
||||
#[DataProvider('hostDataProvider')]
|
||||
public function testGetHost(?string $path, ?string $expected): void
|
||||
{
|
||||
$attachment = new PartAttachment();
|
||||
|
|
@ -219,9 +210,7 @@ class AttachmentTest extends TestCase
|
|||
yield [null, 'https://www.google.de/test.txt', null, null];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider filenameProvider
|
||||
*/
|
||||
#[DataProvider('filenameProvider')]
|
||||
public function testGetFilename(?string $internal_path, ?string $external_path, ?string $original_filename, ?string $expected): void
|
||||
{
|
||||
$attachment = new PartAttachment();
|
||||
|
|
@ -242,7 +231,7 @@ class AttachmentTest extends TestCase
|
|||
//Ensure that changing the external path does reset the internal one
|
||||
$attachment->setInternalPath('%MEDIA%/foo/bar.txt');
|
||||
$attachment->setExternalPath('https://example.de');
|
||||
$this->assertSame(null, $attachment->getInternalPath());
|
||||
$this->assertNull($attachment->getInternalPath());
|
||||
|
||||
//Ensure that setting the same value to the external path again doesn't reset the internal one
|
||||
$attachment->setExternalPath('https://google.de');
|
||||
|
|
|
|||
71
tests/Entity/BulkImportJobStatusTest.php
Normal file
71
tests/Entity/BulkImportJobStatusTest.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Entity;
|
||||
|
||||
use App\Entity\InfoProviderSystem\BulkImportJobStatus;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BulkImportJobStatusTest extends TestCase
|
||||
{
|
||||
public function testEnumValues(): void
|
||||
{
|
||||
$this->assertEquals('pending', BulkImportJobStatus::PENDING->value);
|
||||
$this->assertEquals('in_progress', BulkImportJobStatus::IN_PROGRESS->value);
|
||||
$this->assertEquals('completed', BulkImportJobStatus::COMPLETED->value);
|
||||
$this->assertEquals('stopped', BulkImportJobStatus::STOPPED->value);
|
||||
$this->assertEquals('failed', BulkImportJobStatus::FAILED->value);
|
||||
}
|
||||
|
||||
public function testEnumCases(): void
|
||||
{
|
||||
$cases = BulkImportJobStatus::cases();
|
||||
|
||||
$this->assertCount(5, $cases);
|
||||
$this->assertContains(BulkImportJobStatus::PENDING, $cases);
|
||||
$this->assertContains(BulkImportJobStatus::IN_PROGRESS, $cases);
|
||||
$this->assertContains(BulkImportJobStatus::COMPLETED, $cases);
|
||||
$this->assertContains(BulkImportJobStatus::STOPPED, $cases);
|
||||
$this->assertContains(BulkImportJobStatus::FAILED, $cases);
|
||||
}
|
||||
|
||||
public function testFromString(): void
|
||||
{
|
||||
$this->assertEquals(BulkImportJobStatus::PENDING, BulkImportJobStatus::from('pending'));
|
||||
$this->assertEquals(BulkImportJobStatus::IN_PROGRESS, BulkImportJobStatus::from('in_progress'));
|
||||
$this->assertEquals(BulkImportJobStatus::COMPLETED, BulkImportJobStatus::from('completed'));
|
||||
$this->assertEquals(BulkImportJobStatus::STOPPED, BulkImportJobStatus::from('stopped'));
|
||||
$this->assertEquals(BulkImportJobStatus::FAILED, BulkImportJobStatus::from('failed'));
|
||||
}
|
||||
|
||||
public function testTryFromInvalidValue(): void
|
||||
{
|
||||
$this->assertNull(BulkImportJobStatus::tryFrom('invalid'));
|
||||
$this->assertNull(BulkImportJobStatus::tryFrom(''));
|
||||
}
|
||||
|
||||
public function testFromInvalidValueThrowsException(): void
|
||||
{
|
||||
$this->expectException(\ValueError::class);
|
||||
BulkImportJobStatus::from('invalid');
|
||||
}
|
||||
}
|
||||
301
tests/Entity/BulkInfoProviderImportJobPartTest.php
Normal file
301
tests/Entity/BulkInfoProviderImportJobPartTest.php
Normal file
|
|
@ -0,0 +1,301 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Entity;
|
||||
|
||||
use App\Entity\InfoProviderSystem\BulkImportPartStatus;
|
||||
use App\Entity\InfoProviderSystem\BulkInfoProviderImportJob;
|
||||
use App\Entity\InfoProviderSystem\BulkInfoProviderImportJobPart;
|
||||
use App\Entity\Parts\Part;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BulkInfoProviderImportJobPartTest extends TestCase
|
||||
{
|
||||
private BulkInfoProviderImportJob $job;
|
||||
private Part $part;
|
||||
private BulkInfoProviderImportJobPart $jobPart;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->job = $this->createMock(BulkInfoProviderImportJob::class);
|
||||
$this->part = $this->createMock(Part::class);
|
||||
|
||||
$this->jobPart = new BulkInfoProviderImportJobPart($this->job, $this->part);
|
||||
}
|
||||
|
||||
public function testConstructor(): void
|
||||
{
|
||||
$this->assertSame($this->job, $this->jobPart->getJob());
|
||||
$this->assertSame($this->part, $this->jobPart->getPart());
|
||||
$this->assertEquals(BulkImportPartStatus::PENDING, $this->jobPart->getStatus());
|
||||
$this->assertNull($this->jobPart->getReason());
|
||||
$this->assertNull($this->jobPart->getCompletedAt());
|
||||
}
|
||||
|
||||
public function testGetAndSetJob(): void
|
||||
{
|
||||
$newJob = $this->createMock(BulkInfoProviderImportJob::class);
|
||||
|
||||
$result = $this->jobPart->setJob($newJob);
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertSame($newJob, $this->jobPart->getJob());
|
||||
}
|
||||
|
||||
public function testGetAndSetPart(): void
|
||||
{
|
||||
$newPart = $this->createMock(Part::class);
|
||||
|
||||
$result = $this->jobPart->setPart($newPart);
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertSame($newPart, $this->jobPart->getPart());
|
||||
}
|
||||
|
||||
public function testGetAndSetStatus(): void
|
||||
{
|
||||
$result = $this->jobPart->setStatus(BulkImportPartStatus::COMPLETED);
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertEquals(BulkImportPartStatus::COMPLETED, $this->jobPart->getStatus());
|
||||
}
|
||||
|
||||
public function testGetAndSetReason(): void
|
||||
{
|
||||
$reason = 'Test reason';
|
||||
|
||||
$result = $this->jobPart->setReason($reason);
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertEquals($reason, $this->jobPart->getReason());
|
||||
}
|
||||
|
||||
public function testGetAndSetCompletedAt(): void
|
||||
{
|
||||
$completedAt = new \DateTimeImmutable();
|
||||
|
||||
$result = $this->jobPart->setCompletedAt($completedAt);
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertSame($completedAt, $this->jobPart->getCompletedAt());
|
||||
}
|
||||
|
||||
public function testMarkAsCompleted(): void
|
||||
{
|
||||
$beforeTime = new \DateTimeImmutable();
|
||||
|
||||
$result = $this->jobPart->markAsCompleted();
|
||||
|
||||
$afterTime = new \DateTimeImmutable();
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertEquals(BulkImportPartStatus::COMPLETED, $this->jobPart->getStatus());
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $this->jobPart->getCompletedAt());
|
||||
$this->assertGreaterThanOrEqual($beforeTime, $this->jobPart->getCompletedAt());
|
||||
$this->assertLessThanOrEqual($afterTime, $this->jobPart->getCompletedAt());
|
||||
}
|
||||
|
||||
public function testMarkAsSkipped(): void
|
||||
{
|
||||
$reason = 'Skipped for testing';
|
||||
$beforeTime = new \DateTimeImmutable();
|
||||
|
||||
$result = $this->jobPart->markAsSkipped($reason);
|
||||
|
||||
$afterTime = new \DateTimeImmutable();
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertEquals(BulkImportPartStatus::SKIPPED, $this->jobPart->getStatus());
|
||||
$this->assertEquals($reason, $this->jobPart->getReason());
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $this->jobPart->getCompletedAt());
|
||||
$this->assertGreaterThanOrEqual($beforeTime, $this->jobPart->getCompletedAt());
|
||||
$this->assertLessThanOrEqual($afterTime, $this->jobPart->getCompletedAt());
|
||||
}
|
||||
|
||||
public function testMarkAsSkippedWithoutReason(): void
|
||||
{
|
||||
$result = $this->jobPart->markAsSkipped();
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertEquals(BulkImportPartStatus::SKIPPED, $this->jobPart->getStatus());
|
||||
$this->assertEquals('', $this->jobPart->getReason());
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $this->jobPart->getCompletedAt());
|
||||
}
|
||||
|
||||
public function testMarkAsFailed(): void
|
||||
{
|
||||
$reason = 'Failed for testing';
|
||||
$beforeTime = new \DateTimeImmutable();
|
||||
|
||||
$result = $this->jobPart->markAsFailed($reason);
|
||||
|
||||
$afterTime = new \DateTimeImmutable();
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertEquals(BulkImportPartStatus::FAILED, $this->jobPart->getStatus());
|
||||
$this->assertEquals($reason, $this->jobPart->getReason());
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $this->jobPart->getCompletedAt());
|
||||
$this->assertGreaterThanOrEqual($beforeTime, $this->jobPart->getCompletedAt());
|
||||
$this->assertLessThanOrEqual($afterTime, $this->jobPart->getCompletedAt());
|
||||
}
|
||||
|
||||
public function testMarkAsFailedWithoutReason(): void
|
||||
{
|
||||
$result = $this->jobPart->markAsFailed();
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertEquals(BulkImportPartStatus::FAILED, $this->jobPart->getStatus());
|
||||
$this->assertEquals('', $this->jobPart->getReason());
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $this->jobPart->getCompletedAt());
|
||||
}
|
||||
|
||||
public function testMarkAsPending(): void
|
||||
{
|
||||
// First mark as completed to have something to reset
|
||||
$this->jobPart->markAsCompleted();
|
||||
|
||||
$result = $this->jobPart->markAsPending();
|
||||
|
||||
$this->assertSame($this->jobPart, $result);
|
||||
$this->assertEquals(BulkImportPartStatus::PENDING, $this->jobPart->getStatus());
|
||||
$this->assertNull($this->jobPart->getReason());
|
||||
$this->assertNull($this->jobPart->getCompletedAt());
|
||||
}
|
||||
|
||||
public function testIsPending(): void
|
||||
{
|
||||
$this->assertTrue($this->jobPart->isPending());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::COMPLETED);
|
||||
$this->assertFalse($this->jobPart->isPending());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::SKIPPED);
|
||||
$this->assertFalse($this->jobPart->isPending());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::FAILED);
|
||||
$this->assertFalse($this->jobPart->isPending());
|
||||
}
|
||||
|
||||
public function testIsCompleted(): void
|
||||
{
|
||||
$this->assertFalse($this->jobPart->isCompleted());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::COMPLETED);
|
||||
$this->assertTrue($this->jobPart->isCompleted());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::SKIPPED);
|
||||
$this->assertFalse($this->jobPart->isCompleted());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::FAILED);
|
||||
$this->assertFalse($this->jobPart->isCompleted());
|
||||
}
|
||||
|
||||
public function testIsSkipped(): void
|
||||
{
|
||||
$this->assertFalse($this->jobPart->isSkipped());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::SKIPPED);
|
||||
$this->assertTrue($this->jobPart->isSkipped());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::COMPLETED);
|
||||
$this->assertFalse($this->jobPart->isSkipped());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::FAILED);
|
||||
$this->assertFalse($this->jobPart->isSkipped());
|
||||
}
|
||||
|
||||
public function testIsFailed(): void
|
||||
{
|
||||
$this->assertFalse($this->jobPart->isFailed());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::FAILED);
|
||||
$this->assertTrue($this->jobPart->isFailed());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::COMPLETED);
|
||||
$this->assertFalse($this->jobPart->isFailed());
|
||||
|
||||
$this->jobPart->setStatus(BulkImportPartStatus::SKIPPED);
|
||||
$this->assertFalse($this->jobPart->isFailed());
|
||||
}
|
||||
|
||||
public function testBulkImportPartStatusEnum(): void
|
||||
{
|
||||
$this->assertEquals('pending', BulkImportPartStatus::PENDING->value);
|
||||
$this->assertEquals('completed', BulkImportPartStatus::COMPLETED->value);
|
||||
$this->assertEquals('skipped', BulkImportPartStatus::SKIPPED->value);
|
||||
$this->assertEquals('failed', BulkImportPartStatus::FAILED->value);
|
||||
}
|
||||
|
||||
public function testStatusTransitions(): void
|
||||
{
|
||||
// Test pending -> completed
|
||||
$this->assertTrue($this->jobPart->isPending());
|
||||
$this->jobPart->markAsCompleted();
|
||||
$this->assertTrue($this->jobPart->isCompleted());
|
||||
|
||||
// Test completed -> pending
|
||||
$this->jobPart->markAsPending();
|
||||
$this->assertTrue($this->jobPart->isPending());
|
||||
|
||||
// Test pending -> skipped
|
||||
$this->jobPart->markAsSkipped('Test reason');
|
||||
$this->assertTrue($this->jobPart->isSkipped());
|
||||
|
||||
// Test skipped -> pending
|
||||
$this->jobPart->markAsPending();
|
||||
$this->assertTrue($this->jobPart->isPending());
|
||||
|
||||
// Test pending -> failed
|
||||
$this->jobPart->markAsFailed('Test error');
|
||||
$this->assertTrue($this->jobPart->isFailed());
|
||||
|
||||
// Test failed -> pending
|
||||
$this->jobPart->markAsPending();
|
||||
$this->assertTrue($this->jobPart->isPending());
|
||||
}
|
||||
|
||||
public function testReasonAndCompletedAtConsistency(): void
|
||||
{
|
||||
// Initially no reason or completion time
|
||||
$this->assertNull($this->jobPart->getReason());
|
||||
$this->assertNull($this->jobPart->getCompletedAt());
|
||||
|
||||
// After marking as skipped, should have reason and completion time
|
||||
$this->jobPart->markAsSkipped('Skipped reason');
|
||||
$this->assertEquals('Skipped reason', $this->jobPart->getReason());
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $this->jobPart->getCompletedAt());
|
||||
|
||||
// After marking as pending, reason and completion time should be cleared
|
||||
$this->jobPart->markAsPending();
|
||||
$this->assertNull($this->jobPart->getReason());
|
||||
$this->assertNull($this->jobPart->getCompletedAt());
|
||||
|
||||
// After marking as failed, should have reason and completion time
|
||||
$this->jobPart->markAsFailed('Failed reason');
|
||||
$this->assertEquals('Failed reason', $this->jobPart->getReason());
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $this->jobPart->getCompletedAt());
|
||||
|
||||
// After marking as completed, should have completion time (reason may remain from previous state)
|
||||
$this->jobPart->markAsCompleted();
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $this->jobPart->getCompletedAt());
|
||||
}
|
||||
}
|
||||
368
tests/Entity/BulkInfoProviderImportJobTest.php
Normal file
368
tests/Entity/BulkInfoProviderImportJobTest.php
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Entity;
|
||||
|
||||
use App\Entity\InfoProviderSystem\BulkImportJobStatus;
|
||||
use App\Entity\InfoProviderSystem\BulkInfoProviderImportJob;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchResponseDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BulkInfoProviderImportJobTest extends TestCase
|
||||
{
|
||||
private BulkInfoProviderImportJob $job;
|
||||
private User $user;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->user = new User();
|
||||
$this->user->setName('test_user');
|
||||
|
||||
$this->job = new BulkInfoProviderImportJob();
|
||||
$this->job->setCreatedBy($this->user);
|
||||
}
|
||||
|
||||
private function createMockPart(int $id): \App\Entity\Parts\Part
|
||||
{
|
||||
$part = $this->createMock(\App\Entity\Parts\Part::class);
|
||||
$part->method('getId')->willReturn($id);
|
||||
$part->method('getName')->willReturn("Test Part {$id}");
|
||||
return $part;
|
||||
}
|
||||
|
||||
public function testConstruct(): void
|
||||
{
|
||||
$job = new BulkInfoProviderImportJob();
|
||||
|
||||
$this->assertInstanceOf(\DateTimeImmutable::class, $job->getCreatedAt());
|
||||
$this->assertEquals(BulkImportJobStatus::PENDING, $job->getStatus());
|
||||
$this->assertEmpty($job->getPartIds());
|
||||
$this->assertEmpty($job->getFieldMappings());
|
||||
$this->assertEmpty($job->getSearchResultsRaw());
|
||||
$this->assertEmpty($job->getProgress());
|
||||
$this->assertNull($job->getCompletedAt());
|
||||
$this->assertFalse($job->isPrefetchDetails());
|
||||
}
|
||||
|
||||
public function testBasicGettersSetters(): void
|
||||
{
|
||||
$this->job->setName('Test Job');
|
||||
$this->assertEquals('Test Job', $this->job->getName());
|
||||
|
||||
// Test with actual parts - this is what actually works
|
||||
$parts = [$this->createMockPart(1), $this->createMockPart(2), $this->createMockPart(3)];
|
||||
foreach ($parts as $part) {
|
||||
$this->job->addPart($part);
|
||||
}
|
||||
$this->assertEquals([1, 2, 3], $this->job->getPartIds());
|
||||
|
||||
$fieldMappings = [new BulkSearchFieldMappingDTO(field: 'field1', providers: ['provider1', 'provider2'])];
|
||||
$this->job->setFieldMappings($fieldMappings);
|
||||
$this->assertEquals($fieldMappings, $this->job->getFieldMappings());
|
||||
|
||||
$this->job->setPrefetchDetails(true);
|
||||
$this->assertTrue($this->job->isPrefetchDetails());
|
||||
|
||||
$this->assertEquals($this->user, $this->job->getCreatedBy());
|
||||
}
|
||||
|
||||
public function testStatusTransitions(): void
|
||||
{
|
||||
$this->assertTrue($this->job->isPending());
|
||||
$this->assertFalse($this->job->isInProgress());
|
||||
$this->assertFalse($this->job->isCompleted());
|
||||
$this->assertFalse($this->job->isFailed());
|
||||
$this->assertFalse($this->job->isStopped());
|
||||
|
||||
$this->job->markAsInProgress();
|
||||
$this->assertEquals(BulkImportJobStatus::IN_PROGRESS, $this->job->getStatus());
|
||||
$this->assertTrue($this->job->isInProgress());
|
||||
$this->assertFalse($this->job->isPending());
|
||||
|
||||
$this->job->markAsCompleted();
|
||||
$this->assertEquals(BulkImportJobStatus::COMPLETED, $this->job->getStatus());
|
||||
$this->assertTrue($this->job->isCompleted());
|
||||
$this->assertNotNull($this->job->getCompletedAt());
|
||||
|
||||
$job2 = new BulkInfoProviderImportJob();
|
||||
$job2->markAsFailed();
|
||||
$this->assertEquals(BulkImportJobStatus::FAILED, $job2->getStatus());
|
||||
$this->assertTrue($job2->isFailed());
|
||||
$this->assertNotNull($job2->getCompletedAt());
|
||||
|
||||
$job3 = new BulkInfoProviderImportJob();
|
||||
$job3->markAsStopped();
|
||||
$this->assertEquals(BulkImportJobStatus::STOPPED, $job3->getStatus());
|
||||
$this->assertTrue($job3->isStopped());
|
||||
$this->assertNotNull($job3->getCompletedAt());
|
||||
}
|
||||
|
||||
public function testCanBeStopped(): void
|
||||
{
|
||||
$this->assertTrue($this->job->canBeStopped());
|
||||
|
||||
$this->job->markAsInProgress();
|
||||
$this->assertTrue($this->job->canBeStopped());
|
||||
|
||||
$this->job->markAsCompleted();
|
||||
$this->assertFalse($this->job->canBeStopped());
|
||||
|
||||
$this->job->setStatus(BulkImportJobStatus::FAILED);
|
||||
$this->assertFalse($this->job->canBeStopped());
|
||||
|
||||
$this->job->setStatus(BulkImportJobStatus::STOPPED);
|
||||
$this->assertFalse($this->job->canBeStopped());
|
||||
}
|
||||
|
||||
public function testPartCount(): void
|
||||
{
|
||||
$this->assertEquals(0, $this->job->getPartCount());
|
||||
|
||||
// Test with actual parts - setPartIds doesn't actually add parts
|
||||
$parts = [
|
||||
$this->createMockPart(1),
|
||||
$this->createMockPart(2),
|
||||
$this->createMockPart(3),
|
||||
$this->createMockPart(4),
|
||||
$this->createMockPart(5)
|
||||
];
|
||||
foreach ($parts as $part) {
|
||||
$this->job->addPart($part);
|
||||
}
|
||||
$this->assertEquals(5, $this->job->getPartCount());
|
||||
}
|
||||
|
||||
public function testResultCount(): void
|
||||
{
|
||||
$this->assertEquals(0, $this->job->getResultCount());
|
||||
|
||||
$searchResults = new BulkSearchResponseDTO([
|
||||
new \App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultsDTO(
|
||||
part: $this->createMockPart(1),
|
||||
searchResults: [new BulkSearchPartResultDTO(searchResult: new SearchResultDTO(provider_key: 'dummy', provider_id: '1234', name: 'Part 1', description: 'A part'))]
|
||||
),
|
||||
new \App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultsDTO(
|
||||
part: $this->createMockPart(2),
|
||||
searchResults: [new BulkSearchPartResultDTO(searchResult: new SearchResultDTO(provider_key: 'dummy', provider_id: '1234', name: 'Part 2', description: 'A part')),
|
||||
new BulkSearchPartResultDTO(searchResult: new SearchResultDTO(provider_key: 'dummy', provider_id: '5678', name: 'Part 2 Alt', description: 'Another part'))]
|
||||
),
|
||||
new \App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultsDTO(
|
||||
part: $this->createMockPart(3),
|
||||
searchResults: []
|
||||
)
|
||||
]);
|
||||
|
||||
$this->job->setSearchResults($searchResults);
|
||||
$this->assertEquals(3, $this->job->getResultCount());
|
||||
}
|
||||
|
||||
public function testPartProgressTracking(): void
|
||||
{
|
||||
// Test with actual parts - setPartIds doesn't actually add parts
|
||||
$parts = [
|
||||
$this->createMockPart(1),
|
||||
$this->createMockPart(2),
|
||||
$this->createMockPart(3),
|
||||
$this->createMockPart(4)
|
||||
];
|
||||
foreach ($parts as $part) {
|
||||
$this->job->addPart($part);
|
||||
}
|
||||
|
||||
$this->assertFalse($this->job->isPartCompleted(1));
|
||||
$this->assertFalse($this->job->isPartSkipped(1));
|
||||
|
||||
$this->job->markPartAsCompleted(1);
|
||||
$this->assertTrue($this->job->isPartCompleted(1));
|
||||
$this->assertFalse($this->job->isPartSkipped(1));
|
||||
|
||||
$this->job->markPartAsSkipped(2, 'Not found');
|
||||
$this->assertFalse($this->job->isPartCompleted(2));
|
||||
$this->assertTrue($this->job->isPartSkipped(2));
|
||||
|
||||
$this->job->markPartAsPending(1);
|
||||
$this->assertFalse($this->job->isPartCompleted(1));
|
||||
$this->assertFalse($this->job->isPartSkipped(1));
|
||||
}
|
||||
|
||||
public function testProgressCounts(): void
|
||||
{
|
||||
// Test with actual parts - setPartIds doesn't actually add parts
|
||||
$parts = [
|
||||
$this->createMockPart(1),
|
||||
$this->createMockPart(2),
|
||||
$this->createMockPart(3),
|
||||
$this->createMockPart(4),
|
||||
$this->createMockPart(5)
|
||||
];
|
||||
foreach ($parts as $part) {
|
||||
$this->job->addPart($part);
|
||||
}
|
||||
|
||||
$this->assertEquals(0, $this->job->getCompletedPartsCount());
|
||||
$this->assertEquals(0, $this->job->getSkippedPartsCount());
|
||||
|
||||
$this->job->markPartAsCompleted(1);
|
||||
$this->job->markPartAsCompleted(2);
|
||||
$this->job->markPartAsSkipped(3, 'Error');
|
||||
|
||||
$this->assertEquals(2, $this->job->getCompletedPartsCount());
|
||||
$this->assertEquals(1, $this->job->getSkippedPartsCount());
|
||||
}
|
||||
|
||||
public function testProgressPercentage(): void
|
||||
{
|
||||
$emptyJob = new BulkInfoProviderImportJob();
|
||||
$this->assertEquals(100.0, $emptyJob->getProgressPercentage());
|
||||
|
||||
// Test with actual parts - setPartIds doesn't actually add parts
|
||||
$parts = [
|
||||
$this->createMockPart(1),
|
||||
$this->createMockPart(2),
|
||||
$this->createMockPart(3),
|
||||
$this->createMockPart(4),
|
||||
$this->createMockPart(5)
|
||||
];
|
||||
foreach ($parts as $part) {
|
||||
$this->job->addPart($part);
|
||||
}
|
||||
|
||||
$this->assertEquals(0.0, $this->job->getProgressPercentage());
|
||||
|
||||
$this->job->markPartAsCompleted(1);
|
||||
$this->job->markPartAsCompleted(2);
|
||||
$this->assertEquals(40.0, $this->job->getProgressPercentage());
|
||||
|
||||
$this->job->markPartAsSkipped(3, 'Error');
|
||||
$this->assertEquals(60.0, $this->job->getProgressPercentage());
|
||||
|
||||
$this->job->markPartAsCompleted(4);
|
||||
$this->job->markPartAsCompleted(5);
|
||||
$this->assertEquals(100.0, $this->job->getProgressPercentage());
|
||||
}
|
||||
|
||||
public function testIsAllPartsCompleted(): void
|
||||
{
|
||||
$emptyJob = new BulkInfoProviderImportJob();
|
||||
$this->assertTrue($emptyJob->isAllPartsCompleted());
|
||||
|
||||
// Test with actual parts - setPartIds doesn't actually add parts
|
||||
$parts = [
|
||||
$this->createMockPart(1),
|
||||
$this->createMockPart(2),
|
||||
$this->createMockPart(3)
|
||||
];
|
||||
foreach ($parts as $part) {
|
||||
$this->job->addPart($part);
|
||||
}
|
||||
|
||||
$this->assertFalse($this->job->isAllPartsCompleted());
|
||||
|
||||
$this->job->markPartAsCompleted(1);
|
||||
$this->assertFalse($this->job->isAllPartsCompleted());
|
||||
|
||||
$this->job->markPartAsCompleted(2);
|
||||
$this->job->markPartAsSkipped(3, 'Error');
|
||||
$this->assertTrue($this->job->isAllPartsCompleted());
|
||||
}
|
||||
|
||||
public function testDisplayNameMethods(): void
|
||||
{
|
||||
// Test with actual parts - setPartIds doesn't actually add parts
|
||||
$parts = [
|
||||
$this->createMockPart(1),
|
||||
$this->createMockPart(2),
|
||||
$this->createMockPart(3)
|
||||
];
|
||||
foreach ($parts as $part) {
|
||||
$this->job->addPart($part);
|
||||
}
|
||||
|
||||
$this->assertEquals('info_providers.bulk_import.job_name_template', $this->job->getDisplayNameKey());
|
||||
$this->assertEquals(['%count%' => 3], $this->job->getDisplayNameParams());
|
||||
}
|
||||
|
||||
public function testFormattedTimestamp(): void
|
||||
{
|
||||
$timestampRegex = '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/';
|
||||
$this->assertMatchesRegularExpression($timestampRegex, $this->job->getFormattedTimestamp());
|
||||
}
|
||||
|
||||
public function testProgressDataStructure(): void
|
||||
{
|
||||
$parts = [
|
||||
$this->createMockPart(1),
|
||||
$this->createMockPart(2),
|
||||
$this->createMockPart(3)
|
||||
];
|
||||
foreach ($parts as $part) {
|
||||
$this->job->addPart($part);
|
||||
}
|
||||
|
||||
$this->job->markPartAsCompleted(1);
|
||||
$this->job->markPartAsSkipped(2, 'Test reason');
|
||||
|
||||
$progress = $this->job->getProgress();
|
||||
|
||||
// The progress array should have keys for all part IDs, even if not completed/skipped
|
||||
$this->assertArrayHasKey(1, $progress, 'Progress should contain key for part 1');
|
||||
$this->assertArrayHasKey(2, $progress, 'Progress should contain key for part 2');
|
||||
$this->assertArrayHasKey(3, $progress, 'Progress should contain key for part 3');
|
||||
|
||||
// Part 1: completed
|
||||
$this->assertEquals('completed', $progress[1]['status']);
|
||||
$this->assertArrayHasKey('completed_at', $progress[1]);
|
||||
$this->assertArrayNotHasKey('reason', $progress[1]);
|
||||
|
||||
// Part 2: skipped
|
||||
$this->assertEquals('skipped', $progress[2]['status']);
|
||||
$this->assertEquals('Test reason', $progress[2]['reason']);
|
||||
$this->assertArrayHasKey('completed_at', $progress[2]);
|
||||
|
||||
// Part 3: should be present but not completed/skipped
|
||||
$this->assertEquals('pending', $progress[3]['status']);
|
||||
$this->assertArrayNotHasKey('completed_at', $progress[3]);
|
||||
$this->assertArrayNotHasKey('reason', $progress[3]);
|
||||
}
|
||||
|
||||
public function testCompletedAtTimestamp(): void
|
||||
{
|
||||
$this->assertNull($this->job->getCompletedAt());
|
||||
|
||||
$beforeCompletion = new \DateTimeImmutable();
|
||||
$this->job->markAsCompleted();
|
||||
$afterCompletion = new \DateTimeImmutable();
|
||||
|
||||
$completedAt = $this->job->getCompletedAt();
|
||||
$this->assertNotNull($completedAt);
|
||||
$this->assertGreaterThanOrEqual($beforeCompletion, $completedAt);
|
||||
$this->assertLessThanOrEqual($afterCompletion, $completedAt);
|
||||
|
||||
$customTime = new \DateTimeImmutable('2023-01-01 12:00:00');
|
||||
$this->job->setCompletedAt($customTime);
|
||||
$this->assertEquals($customTime, $this->job->getCompletedAt());
|
||||
}
|
||||
}
|
||||
|
|
@ -41,12 +41,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Entity\Parameters;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Parameters\PartParameter;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class PartParameterTest extends TestCase
|
||||
{
|
||||
public function valueWithUnitDataProvider(): \Iterator
|
||||
public static function valueWithUnitDataProvider(): \Iterator
|
||||
{
|
||||
yield ['1', 1.0, ''];
|
||||
yield ['1 V', 1.0, 'V'];
|
||||
|
|
@ -54,7 +55,7 @@ class PartParameterTest extends TestCase
|
|||
yield ['1.23 V', 1.23, 'V'];
|
||||
}
|
||||
|
||||
public function formattedValueDataProvider(): \Iterator
|
||||
public static function formattedValueDataProvider(): \Iterator
|
||||
{
|
||||
yield ['Text Test', null, null, null, 'V', 'Text Test'];
|
||||
yield ['10.23 V', null, 10.23, null, 'V', ''];
|
||||
|
|
@ -67,7 +68,7 @@ class PartParameterTest extends TestCase
|
|||
yield ['10.23 V (9 V ... 11 V) [Test]', 9, 10.23, 11, 'V', 'Test'];
|
||||
}
|
||||
|
||||
public function formattedValueWithLatexDataProvider(): \Iterator
|
||||
public static function formattedValueWithLatexDataProvider(): \Iterator
|
||||
{
|
||||
yield ['Text Test', null, null, null, 'V', 'Text Test'];
|
||||
yield ['10.23 $\mathrm{V}$', null, 10.23, null, 'V', ''];
|
||||
|
|
@ -80,9 +81,7 @@ class PartParameterTest extends TestCase
|
|||
yield ['10.23 $\mathrm{V}$ (9 $\mathrm{V}$ ... 11 $\mathrm{V}$) [Test]', 9, 10.23, 11, 'V', 'Test'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider valueWithUnitDataProvider
|
||||
*/
|
||||
#[DataProvider('valueWithUnitDataProvider')]
|
||||
public function testGetValueMinWithUnit(string $expected, float $value, string $unit): void
|
||||
{
|
||||
$param = new PartParameter();
|
||||
|
|
@ -91,9 +90,7 @@ class PartParameterTest extends TestCase
|
|||
$this->assertSame($expected, $param->getValueMinWithUnit());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider valueWithUnitDataProvider
|
||||
*/
|
||||
#[DataProvider('valueWithUnitDataProvider')]
|
||||
public function testGetValueMaxWithUnit(string $expected, float $value, string $unit): void
|
||||
{
|
||||
$param = new PartParameter();
|
||||
|
|
@ -102,9 +99,7 @@ class PartParameterTest extends TestCase
|
|||
$this->assertSame($expected, $param->getValueMaxWithUnit());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider valueWithUnitDataProvider
|
||||
*/
|
||||
#[DataProvider('valueWithUnitDataProvider')]
|
||||
public function testGetValueTypicalWithUnit(string $expected, float $value, string $unit): void
|
||||
{
|
||||
$param = new PartParameter();
|
||||
|
|
@ -114,12 +109,12 @@ class PartParameterTest extends TestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @dataProvider formattedValueDataProvider
|
||||
*
|
||||
* @param float $min
|
||||
* @param float $typical
|
||||
* @param float $max
|
||||
*/
|
||||
#[DataProvider('formattedValueDataProvider')]
|
||||
public function testGetFormattedValue(string $expected, ?float $min, ?float $typical, ?float $max, string $unit, string $text): void
|
||||
{
|
||||
$param = new PartParameter();
|
||||
|
|
@ -132,12 +127,12 @@ class PartParameterTest extends TestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @dataProvider formattedValueWithLatexDataProvider
|
||||
*
|
||||
* @param float $min
|
||||
* @param float $typical
|
||||
* @param float $max
|
||||
*/
|
||||
#[DataProvider('formattedValueWithLatexDataProvider')]
|
||||
public function testGetFormattedValueWithLatex(string $expected, ?float $min, ?float $typical, ?float $max, string $unit, string $text): void
|
||||
{
|
||||
$param = new PartParameter();
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class PartTest extends TestCase
|
|||
$lot = new PartLot();
|
||||
$part->addPartLot($lot);
|
||||
$this->assertSame($part, $lot->getPart());
|
||||
$this->assertSame(1, $part->getPartLots()->count());
|
||||
$this->assertCount(1, $part->getPartLots());
|
||||
|
||||
//Remove element
|
||||
$part->removePartLot($lot);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class OrderdetailTest extends TestCase
|
|||
$pricedetail = new Pricedetail();
|
||||
$orderdetail->addPricedetail($pricedetail);
|
||||
$this->assertSame($orderdetail, $pricedetail->getOrderdetail());
|
||||
$this->assertSame(1, $orderdetail->getPricedetails()->count());
|
||||
$this->assertCount(1, $orderdetail->getPricedetails());
|
||||
|
||||
//After removal of the pricedetail, the orderdetail must be empty again
|
||||
$orderdetail->removePricedetail($pricedetail);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class ApiTokenTypeTest extends TestCase
|
|||
|
||||
public function testGetTypeFromToken(): void
|
||||
{
|
||||
$this->assertEquals(ApiTokenType::PERSONAL_ACCESS_TOKEN, ApiTokenType::getTypeFromToken('tcp_123'));
|
||||
$this->assertSame(ApiTokenType::PERSONAL_ACCESS_TOKEN, ApiTokenType::getTypeFromToken('tcp_123'));
|
||||
}
|
||||
|
||||
public function testGetTypeFromTokenInvalid(): void
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Entity\UserSystem;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\RequiresPhpunit;
|
||||
use App\Entity\UserSystem\User;
|
||||
use App\Entity\UserSystem\WebauthnKey;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
|
|
@ -45,16 +47,14 @@ class UserTest extends TestCase
|
|||
$this->assertSame('John (@username)', $user->getFullName(true));
|
||||
}
|
||||
|
||||
public function googleAuthenticatorEnabledDataProvider(): \Iterator
|
||||
public static function googleAuthenticatorEnabledDataProvider(): \Iterator
|
||||
{
|
||||
yield [null, false];
|
||||
yield ['', false];
|
||||
yield ['SSSk38498', true];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider googleAuthenticatorEnabledDataProvider
|
||||
*/
|
||||
#[DataProvider('googleAuthenticatorEnabledDataProvider')]
|
||||
public function testIsGoogleAuthenticatorEnabled(?string $secret, bool $expected): void
|
||||
{
|
||||
$user = new User();
|
||||
|
|
@ -62,9 +62,7 @@ class UserTest extends TestCase
|
|||
$this->assertSame($expected, $user->isGoogleAuthenticatorEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHPUnit 8
|
||||
*/
|
||||
//#[RequiresPhpunit('8')]
|
||||
public function testSetBackupCodes(): void
|
||||
{
|
||||
$user = new User();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
|
|
@ -17,7 +20,6 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Exceptions;
|
||||
|
||||
use App\Exceptions\TwigModeException;
|
||||
|
|
|
|||
68
tests/Form/InfoProviderSystem/GlobalFieldMappingTypeTest.php
Normal file
68
tests/Form/InfoProviderSystem/GlobalFieldMappingTypeTest.php
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Form\InfoProviderSystem;
|
||||
|
||||
use App\Form\InfoProviderSystem\GlobalFieldMappingType;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
|
||||
/**
|
||||
* @group slow
|
||||
* @group DB
|
||||
*/
|
||||
class GlobalFieldMappingTypeTest extends KernelTestCase
|
||||
{
|
||||
private FormFactoryInterface $formFactory;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
$this->formFactory = static::getContainer()->get(FormFactoryInterface::class);
|
||||
}
|
||||
|
||||
public function testFormCreation(): void
|
||||
{
|
||||
$form = $this->formFactory->create(GlobalFieldMappingType::class, null, [
|
||||
'field_choices' => [
|
||||
'MPN' => 'mpn',
|
||||
'Name' => 'name'
|
||||
],
|
||||
'csrf_protection' => false
|
||||
]);
|
||||
|
||||
$this->assertTrue($form->has('field_mappings'));
|
||||
$this->assertTrue($form->has('prefetch_details'));
|
||||
$this->assertTrue($form->has('submit'));
|
||||
}
|
||||
|
||||
public function testFormOptions(): void
|
||||
{
|
||||
$form = $this->formFactory->create(GlobalFieldMappingType::class, null, [
|
||||
'field_choices' => [],
|
||||
'csrf_protection' => false
|
||||
]);
|
||||
|
||||
$view = $form->createView();
|
||||
$this->assertFalse($view['prefetch_details']->vars['required']);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Helpers;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Helpers\BBCodeToMarkdownConverter;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
|
|
@ -34,7 +35,7 @@ class BBCodeToMarkdownConverterTest extends TestCase
|
|||
$this->converter = new BBCodeToMarkdownConverter();
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
yield ['[b]Bold[/b]', '**Bold**'];
|
||||
yield ['[i]Italic[/i]', '*Italic*'];
|
||||
|
|
@ -46,11 +47,11 @@ class BBCodeToMarkdownConverterTest extends TestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*
|
||||
* @param $bbcode
|
||||
* @param $expected
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testConvert($bbcode, $expected): void
|
||||
{
|
||||
$this->assertSame($expected, $this->converter->convert($bbcode));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
|
|
@ -17,16 +20,16 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Helpers;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Helpers\IPAnonymizer;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class IPAnonymizerTest extends TestCase
|
||||
{
|
||||
|
||||
public function anonymizeDataProvider(): \Generator
|
||||
public static function anonymizeDataProvider(): \Generator
|
||||
{
|
||||
yield ['127.0.0.0', '127.0.0.23'];
|
||||
yield ['2001:db8:85a3::', '2001:0db8:85a3:0000:0000:8a2e:0370:7334'];
|
||||
|
|
@ -34,9 +37,7 @@ class IPAnonymizerTest extends TestCase
|
|||
yield ['fe80::', 'fe80::1fc4:15d8:78db:2319%enp4s0'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider anonymizeDataProvider
|
||||
*/
|
||||
#[DataProvider('anonymizeDataProvider')]
|
||||
public function testAnonymize(string $expected, string $input): void
|
||||
{
|
||||
$this->assertSame($expected, IPAnonymizer::anonymize($input));
|
||||
|
|
|
|||
|
|
@ -33,9 +33,6 @@ use PHPUnit\Framework\TestCase;
|
|||
class ProjectBuildRequestTest extends TestCase
|
||||
{
|
||||
|
||||
/** @var MeasurementUnit $float_unit */
|
||||
private MeasurementUnit $float_unit;
|
||||
|
||||
/** @var Project */
|
||||
private Project $project1;
|
||||
/** @var ProjectBOMEntry */
|
||||
|
|
@ -49,30 +46,25 @@ class ProjectBuildRequestTest extends TestCase
|
|||
private PartLot $lot1b;
|
||||
private PartLot $lot2;
|
||||
|
||||
/** @var Part */
|
||||
private Part $part1;
|
||||
/** @var Part */
|
||||
private Part $part2;
|
||||
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->float_unit = new MeasurementUnit();
|
||||
$this->float_unit->setName('float');
|
||||
$this->float_unit->setUnit('f');
|
||||
$this->float_unit->setIsInteger(false);
|
||||
$this->float_unit->setUseSIPrefix(true);
|
||||
$float_unit = new MeasurementUnit();
|
||||
$float_unit->setName('float');
|
||||
$float_unit->setUnit('f');
|
||||
$float_unit->setIsInteger(false);
|
||||
$float_unit->setUseSIPrefix(true);
|
||||
|
||||
//Setup some example parts and part lots
|
||||
$this->part1 = new Part();
|
||||
$this->part1->setName('Part 1');
|
||||
$part1 = new Part();
|
||||
$part1->setName('Part 1');
|
||||
$this->lot1a = new class extends PartLot {
|
||||
public function getID(): ?int
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
$this->part1->addPartLot($this->lot1a);
|
||||
$part1->addPartLot($this->lot1a);
|
||||
$this->lot1a->setAmount(10);
|
||||
$this->lot1a->setDescription('Lot 1a');
|
||||
|
||||
|
|
@ -82,25 +74,25 @@ class ProjectBuildRequestTest extends TestCase
|
|||
return 2;
|
||||
}
|
||||
};
|
||||
$this->part1->addPartLot($this->lot1b);
|
||||
$part1->addPartLot($this->lot1b);
|
||||
$this->lot1b->setAmount(20);
|
||||
$this->lot1b->setDescription('Lot 1b');
|
||||
|
||||
$this->part2 = new Part();
|
||||
$part2 = new Part();
|
||||
|
||||
$this->part2->setName('Part 2');
|
||||
$this->part2->setPartUnit($this->float_unit);
|
||||
$part2->setName('Part 2');
|
||||
$part2->setPartUnit($float_unit);
|
||||
$this->lot2 = new PartLot();
|
||||
$this->part2->addPartLot($this->lot2);
|
||||
$part2->addPartLot($this->lot2);
|
||||
$this->lot2->setAmount(2.5);
|
||||
$this->lot2->setDescription('Lot 2');
|
||||
|
||||
$this->bom_entry1a = new ProjectBOMEntry();
|
||||
$this->bom_entry1a->setPart($this->part1);
|
||||
$this->bom_entry1a->setPart($part1);
|
||||
$this->bom_entry1a->setQuantity(2);
|
||||
|
||||
$this->bom_entry1b = new ProjectBOMEntry();
|
||||
$this->bom_entry1b->setPart($this->part2);
|
||||
$this->bom_entry1b->setPart($part2);
|
||||
$this->bom_entry1b->setQuantity(1.5);
|
||||
|
||||
$this->bom_entry1c = new ProjectBOMEntry();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
|
|
@ -17,7 +20,6 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Repository;
|
||||
|
||||
use App\Entity\LogSystem\AbstractLogEntry;
|
||||
|
|
@ -110,7 +112,8 @@ class LogEntryRepositoryTest extends KernelTestCase
|
|||
$this->assertCount(2, $logs);
|
||||
|
||||
//The first one must be newer than the second one
|
||||
$this->assertGreaterThanOrEqual($logs[0]->getTimestamp(), $logs[1]->getTimestamp());
|
||||
$this->assertGreaterThanOrEqual($logs[1]->getTimestamp(), $logs[0]->getTimestamp());
|
||||
$this->assertGreaterThanOrEqual($logs[1]->getID(), $logs[0]->getID());
|
||||
}
|
||||
|
||||
public function testGetElementExistedAtTimestamp(): void
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|||
*/
|
||||
class NamedDBElementRepositoryTest extends WebTestCase
|
||||
{
|
||||
private $entityManager;
|
||||
/**
|
||||
* @var StructuralDBElementRepository
|
||||
*/
|
||||
|
|
@ -42,11 +41,11 @@ class NamedDBElementRepositoryTest extends WebTestCase
|
|||
{
|
||||
$kernel = self::bootKernel();
|
||||
|
||||
$this->entityManager = $kernel->getContainer()
|
||||
$entityManager = $kernel->getContainer()
|
||||
->get('doctrine')
|
||||
->getManager();
|
||||
|
||||
$this->repo = $this->entityManager->getRepository(User::class);
|
||||
$this->repo = $entityManager->getRepository(User::class);
|
||||
}
|
||||
|
||||
public function testGetGenericNodeTree(): void
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|||
*/
|
||||
class StructuralDBElementRepositoryTest extends WebTestCase
|
||||
{
|
||||
private $entityManager;
|
||||
/**
|
||||
* @var StructuralDBElementRepository
|
||||
*/
|
||||
|
|
@ -42,11 +41,11 @@ class StructuralDBElementRepositoryTest extends WebTestCase
|
|||
{
|
||||
$kernel = self::bootKernel();
|
||||
|
||||
$this->entityManager = $kernel->getContainer()
|
||||
$entityManager = $kernel->getContainer()
|
||||
->get('doctrine')
|
||||
->getManager();
|
||||
|
||||
$this->repo = $this->entityManager->getRepository(AttachmentType::class);
|
||||
$this->repo = $entityManager->getRepository(AttachmentType::class);
|
||||
}
|
||||
|
||||
public function testFindRootNodes(): void
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
|||
class UserRepositoryTest extends WebTestCase
|
||||
{
|
||||
|
||||
private $entityManager;
|
||||
/**
|
||||
* @var UserRepository
|
||||
*/
|
||||
|
|
@ -40,11 +39,11 @@ class UserRepositoryTest extends WebTestCase
|
|||
{
|
||||
$kernel = self::bootKernel();
|
||||
|
||||
$this->entityManager = $kernel->getContainer()
|
||||
$entityManager = $kernel->getContainer()
|
||||
->get('doctrine')
|
||||
->getManager();
|
||||
|
||||
$this->repo = $this->entityManager->getRepository(User::class);
|
||||
$this->repo = $entityManager->getRepository(User::class);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace App\Tests\Serializer;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Serializer\StructuralElementDenormalizer;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
|
@ -53,9 +54,7 @@ class StructuralElementDenormalizerTest extends WebTestCase
|
|||
$this->assertTrue($this->service->supportsDenormalization(['name' => 'Test'], Category::class, 'json', ['groups' => ['import'], 'partdb_import' => true]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
*/
|
||||
#[Group('DB')]
|
||||
public function testDenormalize(): void
|
||||
{
|
||||
//Check that we retrieve DB elements via the name
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ class StructuralElementNormalizerTest extends WebTestCase
|
|||
//Get an service instance.
|
||||
self::bootKernel();
|
||||
$this->service = self::getContainer()->get(StructuralElementNormalizer::class);
|
||||
//Inject the serializer, as the normalizer as this is not handled by the DI container
|
||||
$this->service->setNormalizer(self::getContainer()->get('serializer'));
|
||||
|
||||
}
|
||||
|
||||
public function testNormalize(): void
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\Attachments;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Services\Formatters\AmountFormatter;
|
||||
use App\Services\Attachments\AttachmentPathResolver;
|
||||
use const DIRECTORY_SEPARATOR;
|
||||
|
|
@ -69,19 +70,19 @@ class AttachmentPathResolverTest extends WebTestCase
|
|||
$this->assertNull($this->service->parameterToAbsolutePath('/./this/one/too'));
|
||||
}
|
||||
|
||||
public function placeholderDataProvider(): \Iterator
|
||||
public static function placeholderDataProvider(): \Iterator
|
||||
{
|
||||
//We need to do initialization (again), as dataprovider is called before setUp()
|
||||
self::bootKernel();
|
||||
$this->projectDir_orig = realpath(self::$kernel->getProjectDir());
|
||||
$this->projectDir = str_replace('\\', '/', $this->projectDir_orig);
|
||||
$this->media_path = $this->projectDir.'/public/media';
|
||||
$this->footprint_path = $this->projectDir.'/public/img/footprints';
|
||||
yield ['%FOOTPRINTS%/test/test.jpg', $this->footprint_path.'/test/test.jpg'];
|
||||
yield ['%FOOTPRINTS%/test/', $this->footprint_path.'/test/'];
|
||||
yield ['%MEDIA%/test', $this->media_path.'/test'];
|
||||
yield ['%MEDIA%', $this->media_path];
|
||||
yield ['%FOOTPRINTS%', $this->footprint_path];
|
||||
$projectDir_orig = realpath(self::$kernel->getProjectDir());
|
||||
$projectDir = str_replace('\\', '/', $projectDir_orig);
|
||||
$media_path = $projectDir.'/public/media';
|
||||
$footprint_path = $projectDir.'/public/img/footprints';
|
||||
yield ['%FOOTPRINTS%/test/test.jpg', $footprint_path.'/test/test.jpg'];
|
||||
yield ['%FOOTPRINTS%/test/', $footprint_path.'/test/'];
|
||||
yield ['%MEDIA%/test', $media_path.'/test'];
|
||||
yield ['%MEDIA%', $media_path];
|
||||
yield ['%FOOTPRINTS%', $footprint_path];
|
||||
//Footprints 3D are disabled
|
||||
yield ['%FOOTPRINTS_3D%', null];
|
||||
//Check that invalid pathes return null
|
||||
|
|
@ -98,65 +99,59 @@ class AttachmentPathResolverTest extends WebTestCase
|
|||
yield ['%FOOTPRINTS%/0\..\test', null];
|
||||
}
|
||||
|
||||
public function realPathDataProvider(): \Iterator
|
||||
public static function realPathDataProvider(): \Iterator
|
||||
{
|
||||
//We need to do initialization (again), as dataprovider is called before setUp()
|
||||
self::bootKernel();
|
||||
$this->projectDir_orig = realpath(self::$kernel->getProjectDir());
|
||||
$this->projectDir = str_replace('\\', '/', $this->projectDir_orig);
|
||||
$this->media_path = $this->projectDir.'/public/media';
|
||||
$this->footprint_path = $this->projectDir.'/public/img/footprints';
|
||||
yield [$this->media_path.'/test/img.jpg', '%MEDIA%/test/img.jpg'];
|
||||
yield [$this->media_path.'/test/img.jpg', '%BASE%/data/media/test/img.jpg', true];
|
||||
yield [$this->footprint_path.'/foo.jpg', '%FOOTPRINTS%/foo.jpg'];
|
||||
yield [$this->footprint_path.'/foo.jpg', '%FOOTPRINTS%/foo.jpg', true];
|
||||
$projectDir_orig = realpath(self::$kernel->getProjectDir());
|
||||
$projectDir = str_replace('\\', '/', $projectDir_orig);
|
||||
$media_path = $projectDir.'/public/media';
|
||||
$footprint_path = $projectDir.'/public/img/footprints';
|
||||
yield [$media_path.'/test/img.jpg', '%MEDIA%/test/img.jpg'];
|
||||
yield [$media_path.'/test/img.jpg', '%BASE%/data/media/test/img.jpg', true];
|
||||
yield [$footprint_path.'/foo.jpg', '%FOOTPRINTS%/foo.jpg'];
|
||||
yield [$footprint_path.'/foo.jpg', '%FOOTPRINTS%/foo.jpg', true];
|
||||
//Every kind of absolute path, that is not based with our placeholder dirs must be invald
|
||||
yield ['/etc/passwd', null];
|
||||
yield ['C:\\not\\existing.txt', null];
|
||||
//More than one placeholder is not allowed
|
||||
yield [$this->footprint_path.'/test/'.$this->footprint_path, null];
|
||||
yield [$footprint_path.'/test/'.$footprint_path, null];
|
||||
//Path must begin with path
|
||||
yield ['/not/root'.$this->footprint_path, null];
|
||||
yield ['/not/root'.$footprint_path, null];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider placeholderDataProvider
|
||||
*/
|
||||
#[DataProvider('placeholderDataProvider')]
|
||||
public function testPlaceholderToRealPath($param, $expected): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->placeholderToRealPath($param));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider realPathDataProvider
|
||||
*/
|
||||
#[DataProvider('realPathDataProvider')]
|
||||
public function testRealPathToPlaceholder($param, $expected, $old_method = false): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->realPathToPlaceholder($param, $old_method));
|
||||
}
|
||||
|
||||
public function germanFootprintPathdDataProvider(): ?\Generator
|
||||
public static function germanFootprintPathdDataProvider(): ?\Generator
|
||||
{
|
||||
self::bootKernel();
|
||||
$this->projectDir_orig = realpath(self::$kernel->getProjectDir());
|
||||
$this->projectDir = str_replace('\\', '/', $this->projectDir_orig);
|
||||
$this->footprint_path = $this->projectDir.'/public/img/footprints';
|
||||
$projectDir_orig = realpath(self::$kernel->getProjectDir());
|
||||
$projectDir = str_replace('\\', '/', $projectDir_orig);
|
||||
$footprint_path = $projectDir.'/public/img/footprints';
|
||||
|
||||
yield [$this->footprint_path. '/Active/Diodes/THT/DIODE_P600.png', '%FOOTPRINTS%/Aktiv/Dioden/Bedrahtet/DIODE_P600.png'];
|
||||
yield [$this->footprint_path . '/Passive/Resistors/THT/Carbon/RESISTOR-CARBON_0207.png', '%FOOTPRINTS%/Passiv/Widerstaende/Bedrahtet/Kohleschicht/WIDERSTAND-KOHLE_0207.png'];
|
||||
yield [$this->footprint_path . '/Optics/LEDs/THT/LED-GREEN_3MM.png', '%FOOTPRINTS%/Optik/LEDs/Bedrahtet/LED-GRUEN_3MM.png'];
|
||||
yield [$this->footprint_path . '/Passive/Capacitors/TrimmerCapacitors/TRIMMER_CAPACITOR-RED_TZ03F.png', '%FOOTPRINTS%/Passiv/Kondensatoren/Trimmkondensatoren/TRIMMKONDENSATOR-ROT_TZ03F.png'];
|
||||
yield [$this->footprint_path . '/Active/ICs/TO/IC_TO126.png', '%FOOTPRINTS%/Aktiv/ICs/TO/IC_TO126.png'];
|
||||
yield [$this->footprint_path . '/Electromechanics/Switches_Buttons/RotarySwitches/ROTARY_SWITCH_DIP10.png', '%FOOTPRINTS%/Elektromechanik/Schalter_Taster/Drehschalter/DREHSCHALTER_DIP10.png'];
|
||||
yield [$this->footprint_path . '/Electromechanics/Connectors/DINConnectors/SOCKET_DIN_MAB_4.png', '%FOOTPRINTS%/Elektromechanik/Verbinder/Rundsteckverbinder/BUCHSE_DIN_MAB_4.png'];
|
||||
yield [$footprint_path. '/Active/Diodes/THT/DIODE_P600.png', '%FOOTPRINTS%/Aktiv/Dioden/Bedrahtet/DIODE_P600.png'];
|
||||
yield [$footprint_path . '/Passive/Resistors/THT/Carbon/RESISTOR-CARBON_0207.png', '%FOOTPRINTS%/Passiv/Widerstaende/Bedrahtet/Kohleschicht/WIDERSTAND-KOHLE_0207.png'];
|
||||
yield [$footprint_path . '/Optics/LEDs/THT/LED-GREEN_3MM.png', '%FOOTPRINTS%/Optik/LEDs/Bedrahtet/LED-GRUEN_3MM.png'];
|
||||
yield [$footprint_path . '/Passive/Capacitors/TrimmerCapacitors/TRIMMER_CAPACITOR-RED_TZ03F.png', '%FOOTPRINTS%/Passiv/Kondensatoren/Trimmkondensatoren/TRIMMKONDENSATOR-ROT_TZ03F.png'];
|
||||
yield [$footprint_path . '/Active/ICs/TO/IC_TO126.png', '%FOOTPRINTS%/Aktiv/ICs/TO/IC_TO126.png'];
|
||||
yield [$footprint_path . '/Electromechanics/Switches_Buttons/RotarySwitches/ROTARY_SWITCH_DIP10.png', '%FOOTPRINTS%/Elektromechanik/Schalter_Taster/Drehschalter/DREHSCHALTER_DIP10.png'];
|
||||
yield [$footprint_path . '/Electromechanics/Connectors/DINConnectors/SOCKET_DIN_MAB_4.png', '%FOOTPRINTS%/Elektromechanik/Verbinder/Rundsteckverbinder/BUCHSE_DIN_MAB_4.png'];
|
||||
|
||||
//Leave english pathes untouched
|
||||
yield [$this->footprint_path . '/Passive/Capacitors/CAPACITOR_CTS_A_15MM.png', '%FOOTPRINTS%/Passive/Capacitors/CAPACITOR_CTS_A_15MM.png'];
|
||||
yield [$footprint_path . '/Passive/Capacitors/CAPACITOR_CTS_A_15MM.png', '%FOOTPRINTS%/Passive/Capacitors/CAPACITOR_CTS_A_15MM.png'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider germanFootprintPathdDataProvider
|
||||
*/
|
||||
#[DataProvider('germanFootprintPathdDataProvider')]
|
||||
public function testConversionOfGermanFootprintPaths(string $expected, string $input): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->placeholderToRealPath($input));
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\Attachments;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Services\Attachments\AttachmentURLGenerator;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
|
|
@ -38,7 +39,7 @@ class AttachmentURLGeneratorTest extends WebTestCase
|
|||
self::$service = self::getContainer()->get(AttachmentURLGenerator::class);
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
yield ['/public/test.jpg', 'test.jpg'];
|
||||
yield ['/public/folder/test.jpg', 'folder/test.jpg'];
|
||||
|
|
@ -48,11 +49,11 @@ class AttachmentURLGeneratorTest extends WebTestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*
|
||||
* @param $input
|
||||
* @param $expected
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testTestabsolutePathToAssetPath($input, $expected): void
|
||||
{
|
||||
$this->assertSame($expected, static::$service->absolutePathToAssetPath($input, static::PUBLIC_DIR));
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\Attachments;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Services\Attachments\BuiltinAttachmentsFinder;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
|
|
@ -43,7 +44,7 @@ class BuiltinAttachmentsFinderTest extends WebTestCase
|
|||
self::$service = self::getContainer()->get(BuiltinAttachmentsFinder::class);
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
//No value should return empty array
|
||||
yield ['', [], []];
|
||||
|
|
@ -54,9 +55,7 @@ class BuiltinAttachmentsFinderTest extends WebTestCase
|
|||
yield ['.txt', [], ['%FOOTPRINTS_3D%/hallo.txt']];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testFind($keyword, $options, $expected): void
|
||||
{
|
||||
$value = static::$service->find($keyword, $options, static::$mock_list);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\Attachments;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Services\Attachments\FileTypeFilterTools;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
|
|
@ -35,7 +36,7 @@ class FileTypeFilterToolsTest extends WebTestCase
|
|||
self::$service = self::getContainer()->get(FileTypeFilterTools::class);
|
||||
}
|
||||
|
||||
public function validateDataProvider(): \Iterator
|
||||
public static function validateDataProvider(): \Iterator
|
||||
{
|
||||
yield ['', true];
|
||||
//Empty string is valid
|
||||
|
|
@ -54,7 +55,7 @@ class FileTypeFilterToolsTest extends WebTestCase
|
|||
yield ['.png .jpg .gif', false];
|
||||
}
|
||||
|
||||
public function normalizeDataProvider(): \Iterator
|
||||
public static function normalizeDataProvider(): \Iterator
|
||||
{
|
||||
yield ['', ''];
|
||||
yield ['.jpeg,.png,.gif', '.jpeg,.png,.gif'];
|
||||
|
|
@ -68,7 +69,7 @@ class FileTypeFilterToolsTest extends WebTestCase
|
|||
yield ['png, .gif, .png,', '.png,.gif'];
|
||||
}
|
||||
|
||||
public function extensionAllowedDataProvider(): \Iterator
|
||||
public static function extensionAllowedDataProvider(): \Iterator
|
||||
{
|
||||
yield ['', 'txt', true];
|
||||
yield ['', 'everything_should_match', true];
|
||||
|
|
@ -85,25 +86,20 @@ class FileTypeFilterToolsTest extends WebTestCase
|
|||
|
||||
/**
|
||||
* Test the validateFilterString method.
|
||||
*
|
||||
* @dataProvider validateDataProvider
|
||||
*/
|
||||
#[DataProvider('validateDataProvider')]
|
||||
public function testValidateFilterString(string $filter, bool $expected): void
|
||||
{
|
||||
$this->assertSame($expected, self::$service->validateFilterString($filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider normalizeDataProvider
|
||||
*/
|
||||
#[DataProvider('normalizeDataProvider')]
|
||||
public function testNormalizeFilterString(string $filter, string $expected): void
|
||||
{
|
||||
$this->assertSame($expected, self::$service->normalizeFilterString($filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider extensionAllowedDataProvider
|
||||
*/
|
||||
#[DataProvider('extensionAllowedDataProvider')]
|
||||
public function testIsExtensionAllowed(string $filter, string $extension, bool $expected): void
|
||||
{
|
||||
$this->assertSame($expected, self::$service->isExtensionAllowed($filter, $extension));
|
||||
|
|
|
|||
|
|
@ -25,11 +25,12 @@ namespace App\Tests\Services;
|
|||
use App\Entity\Attachments\PartAttachment;
|
||||
use App\Entity\Base\AbstractDBElement;
|
||||
use App\Entity\Base\AbstractNamedDBElement;
|
||||
use App\Entity\InfoProviderSystem\BulkInfoProviderImportJob;
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Exceptions\EntityNotSupportedException;
|
||||
use App\Services\Formatters\AmountFormatter;
|
||||
use App\Services\ElementTypeNameGenerator;
|
||||
use App\Services\Formatters\AmountFormatter;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
class ElementTypeNameGeneratorTest extends WebTestCase
|
||||
|
|
@ -50,16 +51,18 @@ class ElementTypeNameGeneratorTest extends WebTestCase
|
|||
//We only test in english
|
||||
$this->assertSame('Part', $this->service->getLocalizedTypeLabel(new Part()));
|
||||
$this->assertSame('Category', $this->service->getLocalizedTypeLabel(new Category()));
|
||||
$this->assertSame('Bulk info provider import', $this->service->getLocalizedTypeLabel(new BulkInfoProviderImportJob()));
|
||||
|
||||
//Test inheritance
|
||||
$this->assertSame('Attachment', $this->service->getLocalizedTypeLabel(new PartAttachment()));
|
||||
|
||||
//Test for class name
|
||||
$this->assertSame('Part', $this->service->getLocalizedTypeLabel(Part::class));
|
||||
$this->assertSame('Bulk info provider import', $this->service->getLocalizedTypeLabel(BulkInfoProviderImportJob::class));
|
||||
|
||||
//Test exception for unknpwn type
|
||||
$this->expectException(EntityNotSupportedException::class);
|
||||
$this->service->getLocalizedTypeLabel(new class() extends AbstractDBElement {
|
||||
$this->service->getLocalizedTypeLabel(new class () extends AbstractDBElement {
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +77,7 @@ class ElementTypeNameGeneratorTest extends WebTestCase
|
|||
|
||||
//Test exception
|
||||
$this->expectException(EntityNotSupportedException::class);
|
||||
$this->service->getTypeNameCombination(new class() extends AbstractNamedDBElement {
|
||||
$this->service->getTypeNameCombination(new class () extends AbstractNamedDBElement {
|
||||
public function getIDString(): string
|
||||
{
|
||||
return 'Stub';
|
||||
|
|
|
|||
|
|
@ -178,7 +178,9 @@ class PartMergerTest extends KernelTestCase
|
|||
//But the new lots, should be assigned to the target part and contain the same info
|
||||
$clone3 = $merged->getPartLots()->get(2);
|
||||
$clone4 = $merged->getPartLots()->get(3);
|
||||
$this->assertInstanceOf(PartLot::class, $clone3);
|
||||
$this->assertSame($merged, $clone3->getPart());
|
||||
$this->assertInstanceOf(PartLot::class, $clone4);
|
||||
$this->assertSame($merged, $clone4->getPart());
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,9 +22,12 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace App\Tests\Services\ImportExportSystem;
|
||||
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\Parts\Supplier;
|
||||
use App\Entity\ProjectSystem\Project;
|
||||
use App\Entity\ProjectSystem\ProjectBOMEntry;
|
||||
use App\Services\ImportExportSystem\BOMImporter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
|
||||
|
|
@ -36,11 +39,17 @@ class BOMImporterTest extends WebTestCase
|
|||
*/
|
||||
protected $service;
|
||||
|
||||
/**
|
||||
* @var EntityManagerInterface
|
||||
*/
|
||||
protected $entityManager;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
//Get a service instance.
|
||||
self::bootKernel();
|
||||
$this->service = self::getContainer()->get(BOMImporter::class);
|
||||
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
|
||||
}
|
||||
|
||||
public function testImportFileIntoProject(): void
|
||||
|
|
@ -119,4 +128,489 @@ class BOMImporterTest extends WebTestCase
|
|||
|
||||
$this->service->stringToBOMEntries($input, ['type' => 'kicad_pcbnew']);
|
||||
}
|
||||
|
||||
public function testDetectFields(): void
|
||||
{
|
||||
$input = <<<CSV
|
||||
"Reference","Value","Footprint","Quantity","MPN","Manufacturer","LCSC SPN","Mouser SPN"
|
||||
CSV;
|
||||
|
||||
$fields = $this->service->detectFields($input);
|
||||
|
||||
$this->assertIsArray($fields);
|
||||
$this->assertCount(8, $fields);
|
||||
$this->assertContains('Reference', $fields);
|
||||
$this->assertContains('Value', $fields);
|
||||
$this->assertContains('Footprint', $fields);
|
||||
$this->assertContains('Quantity', $fields);
|
||||
$this->assertContains('MPN', $fields);
|
||||
$this->assertContains('Manufacturer', $fields);
|
||||
$this->assertContains('LCSC SPN', $fields);
|
||||
$this->assertContains('Mouser SPN', $fields);
|
||||
}
|
||||
|
||||
public function testDetectFieldsWithQuotes(): void
|
||||
{
|
||||
$input = <<<CSV
|
||||
"Reference","Value","Footprint","Quantity","MPN","Manufacturer","LCSC SPN","Mouser SPN"
|
||||
CSV;
|
||||
|
||||
$fields = $this->service->detectFields($input);
|
||||
|
||||
$this->assertIsArray($fields);
|
||||
$this->assertCount(8, $fields);
|
||||
$this->assertEquals('Reference', $fields[0]);
|
||||
$this->assertEquals('Value', $fields[1]);
|
||||
}
|
||||
|
||||
public function testDetectFieldsWithSemicolon(): void
|
||||
{
|
||||
$input = <<<CSV
|
||||
"Reference";"Value";"Footprint";"Quantity";"MPN";"Manufacturer";"LCSC SPN";"Mouser SPN"
|
||||
CSV;
|
||||
|
||||
$fields = $this->service->detectFields($input, ';');
|
||||
|
||||
$this->assertIsArray($fields);
|
||||
$this->assertCount(8, $fields);
|
||||
$this->assertEquals('Reference', $fields[0]);
|
||||
$this->assertEquals('Value', $fields[1]);
|
||||
}
|
||||
|
||||
public function testGetAvailableFieldTargets(): void
|
||||
{
|
||||
$targets = $this->service->getAvailableFieldTargets();
|
||||
|
||||
$this->assertIsArray($targets);
|
||||
$this->assertArrayHasKey('Designator', $targets);
|
||||
$this->assertArrayHasKey('Quantity', $targets);
|
||||
$this->assertArrayHasKey('Value', $targets);
|
||||
$this->assertArrayHasKey('Package', $targets);
|
||||
$this->assertArrayHasKey('MPN', $targets);
|
||||
$this->assertArrayHasKey('Manufacturer', $targets);
|
||||
$this->assertArrayHasKey('Part-DB ID', $targets);
|
||||
$this->assertArrayHasKey('Comment', $targets);
|
||||
|
||||
// Check structure of a target
|
||||
$this->assertArrayHasKey('label', $targets['Designator']);
|
||||
$this->assertArrayHasKey('description', $targets['Designator']);
|
||||
$this->assertArrayHasKey('required', $targets['Designator']);
|
||||
$this->assertArrayHasKey('multiple', $targets['Designator']);
|
||||
|
||||
$this->assertTrue($targets['Designator']['required']);
|
||||
$this->assertTrue($targets['Quantity']['required']);
|
||||
$this->assertFalse($targets['Value']['required']);
|
||||
}
|
||||
|
||||
public function testGetAvailableFieldTargetsWithSuppliers(): void
|
||||
{
|
||||
// Create test suppliers
|
||||
$supplier1 = new Supplier();
|
||||
$supplier1->setName('LCSC');
|
||||
$supplier2 = new Supplier();
|
||||
$supplier2->setName('Mouser');
|
||||
|
||||
$this->entityManager->persist($supplier1);
|
||||
$this->entityManager->persist($supplier2);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$targets = $this->service->getAvailableFieldTargets();
|
||||
|
||||
$this->assertArrayHasKey('LCSC SPN', $targets);
|
||||
$this->assertArrayHasKey('Mouser SPN', $targets);
|
||||
|
||||
$this->assertEquals('LCSC SPN', $targets['LCSC SPN']['label']);
|
||||
$this->assertEquals('Mouser SPN', $targets['Mouser SPN']['label']);
|
||||
$this->assertFalse($targets['LCSC SPN']['required']);
|
||||
$this->assertTrue($targets['LCSC SPN']['multiple']);
|
||||
|
||||
// Clean up
|
||||
$this->entityManager->remove($supplier1);
|
||||
$this->entityManager->remove($supplier2);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function testGetSuggestedFieldMapping(): void
|
||||
{
|
||||
$detected_fields = [
|
||||
'Reference',
|
||||
'Value',
|
||||
'Footprint',
|
||||
'Quantity',
|
||||
'MPN',
|
||||
'Manufacturer',
|
||||
'LCSC',
|
||||
'Mouser',
|
||||
'Part-DB ID',
|
||||
'Comment'
|
||||
];
|
||||
|
||||
$suggestions = $this->service->getSuggestedFieldMapping($detected_fields);
|
||||
|
||||
$this->assertIsArray($suggestions);
|
||||
$this->assertEquals('Designator', $suggestions['Reference']);
|
||||
$this->assertEquals('Value', $suggestions['Value']);
|
||||
$this->assertEquals('Package', $suggestions['Footprint']);
|
||||
$this->assertEquals('Quantity', $suggestions['Quantity']);
|
||||
$this->assertEquals('MPN', $suggestions['MPN']);
|
||||
$this->assertEquals('Manufacturer', $suggestions['Manufacturer']);
|
||||
$this->assertEquals('Part-DB ID', $suggestions['Part-DB ID']);
|
||||
$this->assertEquals('Comment', $suggestions['Comment']);
|
||||
}
|
||||
|
||||
public function testGetSuggestedFieldMappingWithSuppliers(): void
|
||||
{
|
||||
// Create test suppliers
|
||||
$supplier1 = new Supplier();
|
||||
$supplier1->setName('LCSC');
|
||||
$supplier2 = new Supplier();
|
||||
$supplier2->setName('Mouser');
|
||||
|
||||
$this->entityManager->persist($supplier1);
|
||||
$this->entityManager->persist($supplier2);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$detected_fields = [
|
||||
'Reference',
|
||||
'LCSC',
|
||||
'Mouser',
|
||||
'lcsc_part',
|
||||
'mouser_spn'
|
||||
];
|
||||
|
||||
$suggestions = $this->service->getSuggestedFieldMapping($detected_fields);
|
||||
|
||||
$this->assertIsArray($suggestions);
|
||||
$this->assertEquals('Designator', $suggestions['Reference']);
|
||||
// Note: The exact mapping depends on the pattern matching logic
|
||||
// We just check that supplier fields are mapped to something
|
||||
$this->assertArrayHasKey('LCSC', $suggestions);
|
||||
$this->assertArrayHasKey('Mouser', $suggestions);
|
||||
$this->assertArrayHasKey('lcsc_part', $suggestions);
|
||||
$this->assertArrayHasKey('mouser_spn', $suggestions);
|
||||
|
||||
// Clean up
|
||||
$this->entityManager->remove($supplier1);
|
||||
$this->entityManager->remove($supplier2);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function testValidateFieldMappingValid(): void
|
||||
{
|
||||
$field_mapping = [
|
||||
'Reference' => 'Designator',
|
||||
'Quantity' => 'Quantity',
|
||||
'Value' => 'Value'
|
||||
];
|
||||
|
||||
$detected_fields = ['Reference', 'Quantity', 'Value', 'MPN'];
|
||||
|
||||
$result = $this->service->validateFieldMapping($field_mapping, $detected_fields);
|
||||
|
||||
$this->assertIsArray($result);
|
||||
$this->assertArrayHasKey('errors', $result);
|
||||
$this->assertArrayHasKey('warnings', $result);
|
||||
$this->assertArrayHasKey('is_valid', $result);
|
||||
|
||||
$this->assertTrue($result['is_valid']);
|
||||
$this->assertEmpty($result['errors']);
|
||||
$this->assertNotEmpty($result['warnings']); // Should warn about unmapped MPN
|
||||
}
|
||||
|
||||
public function testValidateFieldMappingMissingRequired(): void
|
||||
{
|
||||
$field_mapping = [
|
||||
'Value' => 'Value',
|
||||
'MPN' => 'MPN'
|
||||
];
|
||||
|
||||
$detected_fields = ['Value', 'MPN'];
|
||||
|
||||
$result = $this->service->validateFieldMapping($field_mapping, $detected_fields);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertNotEmpty($result['errors']);
|
||||
$this->assertContains("Required field 'Designator' is not mapped from any CSV column.", $result['errors']);
|
||||
$this->assertContains("Required field 'Quantity' is not mapped from any CSV column.", $result['errors']);
|
||||
}
|
||||
|
||||
public function testValidateFieldMappingInvalidTarget(): void
|
||||
{
|
||||
$field_mapping = [
|
||||
'Reference' => 'Designator',
|
||||
'Quantity' => 'Quantity',
|
||||
'Value' => 'InvalidTarget'
|
||||
];
|
||||
|
||||
$detected_fields = ['Reference', 'Quantity', 'Value'];
|
||||
|
||||
$result = $this->service->validateFieldMapping($field_mapping, $detected_fields);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertNotEmpty($result['errors']);
|
||||
$this->assertContains("Invalid target field 'InvalidTarget' for CSV field 'Value'.", $result['errors']);
|
||||
}
|
||||
|
||||
public function testStringToBOMEntriesKiCADSchematic(): void
|
||||
{
|
||||
$input = <<<CSV
|
||||
"Reference","Value","Footprint","Quantity","MPN","Manufacturer","LCSC SPN","Mouser SPN"
|
||||
"R1,R2","10k","R_0805_2012Metric",2,"CRCW080510K0FKEA","Vishay","C123456","123-M10K"
|
||||
"C1","100nF","C_0805_2012Metric",1,"CL21A104KOCLRNC","Samsung","C789012","80-CL21A104KOCLRNC"
|
||||
CSV;
|
||||
|
||||
$field_mapping = [
|
||||
'Reference' => 'Designator',
|
||||
'Value' => 'Value',
|
||||
'Footprint' => 'Package',
|
||||
'Quantity' => 'Quantity',
|
||||
'MPN' => 'MPN',
|
||||
'Manufacturer' => 'Manufacturer',
|
||||
'LCSC SPN' => 'LCSC SPN',
|
||||
'Mouser SPN' => 'Mouser SPN'
|
||||
];
|
||||
|
||||
$bom_entries = $this->service->stringToBOMEntries($input, [
|
||||
'type' => 'kicad_schematic',
|
||||
'field_mapping' => $field_mapping,
|
||||
'delimiter' => ','
|
||||
]);
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(ProjectBOMEntry::class, $bom_entries);
|
||||
$this->assertCount(2, $bom_entries);
|
||||
|
||||
// Check first entry
|
||||
$this->assertEquals('R1,R2', $bom_entries[0]->getMountnames());
|
||||
$this->assertEquals(2.0, $bom_entries[0]->getQuantity());
|
||||
$this->assertEquals('CRCW080510K0FKEA (R_0805_2012Metric)', $bom_entries[0]->getName());
|
||||
$this->assertStringContainsString('Value: 10k', $bom_entries[0]->getComment());
|
||||
$this->assertStringContainsString('MPN: CRCW080510K0FKEA', $bom_entries[0]->getComment());
|
||||
$this->assertStringContainsString('Manf: Vishay', $bom_entries[0]->getComment());
|
||||
|
||||
// Check second entry
|
||||
$this->assertEquals('C1', $bom_entries[1]->getMountnames());
|
||||
$this->assertEquals(1.0, $bom_entries[1]->getQuantity());
|
||||
}
|
||||
|
||||
public function testStringToBOMEntriesKiCADSchematicWithPriority(): void
|
||||
{
|
||||
$input = <<<CSV
|
||||
"Reference","Value","MPN1","MPN2","Quantity"
|
||||
"R1,R2","10k","CRCW080510K0FKEA","","2"
|
||||
"C1","100nF","","CL21A104KOCLRNC","1"
|
||||
CSV;
|
||||
|
||||
$field_mapping = [
|
||||
'Reference' => 'Designator',
|
||||
'Value' => 'Value',
|
||||
'MPN1' => 'MPN',
|
||||
'MPN2' => 'MPN',
|
||||
'Quantity' => 'Quantity'
|
||||
];
|
||||
|
||||
$field_priorities = [
|
||||
'MPN1' => 1,
|
||||
'MPN2' => 2
|
||||
];
|
||||
|
||||
$bom_entries = $this->service->stringToBOMEntries($input, [
|
||||
'type' => 'kicad_schematic',
|
||||
'field_mapping' => $field_mapping,
|
||||
'field_priorities' => $field_priorities,
|
||||
'delimiter' => ','
|
||||
]);
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(ProjectBOMEntry::class, $bom_entries);
|
||||
$this->assertCount(2, $bom_entries);
|
||||
|
||||
// First entry should use MPN1 (higher priority)
|
||||
$this->assertEquals('CRCW080510K0FKEA', $bom_entries[0]->getName());
|
||||
|
||||
// Second entry should use MPN2 (MPN1 is empty)
|
||||
$this->assertEquals('CL21A104KOCLRNC', $bom_entries[1]->getName());
|
||||
}
|
||||
|
||||
public function testStringToBOMEntriesKiCADSchematicWithPartDBID(): void
|
||||
{
|
||||
// Create a test part with required fields
|
||||
$part = new Part();
|
||||
$part->setName('Test Part');
|
||||
$part->setCategory($this->getDefaultCategory($this->entityManager));
|
||||
$this->entityManager->persist($part);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$input = <<<CSV
|
||||
"Reference","Value","Part-DB ID","Quantity"
|
||||
"R1,R2","10k","{$part->getID()}","2"
|
||||
CSV;
|
||||
|
||||
$field_mapping = [
|
||||
'Reference' => 'Designator',
|
||||
'Value' => 'Value',
|
||||
'Part-DB ID' => 'Part-DB ID',
|
||||
'Quantity' => 'Quantity'
|
||||
];
|
||||
|
||||
$bom_entries = $this->service->stringToBOMEntries($input, [
|
||||
'type' => 'kicad_schematic',
|
||||
'field_mapping' => $field_mapping,
|
||||
'delimiter' => ','
|
||||
]);
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(ProjectBOMEntry::class, $bom_entries);
|
||||
$this->assertCount(1, $bom_entries);
|
||||
|
||||
$this->assertEquals('Test Part', $bom_entries[0]->getName());
|
||||
$this->assertSame($part, $bom_entries[0]->getPart());
|
||||
$this->assertStringContainsString("Part-DB ID: {$part->getID()}", $bom_entries[0]->getComment());
|
||||
|
||||
// Clean up
|
||||
$this->entityManager->remove($part);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function testStringToBOMEntriesKiCADSchematicWithInvalidPartDBID(): void
|
||||
{
|
||||
$input = <<<CSV
|
||||
"Reference","Value","Part-DB ID","Quantity"
|
||||
"R1,R2","10k","99999","2"
|
||||
CSV;
|
||||
|
||||
$field_mapping = [
|
||||
'Reference' => 'Designator',
|
||||
'Value' => 'Value',
|
||||
'Part-DB ID' => 'Part-DB ID',
|
||||
'Quantity' => 'Quantity'
|
||||
];
|
||||
|
||||
$bom_entries = $this->service->stringToBOMEntries($input, [
|
||||
'type' => 'kicad_schematic',
|
||||
'field_mapping' => $field_mapping,
|
||||
'delimiter' => ','
|
||||
]);
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(ProjectBOMEntry::class, $bom_entries);
|
||||
$this->assertCount(1, $bom_entries);
|
||||
|
||||
$this->assertEquals('10k', $bom_entries[0]->getName()); // Should use Value as name
|
||||
$this->assertNull($bom_entries[0]->getPart()); // Should not link to part
|
||||
$this->assertStringContainsString("Part-DB ID: 99999 (NOT FOUND)", $bom_entries[0]->getComment());
|
||||
}
|
||||
|
||||
public function testStringToBOMEntriesKiCADSchematicMergeDuplicates(): void
|
||||
{
|
||||
$input = <<<CSV
|
||||
"Reference","Value","MPN","Quantity"
|
||||
"R1","10k","CRCW080510K0FKEA","1"
|
||||
"R2","10k","CRCW080510K0FKEA","1"
|
||||
CSV;
|
||||
|
||||
$field_mapping = [
|
||||
'Reference' => 'Designator',
|
||||
'Value' => 'Value',
|
||||
'MPN' => 'MPN',
|
||||
'Quantity' => 'Quantity'
|
||||
];
|
||||
|
||||
$bom_entries = $this->service->stringToBOMEntries($input, [
|
||||
'type' => 'kicad_schematic',
|
||||
'field_mapping' => $field_mapping,
|
||||
'delimiter' => ','
|
||||
]);
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(ProjectBOMEntry::class, $bom_entries);
|
||||
$this->assertCount(1, $bom_entries); // Should merge into one entry
|
||||
|
||||
$this->assertEquals('R1,R2', $bom_entries[0]->getMountnames());
|
||||
$this->assertEquals(2.0, $bom_entries[0]->getQuantity());
|
||||
$this->assertEquals('CRCW080510K0FKEA', $bom_entries[0]->getName());
|
||||
}
|
||||
|
||||
public function testStringToBOMEntriesKiCADSchematicMissingRequired(): void
|
||||
{
|
||||
$input = <<<CSV
|
||||
"Value","MPN"
|
||||
"10k","CRCW080510K0FKEA"
|
||||
CSV;
|
||||
|
||||
$field_mapping = [
|
||||
'Value' => 'Value',
|
||||
'MPN' => 'MPN'
|
||||
];
|
||||
|
||||
$this->expectException(\UnexpectedValueException::class);
|
||||
$this->expectExceptionMessage('Required field "Designator" is missing or empty');
|
||||
|
||||
$this->service->stringToBOMEntries($input, [
|
||||
'type' => 'kicad_schematic',
|
||||
'field_mapping' => $field_mapping,
|
||||
'delimiter' => ','
|
||||
]);
|
||||
}
|
||||
|
||||
public function testStringToBOMEntriesKiCADSchematicQuantityMismatch(): void
|
||||
{
|
||||
$input = <<<CSV
|
||||
"Reference","Value","Quantity"
|
||||
"R1,R2,R3","10k","2"
|
||||
CSV;
|
||||
|
||||
$field_mapping = [
|
||||
'Reference' => 'Designator',
|
||||
'Value' => 'Value',
|
||||
'Quantity' => 'Quantity'
|
||||
];
|
||||
|
||||
$this->expectException(\UnexpectedValueException::class);
|
||||
$this->expectExceptionMessage('Mismatch between quantity and component references');
|
||||
|
||||
$this->service->stringToBOMEntries($input, [
|
||||
'type' => 'kicad_schematic',
|
||||
'field_mapping' => $field_mapping,
|
||||
'delimiter' => ','
|
||||
]);
|
||||
}
|
||||
|
||||
public function testStringToBOMEntriesKiCADSchematicWithBOM(): void
|
||||
{
|
||||
// Test with BOM (Byte Order Mark)
|
||||
$input = "\xEF\xBB\xBF" . <<<CSV
|
||||
"Reference","Value","Quantity"
|
||||
"R1,R2","10k","2"
|
||||
CSV;
|
||||
|
||||
$field_mapping = [
|
||||
'Reference' => 'Designator',
|
||||
'Value' => 'Value',
|
||||
'Quantity' => 'Quantity'
|
||||
];
|
||||
|
||||
$bom_entries = $this->service->stringToBOMEntries($input, [
|
||||
'type' => 'kicad_schematic',
|
||||
'field_mapping' => $field_mapping,
|
||||
'delimiter' => ','
|
||||
]);
|
||||
|
||||
$this->assertContainsOnlyInstancesOf(ProjectBOMEntry::class, $bom_entries);
|
||||
$this->assertCount(1, $bom_entries);
|
||||
$this->assertEquals('R1,R2', $bom_entries[0]->getMountnames());
|
||||
}
|
||||
|
||||
private function getDefaultCategory(EntityManagerInterface $entityManager)
|
||||
{
|
||||
// Get the first available category or create a default one
|
||||
$categoryRepo = $entityManager->getRepository(\App\Entity\Parts\Category::class);
|
||||
$categories = $categoryRepo->findAll();
|
||||
|
||||
if (empty($categories)) {
|
||||
// Create a default category if none exists
|
||||
$category = new \App\Entity\Parts\Category();
|
||||
$category->setName('Default Category');
|
||||
$entityManager->persist($category);
|
||||
$entityManager->flush();
|
||||
return $category;
|
||||
}
|
||||
|
||||
return $categories[0];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
349
tests/Services/ImportExportSystem/BOMValidationServiceTest.php
Normal file
349
tests/Services/ImportExportSystem/BOMValidationServiceTest.php
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
namespace App\Tests\Services\ImportExportSystem;
|
||||
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Services\ImportExportSystem\BOMValidationService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* @see \App\Services\ImportExportSystem\BOMValidationService
|
||||
*/
|
||||
class BOMValidationServiceTest extends WebTestCase
|
||||
{
|
||||
private BOMValidationService $validationService;
|
||||
private EntityManagerInterface $entityManager;
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
|
||||
$this->translator = self::getContainer()->get(TranslatorInterface::class);
|
||||
$this->validationService = new BOMValidationService($this->entityManager, $this->translator);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithValidData(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1,C2,R3',
|
||||
'Quantity' => '3',
|
||||
'MPN' => 'RES-10K',
|
||||
'Package' => '0603',
|
||||
'Value' => '10k',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertTrue($result['is_valid']);
|
||||
$this->assertEmpty($result['errors']);
|
||||
$this->assertEquals(1, $result['line_number']);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithMissingRequiredFields(): void
|
||||
{
|
||||
$entry = [
|
||||
'MPN' => 'RES-10K',
|
||||
'Package' => '0603',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertCount(2, $result['errors']);
|
||||
$this->assertStringContainsString('Designator', (string) $result['errors'][0]);
|
||||
$this->assertStringContainsString('Quantity', (string) $result['errors'][1]);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithQuantityMismatch(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1,C2,R3,C4',
|
||||
'Quantity' => '3',
|
||||
'MPN' => 'RES-10K',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertCount(1, $result['errors']);
|
||||
$this->assertStringContainsString('Mismatch between quantity and component references', (string) $result['errors'][0]);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithInvalidQuantity(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1',
|
||||
'Quantity' => 'abc',
|
||||
'MPN' => 'RES-10K',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertGreaterThanOrEqual(1, count($result['errors']));
|
||||
$this->assertStringContainsString('not a valid number', implode(' ', array_map('strval', $result['errors'])));
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithZeroQuantity(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1',
|
||||
'Quantity' => '0',
|
||||
'MPN' => 'RES-10K',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertGreaterThanOrEqual(1, count($result['errors']));
|
||||
$this->assertStringContainsString('must be greater than 0', implode(' ', array_map('strval', $result['errors'])));
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithDuplicateDesignators(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1,R1,C2',
|
||||
'Quantity' => '3',
|
||||
'MPN' => 'RES-10K',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertCount(1, $result['errors']);
|
||||
$this->assertStringContainsString('Duplicate component references', (string) $result['errors'][0]);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithInvalidDesignatorFormat(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1,invalid,C2',
|
||||
'Quantity' => '3',
|
||||
'MPN' => 'RES-10K',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertTrue($result['is_valid']); // Warnings don't make it invalid
|
||||
$this->assertCount(1, $result['warnings']);
|
||||
$this->assertStringContainsString('unusual format', (string) $result['warnings'][0]);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithEmptyDesignator(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => '',
|
||||
'Quantity' => '1',
|
||||
'MPN' => 'RES-10K',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertGreaterThanOrEqual(1, count($result['errors']));
|
||||
$this->assertStringContainsString('Required field "Designator" is missing or empty', implode(' ', array_map('strval', $result['errors'])));
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithInvalidPartDBID(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1',
|
||||
'Quantity' => '1',
|
||||
'MPN' => 'RES-10K',
|
||||
'Part-DB ID' => 'abc',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertGreaterThanOrEqual(1, count($result['errors']));
|
||||
$this->assertStringContainsString('not a valid number', implode(' ', array_map('strval', $result['errors'])));
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithNonExistentPartDBID(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1',
|
||||
'Quantity' => '1',
|
||||
'MPN' => 'RES-10K',
|
||||
'Part-DB ID' => '999999', // Use very high ID that doesn't exist
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertTrue($result['is_valid']); // Warnings don't make it invalid
|
||||
$this->assertCount(1, $result['warnings']);
|
||||
$this->assertStringContainsString('not found in database', (string) $result['warnings'][0]);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithNoComponentName(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1',
|
||||
'Quantity' => '1',
|
||||
'Package' => '0603',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertTrue($result['is_valid']); // Warnings don't make it invalid
|
||||
$this->assertCount(1, $result['warnings']);
|
||||
$this->assertStringContainsString('No component name/designation', (string) $result['warnings'][0]);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithLongPackageName(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1',
|
||||
'Quantity' => '1',
|
||||
'MPN' => 'RES-10K',
|
||||
'Package' => str_repeat('A', 150), // Very long package name
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertTrue($result['is_valid']); // Warnings don't make it invalid
|
||||
$this->assertCount(1, $result['warnings']);
|
||||
$this->assertStringContainsString('unusually long', (string) $result['warnings'][0]);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntryWithLibraryPrefix(): void
|
||||
{
|
||||
$entry = [
|
||||
'Designator' => 'R1',
|
||||
'Quantity' => '1',
|
||||
'MPN' => 'RES-10K',
|
||||
'Package' => 'Resistor_SMD:R_0603_1608Metric',
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntry($entry, 1);
|
||||
|
||||
$this->assertTrue($result['is_valid']);
|
||||
$this->assertCount(1, $result['info']);
|
||||
$this->assertStringContainsString('library prefix', $result['info'][0]);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntriesWithMultipleEntries(): void
|
||||
{
|
||||
$entries = [
|
||||
[
|
||||
'Designator' => 'R1',
|
||||
'Quantity' => '1',
|
||||
'MPN' => 'RES-10K',
|
||||
],
|
||||
[
|
||||
'Designator' => 'C1,C2',
|
||||
'Quantity' => '2',
|
||||
'MPN' => 'CAP-100nF',
|
||||
],
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntries($entries);
|
||||
|
||||
$this->assertTrue($result['is_valid']);
|
||||
$this->assertEquals(2, $result['total_entries']);
|
||||
$this->assertEquals(2, $result['valid_entries']);
|
||||
$this->assertEquals(0, $result['invalid_entries']);
|
||||
$this->assertCount(2, $result['line_results']);
|
||||
}
|
||||
|
||||
public function testValidateBOMEntriesWithMixedResults(): void
|
||||
{
|
||||
$entries = [
|
||||
[
|
||||
'Designator' => 'R1',
|
||||
'Quantity' => '1',
|
||||
'MPN' => 'RES-10K',
|
||||
],
|
||||
[
|
||||
'Designator' => 'C1,C2',
|
||||
'Quantity' => '1', // Mismatch
|
||||
'MPN' => 'CAP-100nF',
|
||||
],
|
||||
];
|
||||
|
||||
$result = $this->validationService->validateBOMEntries($entries);
|
||||
|
||||
$this->assertFalse($result['is_valid']);
|
||||
$this->assertEquals(2, $result['total_entries']);
|
||||
$this->assertEquals(1, $result['valid_entries']);
|
||||
$this->assertEquals(1, $result['invalid_entries']);
|
||||
$this->assertCount(1, $result['errors']);
|
||||
}
|
||||
|
||||
public function testGetValidationStats(): void
|
||||
{
|
||||
$validation_result = [
|
||||
'total_entries' => 10,
|
||||
'valid_entries' => 8,
|
||||
'invalid_entries' => 2,
|
||||
'errors' => ['Error 1', 'Error 2'],
|
||||
'warnings' => ['Warning 1'],
|
||||
'info' => ['Info 1', 'Info 2'],
|
||||
];
|
||||
|
||||
$stats = $this->validationService->getValidationStats($validation_result);
|
||||
|
||||
$this->assertEquals(10, $stats['total_entries']);
|
||||
$this->assertEquals(8, $stats['valid_entries']);
|
||||
$this->assertEquals(2, $stats['invalid_entries']);
|
||||
$this->assertEquals(2, $stats['error_count']);
|
||||
$this->assertEquals(1, $stats['warning_count']);
|
||||
$this->assertEquals(2, $stats['info_count']);
|
||||
$this->assertEquals(80.0, $stats['success_rate']);
|
||||
}
|
||||
|
||||
public function testGetErrorMessage(): void
|
||||
{
|
||||
$validation_result = [
|
||||
'is_valid' => false,
|
||||
'errors' => ['Error 1', 'Error 2'],
|
||||
'warnings' => ['Warning 1'],
|
||||
];
|
||||
|
||||
$message = $this->validationService->getErrorMessage($validation_result);
|
||||
|
||||
$this->assertStringContainsString('Errors:', $message);
|
||||
$this->assertStringContainsString('• Error 1', $message);
|
||||
$this->assertStringContainsString('• Error 2', $message);
|
||||
$this->assertStringContainsString('Warnings:', $message);
|
||||
$this->assertStringContainsString('• Warning 1', $message);
|
||||
}
|
||||
|
||||
public function testGetErrorMessageWithValidResult(): void
|
||||
{
|
||||
$validation_result = [
|
||||
'is_valid' => true,
|
||||
'errors' => [],
|
||||
'warnings' => [],
|
||||
];
|
||||
|
||||
$message = $this->validationService->getErrorMessage($validation_result);
|
||||
|
||||
$this->assertEquals('', $message);
|
||||
}
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ use App\Entity\Parts\Category;
|
|||
use App\Services\ImportExportSystem\EntityExporter;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use PhpOffice\PhpSpreadsheet\IOFactory;
|
||||
|
||||
class EntityExporterTest extends WebTestCase
|
||||
{
|
||||
|
|
@ -76,7 +77,40 @@ class EntityExporterTest extends WebTestCase
|
|||
|
||||
$this->assertSame('application/json', $response->headers->get('Content-Type'));
|
||||
$this->assertNotEmpty($response->headers->get('Content-Disposition'));
|
||||
}
|
||||
|
||||
public function testExportToExcel(): void
|
||||
{
|
||||
$entities = $this->getEntities();
|
||||
|
||||
$xlsxData = $this->service->exportEntities($entities, ['format' => 'xlsx', 'level' => 'simple']);
|
||||
$this->assertNotEmpty($xlsxData);
|
||||
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'test_export') . '.xlsx';
|
||||
file_put_contents($tempFile, $xlsxData);
|
||||
|
||||
$spreadsheet = IOFactory::load($tempFile);
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
$this->assertSame('name', $worksheet->getCell('A1')->getValue());
|
||||
$this->assertSame('full_name', $worksheet->getCell('B1')->getValue());
|
||||
|
||||
$this->assertSame('Enitity 1', $worksheet->getCell('A2')->getValue());
|
||||
$this->assertSame('Enitity 1', $worksheet->getCell('B2')->getValue());
|
||||
|
||||
unlink($tempFile);
|
||||
}
|
||||
|
||||
public function testExportExcelFromRequest(): void
|
||||
{
|
||||
$entities = $this->getEntities();
|
||||
|
||||
$request = new Request();
|
||||
$request->request->set('format', 'xlsx');
|
||||
$request->request->set('level', 'simple');
|
||||
$response = $this->service->exportEntityFromRequest($entities, $request);
|
||||
|
||||
$this->assertSame('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', $response->headers->get('Content-Type'));
|
||||
$this->assertStringContainsString('export_Category_simple.xlsx', $response->headers->get('Content-Disposition'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\ImportExportSystem;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Attachments\AttachmentContainingDBElement;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
use App\Entity\LabelSystem\LabelProfile;
|
||||
|
|
@ -34,10 +36,11 @@ use Doctrine\ORM\EntityManagerInterface;
|
|||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
*/
|
||||
#[Group('DB')]
|
||||
class EntityImporterTest extends WebTestCase
|
||||
{
|
||||
/**
|
||||
|
|
@ -199,7 +202,7 @@ EOT;
|
|||
$this->assertSame($longName, $errors[0]['entity']->getName());
|
||||
}
|
||||
|
||||
public function formatDataProvider(): \Iterator
|
||||
public static function formatDataProvider(): \Iterator
|
||||
{
|
||||
yield ['csv', 'csv'];
|
||||
yield ['csv', 'CSV'];
|
||||
|
|
@ -207,11 +210,13 @@ EOT;
|
|||
yield ['json', 'json'];
|
||||
yield ['yaml', 'yml'];
|
||||
yield ['yaml', 'YAML'];
|
||||
yield ['xlsx', 'xlsx'];
|
||||
yield ['xlsx', 'XLSX'];
|
||||
yield ['xls', 'xls'];
|
||||
yield ['xls', 'XLS'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider formatDataProvider
|
||||
*/
|
||||
#[DataProvider('formatDataProvider')]
|
||||
public function testDetermineFormat(string $expected, string $extension): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->determineFormat($extension));
|
||||
|
|
@ -344,4 +349,41 @@ EOT;
|
|||
$this->assertSame($category, $results[0]->getCategory());
|
||||
$this->assertSame('test,test2', $results[0]->getTags());
|
||||
}
|
||||
|
||||
public function testImportExcelFileProjects(): void
|
||||
{
|
||||
$spreadsheet = new Spreadsheet();
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
|
||||
$worksheet->setCellValue('A1', 'name');
|
||||
$worksheet->setCellValue('B1', 'comment');
|
||||
$worksheet->setCellValue('A2', 'Test Excel 1');
|
||||
$worksheet->setCellValue('B2', 'Test Excel 1 notes');
|
||||
$worksheet->setCellValue('A3', 'Test Excel 2');
|
||||
$worksheet->setCellValue('B3', 'Test Excel 2 notes');
|
||||
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'test_excel') . '.xlsx';
|
||||
$writer = new Xlsx($spreadsheet);
|
||||
$writer->save($tempFile);
|
||||
|
||||
$file = new File($tempFile);
|
||||
|
||||
$errors = [];
|
||||
$results = $this->service->importFile($file, [
|
||||
'class' => Project::class,
|
||||
'format' => 'xlsx',
|
||||
'csv_delimiter' => ';',
|
||||
], $errors);
|
||||
|
||||
$this->assertCount(2, $results);
|
||||
$this->assertEmpty($errors);
|
||||
$this->assertContainsOnlyInstancesOf(Project::class, $results);
|
||||
|
||||
$this->assertSame('Test Excel 1', $results[0]->getName());
|
||||
$this->assertSame('Test Excel 1 notes', $results[0]->getComment());
|
||||
$this->assertSame('Test Excel 2', $results[1]->getName());
|
||||
$this->assertSame('Test Excel 2 notes', $results[1]->getComment());
|
||||
|
||||
unlink($tempFile);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2025 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Services\InfoProviderSystem\DTOs;
|
||||
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchFieldMappingDTO;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BulkSearchFieldMappingDTOTest extends TestCase
|
||||
{
|
||||
|
||||
public function testIsSupplierPartNumberField(): void
|
||||
{
|
||||
$fieldMapping = new BulkSearchFieldMappingDTO(field: 'reichelt_spn', providers: ['provider1'], priority: 1);
|
||||
$this->assertTrue($fieldMapping->isSupplierPartNumberField());
|
||||
|
||||
$fieldMapping = new BulkSearchFieldMappingDTO(field: 'partNumber', providers: ['provider1'], priority: 1);
|
||||
$this->assertFalse($fieldMapping->isSupplierPartNumberField());
|
||||
}
|
||||
|
||||
public function testToSerializableArray(): void
|
||||
{
|
||||
$fieldMapping = new BulkSearchFieldMappingDTO(field: 'test', providers: ['provider1', 'provider2'], priority: 3);
|
||||
$array = $fieldMapping->toSerializableArray();
|
||||
$this->assertIsArray($array);
|
||||
$this->assertSame([
|
||||
'field' => 'test',
|
||||
'providers' => ['provider1', 'provider2'],
|
||||
'priority' => 3,
|
||||
], $array);
|
||||
}
|
||||
|
||||
public function testFromSerializableArray(): void
|
||||
{
|
||||
$data = [
|
||||
'field' => 'test',
|
||||
'providers' => ['provider1', 'provider2'],
|
||||
'priority' => 3,
|
||||
];
|
||||
$fieldMapping = BulkSearchFieldMappingDTO::fromSerializableArray($data);
|
||||
$this->assertInstanceOf(BulkSearchFieldMappingDTO::class, $fieldMapping);
|
||||
$this->assertSame('test', $fieldMapping->field);
|
||||
$this->assertSame(['provider1', 'provider2'], $fieldMapping->providers);
|
||||
$this->assertSame(3, $fieldMapping->priority);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2025 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Services\InfoProviderSystem\DTOs;
|
||||
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultsDTO;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BulkSearchPartResultsDTOTest extends TestCase
|
||||
{
|
||||
|
||||
public function testHasErrors(): void
|
||||
{
|
||||
$test = new BulkSearchPartResultsDTO($this->createMock(\App\Entity\Parts\Part::class), [], []);
|
||||
$this->assertFalse($test->hasErrors());
|
||||
$test = new BulkSearchPartResultsDTO($this->createMock(\App\Entity\Parts\Part::class), [], ['error1']);
|
||||
$this->assertTrue($test->hasErrors());
|
||||
}
|
||||
|
||||
public function testGetErrorCount(): void
|
||||
{
|
||||
$test = new BulkSearchPartResultsDTO($this->createMock(\App\Entity\Parts\Part::class), [], []);
|
||||
$this->assertCount(0, $test->errors);
|
||||
$test = new BulkSearchPartResultsDTO($this->createMock(\App\Entity\Parts\Part::class), [], ['error1', 'error2']);
|
||||
$this->assertCount(2, $test->errors);
|
||||
}
|
||||
|
||||
public function testHasResults(): void
|
||||
{
|
||||
$test = new BulkSearchPartResultsDTO($this->createMock(\App\Entity\Parts\Part::class), [], []);
|
||||
$this->assertFalse($test->hasResults());
|
||||
$test = new BulkSearchPartResultsDTO($this->createMock(\App\Entity\Parts\Part::class), [ $this->createMock(\App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultDTO::class) ], []);
|
||||
$this->assertTrue($test->hasResults());
|
||||
}
|
||||
|
||||
public function testGetResultCount(): void
|
||||
{
|
||||
$test = new BulkSearchPartResultsDTO($this->createMock(\App\Entity\Parts\Part::class), [], []);
|
||||
$this->assertCount(0, $test->searchResults);
|
||||
$test = new BulkSearchPartResultsDTO($this->createMock(\App\Entity\Parts\Part::class), [
|
||||
$this->createMock(\App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultDTO::class),
|
||||
$this->createMock(\App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultDTO::class)
|
||||
], []);
|
||||
$this->assertCount(2, $test->searchResults);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2025 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Services\InfoProviderSystem\DTOs;
|
||||
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchResponseDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\BulkSearchPartResultsDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\SearchResultDTO;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
|
||||
class BulkSearchResponseDTOTest extends KernelTestCase
|
||||
{
|
||||
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
private BulkSearchResponseDTO $dummyEmpty;
|
||||
private BulkSearchResponseDTO $dummy;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
|
||||
|
||||
$this->dummyEmpty = new BulkSearchResponseDTO(partResults: []);
|
||||
$this->dummy = new BulkSearchResponseDTO(partResults: [
|
||||
new BulkSearchPartResultsDTO(
|
||||
part: $this->entityManager->find(Part::class, 1),
|
||||
searchResults: [
|
||||
new BulkSearchPartResultDTO(
|
||||
searchResult: new SearchResultDTO(provider_key: "dummy", provider_id: "1234", name: "Test Part", description: "A part for testing"),
|
||||
sourceField: "mpn", sourceKeyword: "1234", priority: 1
|
||||
),
|
||||
new BulkSearchPartResultDTO(
|
||||
searchResult: new SearchResultDTO(provider_key: "test", provider_id: "test", name: "Test Part2", description: "A part for testing"),
|
||||
sourceField: "name", sourceKeyword: "1234",
|
||||
localPart: $this->entityManager->find(Part::class, 2), priority: 2,
|
||||
),
|
||||
],
|
||||
errors: ['Error 1']
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
public function testSerializationBackAndForthEmpty(): void
|
||||
{
|
||||
$serialized = $this->dummyEmpty->toSerializableRepresentation();
|
||||
//Ensure that it is json_encodable
|
||||
$json = json_encode($serialized, JSON_THROW_ON_ERROR);
|
||||
$this->assertJson($json);
|
||||
$deserialized = BulkSearchResponseDTO::fromSerializableRepresentation(json_decode($json), $this->entityManager);
|
||||
|
||||
$this->assertEquals($this->dummyEmpty, $deserialized);
|
||||
}
|
||||
|
||||
public function testSerializationBackAndForth(): void
|
||||
{
|
||||
$serialized = $this->dummy->toSerializableRepresentation();
|
||||
//Ensure that it is json_encodable
|
||||
$this->assertJson(json_encode($serialized, JSON_THROW_ON_ERROR));
|
||||
$deserialized = BulkSearchResponseDTO::fromSerializableRepresentation($serialized, $this->entityManager);
|
||||
|
||||
$this->assertEquals($this->dummy, $deserialized);
|
||||
}
|
||||
|
||||
public function testToSerializableRepresentation(): void
|
||||
{
|
||||
$serialized = $this->dummy->toSerializableRepresentation();
|
||||
|
||||
$expected = array (
|
||||
0 =>
|
||||
array (
|
||||
'part_id' => 1,
|
||||
'search_results' =>
|
||||
array (
|
||||
0 =>
|
||||
array (
|
||||
'dto' =>
|
||||
array (
|
||||
'provider_key' => 'dummy',
|
||||
'provider_id' => '1234',
|
||||
'name' => 'Test Part',
|
||||
'description' => 'A part for testing',
|
||||
'category' => NULL,
|
||||
'manufacturer' => NULL,
|
||||
'mpn' => NULL,
|
||||
'preview_image_url' => NULL,
|
||||
'manufacturing_status' => NULL,
|
||||
'provider_url' => NULL,
|
||||
'footprint' => NULL,
|
||||
),
|
||||
'source_field' => 'mpn',
|
||||
'source_keyword' => '1234',
|
||||
'localPart' => NULL,
|
||||
'priority' => 1,
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'dto' =>
|
||||
array (
|
||||
'provider_key' => 'test',
|
||||
'provider_id' => 'test',
|
||||
'name' => 'Test Part2',
|
||||
'description' => 'A part for testing',
|
||||
'category' => NULL,
|
||||
'manufacturer' => NULL,
|
||||
'mpn' => NULL,
|
||||
'preview_image_url' => NULL,
|
||||
'manufacturing_status' => NULL,
|
||||
'provider_url' => NULL,
|
||||
'footprint' => NULL,
|
||||
),
|
||||
'source_field' => 'name',
|
||||
'source_keyword' => '1234',
|
||||
'localPart' => 2,
|
||||
'priority' => 2,
|
||||
),
|
||||
),
|
||||
'errors' =>
|
||||
array (
|
||||
0 => 'Error 1',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertEquals($expected, $serialized);
|
||||
}
|
||||
|
||||
public function testFromSerializableRepresentation(): void
|
||||
{
|
||||
$input = array (
|
||||
0 =>
|
||||
array (
|
||||
'part_id' => 1,
|
||||
'search_results' =>
|
||||
array (
|
||||
0 =>
|
||||
array (
|
||||
'dto' =>
|
||||
array (
|
||||
'provider_key' => 'dummy',
|
||||
'provider_id' => '1234',
|
||||
'name' => 'Test Part',
|
||||
'description' => 'A part for testing',
|
||||
'category' => NULL,
|
||||
'manufacturer' => NULL,
|
||||
'mpn' => NULL,
|
||||
'preview_image_url' => NULL,
|
||||
'manufacturing_status' => NULL,
|
||||
'provider_url' => NULL,
|
||||
'footprint' => NULL,
|
||||
),
|
||||
'source_field' => 'mpn',
|
||||
'source_keyword' => '1234',
|
||||
'localPart' => NULL,
|
||||
'priority' => 1,
|
||||
),
|
||||
1 =>
|
||||
array (
|
||||
'dto' =>
|
||||
array (
|
||||
'provider_key' => 'test',
|
||||
'provider_id' => 'test',
|
||||
'name' => 'Test Part2',
|
||||
'description' => 'A part for testing',
|
||||
'category' => NULL,
|
||||
'manufacturer' => NULL,
|
||||
'mpn' => NULL,
|
||||
'preview_image_url' => NULL,
|
||||
'manufacturing_status' => NULL,
|
||||
'provider_url' => NULL,
|
||||
'footprint' => NULL,
|
||||
),
|
||||
'source_field' => 'name',
|
||||
'source_keyword' => '1234',
|
||||
'localPart' => 2,
|
||||
'priority' => 2,
|
||||
),
|
||||
),
|
||||
'errors' =>
|
||||
array (
|
||||
0 => 'Error 1',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$deserialized = BulkSearchResponseDTO::fromSerializableRepresentation($input, $this->entityManager);
|
||||
$this->assertEquals($this->dummy, $deserialized);
|
||||
}
|
||||
|
||||
public function testMerge(): void
|
||||
{
|
||||
$merged = BulkSearchResponseDTO::merge($this->dummy, $this->dummyEmpty);
|
||||
$this->assertCount(1, $merged->partResults);
|
||||
|
||||
$merged = BulkSearchResponseDTO::merge($this->dummyEmpty, $this->dummyEmpty);
|
||||
$this->assertCount(0, $merged->partResults);
|
||||
|
||||
$merged = BulkSearchResponseDTO::merge($this->dummy, $this->dummy, $this->dummy);
|
||||
$this->assertCount(3, $merged->partResults);
|
||||
}
|
||||
|
||||
public function testReplaceResultsForPart(): void
|
||||
{
|
||||
$newPartResults = new BulkSearchPartResultsDTO(
|
||||
part: $this->entityManager->find(Part::class, 1),
|
||||
searchResults: [
|
||||
new BulkSearchPartResultDTO(
|
||||
searchResult: new SearchResultDTO(provider_key: "new", provider_id: "new", name: "New Part", description: "A new part"),
|
||||
sourceField: "mpn", sourceKeyword: "new", priority: 1
|
||||
)
|
||||
],
|
||||
errors: ['New Error']
|
||||
);
|
||||
|
||||
$replaced = $this->dummy->replaceResultsForPart($newPartResults);
|
||||
$this->assertCount(1, $replaced->partResults);
|
||||
$this->assertSame($newPartResults, $replaced->partResults[0]);
|
||||
}
|
||||
|
||||
public function testReplaceResultsForPartNotExisting(): void
|
||||
{
|
||||
$newPartResults = new BulkSearchPartResultsDTO(
|
||||
part: $this->entityManager->find(Part::class, 1),
|
||||
searchResults: [
|
||||
new BulkSearchPartResultDTO(
|
||||
searchResult: new SearchResultDTO(provider_key: "new", provider_id: "new", name: "New Part", description: "A new part"),
|
||||
sourceField: "mpn", sourceKeyword: "new", priority: 1
|
||||
)
|
||||
],
|
||||
errors: ['New Error']
|
||||
);
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$replaced = $this->dummyEmpty->replaceResultsForPart($newPartResults);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace App\Tests\Services\InfoProviderSystem\DTOs;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
|
|
@ -40,9 +41,7 @@ class FileDTOTest extends TestCase
|
|||
yield ["test%7Cse", "test|se"];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider escapingDataProvider
|
||||
*/
|
||||
#[DataProvider('escapingDataProvider')]
|
||||
public function testURLEscaping(string $expected, string $input): void
|
||||
{
|
||||
$fileDTO = new FileDTO( $input);
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace App\Tests\Services\InfoProviderSystem\DTOs;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ParameterDTOTest extends TestCase
|
||||
{
|
||||
|
||||
public function parseValueFieldDataProvider(): \Generator
|
||||
public static function parseValueFieldDataProvider(): \Generator
|
||||
{
|
||||
//Text value
|
||||
yield [
|
||||
|
|
@ -131,7 +132,7 @@ class ParameterDTOTest extends TestCase
|
|||
];
|
||||
}
|
||||
|
||||
public function parseValueIncludingUnitDataProvider(): \Generator
|
||||
public static function parseValueIncludingUnitDataProvider(): \Generator
|
||||
{
|
||||
//Text value
|
||||
yield [
|
||||
|
|
@ -234,18 +235,18 @@ class ParameterDTOTest extends TestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @dataProvider parseValueFieldDataProvider
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('parseValueFieldDataProvider')]
|
||||
public function testParseValueField(ParameterDTO $expected, string $name, string|float $value, ?string $unit = null, ?string $symbol = null, ?string $group = null)
|
||||
{
|
||||
$this->assertEquals($expected, ParameterDTO::parseValueField($name, $value, $unit, $symbol, $group));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider parseValueIncludingUnitDataProvider
|
||||
* @return void
|
||||
*/
|
||||
#[DataProvider('parseValueIncludingUnitDataProvider')]
|
||||
public function testParseValueIncludingUnit(ParameterDTO $expected, string $name, string|float $value, ?string $symbol = null, ?string $group = null)
|
||||
{
|
||||
$this->assertEquals($expected, ParameterDTO::parseValueIncludingUnit($name, $value, $symbol, $group));
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace App\Tests\Services\InfoProviderSystem;
|
||||
|
||||
use App\Entity\PriceInformations\Currency;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
use App\Entity\Parts\ManufacturingStatus;
|
||||
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||
|
|
@ -83,6 +84,7 @@ class DTOtoEntityConverterTest extends WebTestCase
|
|||
|
||||
//For non-base currencies, a new currency entity is created
|
||||
$currency = $entity->getCurrency();
|
||||
$this->assertInstanceOf(Currency::class, $currency);
|
||||
$this->assertEquals($dto->currency_iso_code, $currency->getIsoCode());
|
||||
}
|
||||
|
||||
|
|
|
|||
540
tests/Services/InfoProviderSystem/Providers/LCSCProviderTest.php
Normal file
540
tests/Services/InfoProviderSystem/Providers/LCSCProviderTest.php
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2023 Jan Böhmer (https://github.com/jbtronics)
|
||||
* Copyright (C) 2024 Nexrem (https://github.com/meganukebmp)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Services\InfoProviderSystem\Providers;
|
||||
|
||||
use App\Services\InfoProviderSystem\DTOs\FileDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\ParameterDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\PartDetailDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
|
||||
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
|
||||
use App\Services\InfoProviderSystem\Providers\LCSCProvider;
|
||||
use App\Services\InfoProviderSystem\Providers\ProviderCapabilities;
|
||||
use App\Settings\InfoProviderSystem\LCSCSettings;
|
||||
use App\Tests\SettingsTestHelper;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpClient\MockHttpClient;
|
||||
use Symfony\Component\HttpClient\Response\MockResponse;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
class LCSCProviderTest extends TestCase
|
||||
{
|
||||
private LCSCSettings $settings;
|
||||
private LCSCProvider $provider;
|
||||
private MockHttpClient $httpClient;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->httpClient = new MockHttpClient();
|
||||
$this->settings = SettingsTestHelper::createSettingsDummy(LCSCSettings::class);
|
||||
$this->settings->currency = 'USD';
|
||||
$this->settings->enabled = true;
|
||||
$this->provider = new LCSCProvider($this->httpClient, $this->settings);
|
||||
}
|
||||
|
||||
public function testGetProviderInfo(): void
|
||||
{
|
||||
$info = $this->provider->getProviderInfo();
|
||||
|
||||
$this->assertIsArray($info);
|
||||
$this->assertArrayHasKey('name', $info);
|
||||
$this->assertArrayHasKey('description', $info);
|
||||
$this->assertArrayHasKey('url', $info);
|
||||
$this->assertArrayHasKey('disabled_help', $info);
|
||||
$this->assertEquals('LCSC', $info['name']);
|
||||
$this->assertEquals('https://www.lcsc.com/', $info['url']);
|
||||
}
|
||||
|
||||
public function testGetProviderKey(): void
|
||||
{
|
||||
$this->assertEquals('lcsc', $this->provider->getProviderKey());
|
||||
}
|
||||
|
||||
public function testIsActiveWhenEnabled(): void
|
||||
{
|
||||
//Ensure that the settings are enabled
|
||||
$this->settings->enabled = true;
|
||||
$this->assertTrue($this->provider->isActive());
|
||||
}
|
||||
|
||||
public function testIsActiveWhenDisabled(): void
|
||||
{
|
||||
//Ensure that the settings are disabled
|
||||
$this->settings->enabled = false;
|
||||
$this->assertFalse($this->provider->isActive());
|
||||
}
|
||||
|
||||
public function testGetCapabilities(): void
|
||||
{
|
||||
$capabilities = $this->provider->getCapabilities();
|
||||
|
||||
$this->assertIsArray($capabilities);
|
||||
$this->assertContains(ProviderCapabilities::BASIC, $capabilities);
|
||||
$this->assertContains(ProviderCapabilities::PICTURE, $capabilities);
|
||||
$this->assertContains(ProviderCapabilities::DATASHEET, $capabilities);
|
||||
$this->assertContains(ProviderCapabilities::PRICE, $capabilities);
|
||||
$this->assertContains(ProviderCapabilities::FOOTPRINT, $capabilities);
|
||||
}
|
||||
|
||||
public function testSearchByKeywordWithCCode(): void
|
||||
{
|
||||
$mockResponse = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productCode' => 'C123456',
|
||||
'productModel' => 'Test Component',
|
||||
'productIntroEn' => 'Test description',
|
||||
'brandNameEn' => 'Test Manufacturer',
|
||||
'encapStandard' => '0603',
|
||||
'productImageUrl' => 'https://example.com/image.jpg',
|
||||
'productImages' => ['https://example.com/image1.jpg'],
|
||||
'productPriceList' => [
|
||||
['ladder' => 1, 'productPrice' => '0.10', 'currencySymbol' => 'US$']
|
||||
],
|
||||
'paramVOList' => [
|
||||
['paramNameEn' => 'Resistance', 'paramValueEn' => '1kΩ']
|
||||
],
|
||||
'pdfUrl' => 'https://example.com/datasheet.pdf',
|
||||
'weight' => 0.001
|
||||
]
|
||||
]));
|
||||
|
||||
$this->httpClient->setResponseFactory([$mockResponse]);
|
||||
|
||||
$results = $this->provider->searchByKeyword('C123456');
|
||||
|
||||
$this->assertIsArray($results);
|
||||
$this->assertCount(1, $results);
|
||||
$this->assertInstanceOf(PartDetailDTO::class, $results[0]);
|
||||
$this->assertEquals('C123456', $results[0]->provider_id);
|
||||
$this->assertEquals('Test Component', $results[0]->name);
|
||||
}
|
||||
|
||||
public function testSearchByKeywordWithRegularTerm(): void
|
||||
{
|
||||
$mockResponse = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productSearchResultVO' => [
|
||||
'productList' => [
|
||||
[
|
||||
'productCode' => 'C789012',
|
||||
'productModel' => 'Regular Component',
|
||||
'productIntroEn' => 'Regular description',
|
||||
'brandNameEn' => 'Regular Manufacturer',
|
||||
'encapStandard' => '0805',
|
||||
'productImageUrl' => 'https://example.com/regular.jpg',
|
||||
'productImages' => ['https://example.com/regular1.jpg'],
|
||||
'productPriceList' => [
|
||||
['ladder' => 10, 'productPrice' => '0.08', 'currencySymbol' => '€']
|
||||
],
|
||||
'paramVOList' => [],
|
||||
'pdfUrl' => null,
|
||||
'weight' => null
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]));
|
||||
|
||||
$this->httpClient->setResponseFactory([$mockResponse]);
|
||||
|
||||
$results = $this->provider->searchByKeyword('resistor');
|
||||
|
||||
$this->assertIsArray($results);
|
||||
$this->assertCount(1, $results);
|
||||
$this->assertInstanceOf(PartDetailDTO::class, $results[0]);
|
||||
$this->assertEquals('C789012', $results[0]->provider_id);
|
||||
$this->assertEquals('Regular Component', $results[0]->name);
|
||||
}
|
||||
|
||||
public function testSearchByKeywordWithTipProduct(): void
|
||||
{
|
||||
$mockResponse = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productSearchResultVO' => [
|
||||
'productList' => []
|
||||
],
|
||||
'tipProductDetailUrlVO' => [
|
||||
'productCode' => 'C555555'
|
||||
]
|
||||
]
|
||||
]));
|
||||
|
||||
$detailResponse = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productCode' => 'C555555',
|
||||
'productModel' => 'Tip Component',
|
||||
'productIntroEn' => 'Tip description',
|
||||
'brandNameEn' => 'Tip Manufacturer',
|
||||
'encapStandard' => '1206',
|
||||
'productImageUrl' => null,
|
||||
'productImages' => [],
|
||||
'productPriceList' => [],
|
||||
'paramVOList' => [],
|
||||
'pdfUrl' => null,
|
||||
'weight' => null
|
||||
]
|
||||
]));
|
||||
|
||||
$this->httpClient->setResponseFactory([$mockResponse, $detailResponse]);
|
||||
|
||||
$results = $this->provider->searchByKeyword('special');
|
||||
|
||||
$this->assertIsArray($results);
|
||||
$this->assertCount(1, $results);
|
||||
$this->assertInstanceOf(PartDetailDTO::class, $results[0]);
|
||||
$this->assertEquals('C555555', $results[0]->provider_id);
|
||||
$this->assertEquals('Tip Component', $results[0]->name);
|
||||
}
|
||||
|
||||
public function testSearchByKeywordsBatch(): void
|
||||
{
|
||||
$mockResponse1 = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productCode' => 'C123456',
|
||||
'productModel' => 'Batch Component 1',
|
||||
'productIntroEn' => 'Batch description 1',
|
||||
'brandNameEn' => 'Batch Manufacturer',
|
||||
'encapStandard' => '0603',
|
||||
'productImageUrl' => null,
|
||||
'productImages' => [],
|
||||
'productPriceList' => [],
|
||||
'paramVOList' => [],
|
||||
'pdfUrl' => null,
|
||||
'weight' => null
|
||||
]
|
||||
]));
|
||||
|
||||
$mockResponse2 = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productSearchResultVO' => [
|
||||
'productList' => [
|
||||
[
|
||||
'productCode' => 'C789012',
|
||||
'productModel' => 'Batch Component 2',
|
||||
'productIntroEn' => 'Batch description 2',
|
||||
'brandNameEn' => 'Batch Manufacturer',
|
||||
'encapStandard' => '0805',
|
||||
'productImageUrl' => null,
|
||||
'productImages' => [],
|
||||
'productPriceList' => [],
|
||||
'paramVOList' => [],
|
||||
'pdfUrl' => null,
|
||||
'weight' => null
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]));
|
||||
|
||||
$this->httpClient->setResponseFactory([$mockResponse1, $mockResponse2]);
|
||||
|
||||
$results = $this->provider->searchByKeywordsBatch(['C123456', 'resistor']);
|
||||
|
||||
$this->assertIsArray($results);
|
||||
$this->assertArrayHasKey('C123456', $results);
|
||||
$this->assertArrayHasKey('resistor', $results);
|
||||
$this->assertCount(1, $results['C123456']);
|
||||
$this->assertCount(1, $results['resistor']);
|
||||
$this->assertEquals('C123456', $results['C123456'][0]->provider_id);
|
||||
$this->assertEquals('C789012', $results['resistor'][0]->provider_id);
|
||||
}
|
||||
|
||||
public function testGetDetails(): void
|
||||
{
|
||||
$mockResponse = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productCode' => 'C123456',
|
||||
'productModel' => 'Detailed Component',
|
||||
'productIntroEn' => 'Detailed description',
|
||||
'brandNameEn' => 'Detailed Manufacturer',
|
||||
'encapStandard' => '0603',
|
||||
'productImageUrl' => 'https://example.com/detail.jpg',
|
||||
'productImages' => ['https://example.com/detail1.jpg'],
|
||||
'productPriceList' => [
|
||||
['ladder' => 1, 'productPrice' => '0.10', 'currencySymbol' => 'US$'],
|
||||
['ladder' => 10, 'productPrice' => '0.08', 'currencySymbol' => 'US$']
|
||||
],
|
||||
'paramVOList' => [
|
||||
['paramNameEn' => 'Resistance', 'paramValueEn' => '1kΩ'],
|
||||
['paramNameEn' => 'Tolerance', 'paramValueEn' => '1%']
|
||||
],
|
||||
'pdfUrl' => 'https://example.com/datasheet.pdf',
|
||||
'weight' => 0.001
|
||||
]
|
||||
]));
|
||||
|
||||
$this->httpClient->setResponseFactory([$mockResponse]);
|
||||
|
||||
$result = $this->provider->getDetails('C123456');
|
||||
|
||||
$this->assertInstanceOf(PartDetailDTO::class, $result);
|
||||
$this->assertEquals('C123456', $result->provider_id);
|
||||
$this->assertEquals('Detailed Component', $result->name);
|
||||
$this->assertEquals('Detailed description', $result->description);
|
||||
$this->assertEquals('Detailed Manufacturer', $result->manufacturer);
|
||||
$this->assertEquals('0603', $result->footprint);
|
||||
$this->assertEquals('https://www.lcsc.com/product-detail/C123456.html', $result->provider_url);
|
||||
$this->assertCount(1, $result->images);
|
||||
$this->assertCount(2, $result->parameters);
|
||||
$this->assertCount(1, $result->vendor_infos);
|
||||
$this->assertEquals('0.001', $result->mass);
|
||||
}
|
||||
|
||||
public function testGetDetailsWithNoResults(): void
|
||||
{
|
||||
$mockResponse = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productSearchResultVO' => [
|
||||
'productList' => []
|
||||
]
|
||||
]
|
||||
]));
|
||||
|
||||
$this->httpClient->setResponseFactory([$mockResponse]);
|
||||
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessage('No part found with ID INVALID');
|
||||
|
||||
$this->provider->getDetails('INVALID');
|
||||
}
|
||||
|
||||
public function testGetDetailsWithMultipleResults(): void
|
||||
{
|
||||
$mockResponse = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productSearchResultVO' => [
|
||||
'productList' => [
|
||||
[
|
||||
'productCode' => 'C123456',
|
||||
'productModel' => 'Component 1',
|
||||
'productIntroEn' => 'Description 1',
|
||||
'brandNameEn' => 'Manufacturer 1',
|
||||
'encapStandard' => '0603',
|
||||
'productImageUrl' => null,
|
||||
'productImages' => [],
|
||||
'productPriceList' => [],
|
||||
'paramVOList' => [],
|
||||
'pdfUrl' => null,
|
||||
'weight' => null
|
||||
],
|
||||
[
|
||||
'productCode' => 'C789012',
|
||||
'productModel' => 'Component 2',
|
||||
'productIntroEn' => 'Description 2',
|
||||
'brandNameEn' => 'Manufacturer 2',
|
||||
'encapStandard' => '0805',
|
||||
'productImageUrl' => null,
|
||||
'productImages' => [],
|
||||
'productPriceList' => [],
|
||||
'paramVOList' => [],
|
||||
'pdfUrl' => null,
|
||||
'weight' => null
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]));
|
||||
|
||||
$this->httpClient->setResponseFactory([$mockResponse]);
|
||||
|
||||
$this->expectException(\RuntimeException::class);
|
||||
$this->expectExceptionMessage('Multiple parts found with ID ambiguous');
|
||||
|
||||
$this->provider->getDetails('ambiguous');
|
||||
}
|
||||
|
||||
public function testSanitizeFieldPrivateMethod(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->provider);
|
||||
$method = $reflection->getMethod('sanitizeField');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$this->assertNull($method->invokeArgs($this->provider, [null]));
|
||||
$this->assertEquals('Clean text', $method->invokeArgs($this->provider, ['Clean text']));
|
||||
$this->assertEquals('Text without tags', $method->invokeArgs($this->provider, ['<b>Text</b> without <i>tags</i>']));
|
||||
}
|
||||
|
||||
public function testGetUsedCurrencyPrivateMethod(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->provider);
|
||||
$method = $reflection->getMethod('getUsedCurrency');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$this->assertEquals('USD', $method->invokeArgs($this->provider, ['US$']));
|
||||
$this->assertEquals('USD', $method->invokeArgs($this->provider, ['$']));
|
||||
$this->assertEquals('EUR', $method->invokeArgs($this->provider, ['€']));
|
||||
$this->assertEquals('GBP', $method->invokeArgs($this->provider, ['£']));
|
||||
$this->assertEquals('USD', $method->invokeArgs($this->provider, ['UNKNOWN'])); // fallback to configured currency
|
||||
}
|
||||
|
||||
public function testGetProductShortURLPrivateMethod(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->provider);
|
||||
$method = $reflection->getMethod('getProductShortURL');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invokeArgs($this->provider, ['C123456']);
|
||||
$this->assertEquals('https://www.lcsc.com/product-detail/C123456.html', $result);
|
||||
}
|
||||
|
||||
public function testGetProductDatasheetsPrivateMethod(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->provider);
|
||||
$method = $reflection->getMethod('getProductDatasheets');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invokeArgs($this->provider, [null]);
|
||||
$this->assertIsArray($result);
|
||||
$this->assertEmpty($result);
|
||||
|
||||
$result = $method->invokeArgs($this->provider, ['https://example.com/datasheet.pdf']);
|
||||
$this->assertIsArray($result);
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertInstanceOf(FileDTO::class, $result[0]);
|
||||
}
|
||||
|
||||
public function testGetProductImagesPrivateMethod(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->provider);
|
||||
$method = $reflection->getMethod('getProductImages');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invokeArgs($this->provider, [null]);
|
||||
$this->assertIsArray($result);
|
||||
$this->assertEmpty($result);
|
||||
|
||||
$result = $method->invokeArgs($this->provider, [['https://example.com/image1.jpg', 'https://example.com/image2.jpg']]);
|
||||
$this->assertIsArray($result);
|
||||
$this->assertCount(2, $result);
|
||||
$this->assertInstanceOf(FileDTO::class, $result[0]);
|
||||
$this->assertInstanceOf(FileDTO::class, $result[1]);
|
||||
}
|
||||
|
||||
public function testAttributesToParametersPrivateMethod(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->provider);
|
||||
$method = $reflection->getMethod('attributesToParameters');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$attributes = [
|
||||
['paramNameEn' => 'Resistance', 'paramValueEn' => '1kΩ'],
|
||||
['paramNameEn' => 'Tolerance', 'paramValueEn' => '1%'],
|
||||
['paramNameEn' => 'Empty', 'paramValueEn' => ''],
|
||||
['paramNameEn' => 'Dash', 'paramValueEn' => '-']
|
||||
];
|
||||
|
||||
$result = $method->invokeArgs($this->provider, [$attributes]);
|
||||
$this->assertIsArray($result);
|
||||
$this->assertCount(2, $result); // Only non-empty values
|
||||
$this->assertInstanceOf(ParameterDTO::class, $result[0]);
|
||||
$this->assertInstanceOf(ParameterDTO::class, $result[1]);
|
||||
}
|
||||
|
||||
public function testPricesToVendorInfoPrivateMethod(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->provider);
|
||||
$method = $reflection->getMethod('pricesToVendorInfo');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$prices = [
|
||||
['ladder' => 1, 'productPrice' => '0.10', 'currencySymbol' => 'US$'],
|
||||
['ladder' => 10, 'productPrice' => '0.08', 'currencySymbol' => 'US$']
|
||||
];
|
||||
|
||||
$result = $method->invokeArgs($this->provider, ['C123456', 'https://example.com', $prices]);
|
||||
$this->assertIsArray($result);
|
||||
$this->assertCount(1, $result);
|
||||
$this->assertInstanceOf(PurchaseInfoDTO::class, $result[0]);
|
||||
$this->assertEquals('LCSC', $result[0]->distributor_name);
|
||||
$this->assertEquals('C123456', $result[0]->order_number);
|
||||
$this->assertCount(2, $result[0]->prices);
|
||||
}
|
||||
|
||||
public function testCategoryBuilding(): void
|
||||
{
|
||||
$mockResponse = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productCode' => 'C123456',
|
||||
'productModel' => 'Test Component',
|
||||
'productIntroEn' => 'Test description',
|
||||
'brandNameEn' => 'Test Manufacturer',
|
||||
'parentCatalogName' => 'Electronic Components',
|
||||
'catalogName' => 'Resistors (SMT)',
|
||||
'encapStandard' => '0603',
|
||||
'productImageUrl' => null,
|
||||
'productImages' => [],
|
||||
'productPriceList' => [],
|
||||
'paramVOList' => [],
|
||||
'pdfUrl' => null,
|
||||
'weight' => null
|
||||
]
|
||||
]));
|
||||
|
||||
$this->httpClient->setResponseFactory([$mockResponse]);
|
||||
|
||||
$result = $this->provider->getDetails('C123456');
|
||||
$this->assertEquals('Electronic Components -> Resistors (SMT)', $result->category);
|
||||
}
|
||||
|
||||
public function testEmptyFootprintHandling(): void
|
||||
{
|
||||
$mockResponse = new MockResponse(json_encode([
|
||||
'result' => [
|
||||
'productCode' => 'C123456',
|
||||
'productModel' => 'Test Component',
|
||||
'productIntroEn' => 'Test description',
|
||||
'brandNameEn' => 'Test Manufacturer',
|
||||
'encapStandard' => '-',
|
||||
'productImageUrl' => null,
|
||||
'productImages' => [],
|
||||
'productPriceList' => [],
|
||||
'paramVOList' => [],
|
||||
'pdfUrl' => null,
|
||||
'weight' => null
|
||||
]
|
||||
]));
|
||||
|
||||
$this->httpClient->setResponseFactory([$mockResponse]);
|
||||
|
||||
$result = $this->provider->getDetails('C123456');
|
||||
$this->assertNull($result->footprint);
|
||||
}
|
||||
|
||||
public function testSearchByKeywordsBatchWithEmptyKeywords(): void
|
||||
{
|
||||
$result = $this->provider->searchByKeywordsBatch([]);
|
||||
$this->assertIsArray($result);
|
||||
$this->assertEmpty($result);
|
||||
}
|
||||
|
||||
public function testSearchByKeywordsBatchWithException(): void
|
||||
{
|
||||
$mockResponse = new MockResponse('', ['http_code' => 500]);
|
||||
$this->httpClient->setResponseFactory([$mockResponse]);
|
||||
|
||||
$results = $this->provider->searchByKeywordsBatch(['error']);
|
||||
$this->assertIsArray($results);
|
||||
$this->assertArrayHasKey('error', $results);
|
||||
$this->assertEmpty($results['error']);
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem\BarcodeScanner;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\LabelSystem\LabelSupportedElement;
|
||||
use App\Services\LabelSystem\BarcodeScanner\BarcodeRedirector;
|
||||
use App\Services\LabelSystem\BarcodeScanner\BarcodeSourceType;
|
||||
|
|
@ -66,10 +68,8 @@ final class BarcodeRedirectorTest extends KernelTestCase
|
|||
yield [new LocalBarcodeScanResult(LabelSupportedElement::STORELOCATION, 1, BarcodeSourceType::INTERNAL), '/en/store_location/1/parts'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider urlDataProvider
|
||||
* @group DB
|
||||
*/
|
||||
#[DataProvider('urlDataProvider')]
|
||||
#[Group('DB')]
|
||||
public function testGetRedirectURL(LocalBarcodeScanResult $scanResult, string $url): void
|
||||
{
|
||||
$this->assertSame($url, $this->service->getRedirectURL($scanResult));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem\BarcodeScanner;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\LabelSystem\LabelSupportedElement;
|
||||
use App\Services\LabelSystem\BarcodeScanner\BarcodeScanHelper;
|
||||
use App\Services\LabelSystem\BarcodeScanner\BarcodeScanResultInterface;
|
||||
|
|
@ -140,17 +141,13 @@ class BarcodeScanHelperTest extends WebTestCase
|
|||
yield [''];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testNormalizeBarcodeContent(BarcodeScanResultInterface $expected, string $input): void
|
||||
{
|
||||
$this->assertEquals($expected, $this->service->scanBarcodeContent($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider invalidDataProvider
|
||||
*/
|
||||
#[DataProvider('invalidDataProvider')]
|
||||
public function testInvalidFormats(string $input): void
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
|
|
@ -17,7 +20,6 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Services\LabelSystem\BarcodeScanner;
|
||||
|
||||
use App\Services\LabelSystem\BarcodeScanner\EIGP114BarcodeScanResult;
|
||||
|
|
@ -51,7 +53,7 @@ class EIGP114BarcodeScanResultTest extends TestCase
|
|||
'4L' => 'US',
|
||||
'13Z' => 'Digi-Key',
|
||||
]);
|
||||
$this->assertEquals('digikey', $barcode->guessBarcodeVendor());
|
||||
$this->assertSame('digikey', $barcode->guessBarcodeVendor());
|
||||
|
||||
//Mouser barcode:
|
||||
$barcode = new EIGP114BarcodeScanResult([
|
||||
|
|
@ -64,7 +66,7 @@ class EIGP114BarcodeScanResultTest extends TestCase
|
|||
'1V' => 'Mouser',
|
||||
]);
|
||||
|
||||
$this->assertEquals('mouser', $barcode->guessBarcodeVendor());
|
||||
$this->assertSame('mouser', $barcode->guessBarcodeVendor());
|
||||
|
||||
//Farnell barcode:
|
||||
$barcode = new EIGP114BarcodeScanResult([
|
||||
|
|
@ -77,7 +79,7 @@ class EIGP114BarcodeScanResultTest extends TestCase
|
|||
'3P' => 'Farnell',
|
||||
]);
|
||||
|
||||
$this->assertEquals('element14', $barcode->guessBarcodeVendor());
|
||||
$this->assertSame('element14', $barcode->guessBarcodeVendor());
|
||||
}
|
||||
|
||||
public function testIsFormat06Code(): void
|
||||
|
|
@ -102,7 +104,7 @@ class EIGP114BarcodeScanResultTest extends TestCase
|
|||
public function testParseFormat06Code(): void
|
||||
{
|
||||
$barcode = EIGP114BarcodeScanResult::parseFormat06Code("[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04");
|
||||
$this->assertEquals([
|
||||
$this->assertSame([
|
||||
'P' => '596-777A1-ND',
|
||||
'1P' => 'XAF4444',
|
||||
'Q' => '3',
|
||||
|
|
@ -123,32 +125,32 @@ class EIGP114BarcodeScanResultTest extends TestCase
|
|||
'4L' => 'US',
|
||||
]);
|
||||
|
||||
$this->assertEquals('596-777A1-ND', $barcode->customerPartNumber);
|
||||
$this->assertEquals('XAF4444', $barcode->supplierPartNumber);
|
||||
$this->assertEquals(3, $barcode->quantity);
|
||||
$this->assertEquals('1452', $barcode->alternativeDateCode);
|
||||
$this->assertEquals('BF1103', $barcode->lotCode);
|
||||
$this->assertEquals('US', $barcode->countryOfOrigin);
|
||||
$this->assertSame('596-777A1-ND', $barcode->customerPartNumber);
|
||||
$this->assertSame('XAF4444', $barcode->supplierPartNumber);
|
||||
$this->assertSame(3, $barcode->quantity);
|
||||
$this->assertSame('1452', $barcode->alternativeDateCode);
|
||||
$this->assertSame('BF1103', $barcode->lotCode);
|
||||
$this->assertSame('US', $barcode->countryOfOrigin);
|
||||
}
|
||||
|
||||
public function testDigikeyParsing(): void
|
||||
{
|
||||
$barcode = EIGP114BarcodeScanResult::parseFormat06Code("[)>\x1e06\x1dPQ1045-ND\x1d1P364019-01\x1d30PQ1045-ND\x1dK12432 TRAVIS FOSS P\x1d1K85732873\x1d10K103332956\x1d9D231013\x1d1TQJ13P\x1d11K1\x1d4LTW\x1dQ3\x1d11ZPICK\x1d12Z7360988\x1d13Z999999\x1d20Z0000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
|
||||
|
||||
$this->assertEquals('digikey', $barcode->guessBarcodeVendor());
|
||||
$this->assertSame('digikey', $barcode->guessBarcodeVendor());
|
||||
|
||||
$this->assertEquals('Q1045-ND', $barcode->customerPartNumber);
|
||||
$this->assertEquals('364019-01', $barcode->supplierPartNumber);
|
||||
$this->assertEquals(3, $barcode->quantity);
|
||||
$this->assertEquals('231013', $barcode->dateCode);
|
||||
$this->assertEquals('QJ13P', $barcode->lotCode);
|
||||
$this->assertEquals('TW', $barcode->countryOfOrigin);
|
||||
$this->assertEquals('Q1045-ND', $barcode->digikeyPartNumber);
|
||||
$this->assertEquals('85732873', $barcode->digikeySalesOrderNumber);
|
||||
$this->assertEquals('103332956', $barcode->digikeyInvoiceNumber);
|
||||
$this->assertEquals('PICK', $barcode->digikeyLabelType);
|
||||
$this->assertEquals('7360988', $barcode->digikeyPartID);
|
||||
$this->assertEquals('999999', $barcode->digikeyNA);
|
||||
$this->assertEquals('0000000000000000000000000000000000000000000000000000000000000000000000000000000000000', $barcode->digikeyPadding);
|
||||
$this->assertSame('Q1045-ND', $barcode->customerPartNumber);
|
||||
$this->assertSame('364019-01', $barcode->supplierPartNumber);
|
||||
$this->assertSame(3, $barcode->quantity);
|
||||
$this->assertSame('231013', $barcode->dateCode);
|
||||
$this->assertSame('QJ13P', $barcode->lotCode);
|
||||
$this->assertSame('TW', $barcode->countryOfOrigin);
|
||||
$this->assertSame('Q1045-ND', $barcode->digikeyPartNumber);
|
||||
$this->assertSame('85732873', $barcode->digikeySalesOrderNumber);
|
||||
$this->assertSame('103332956', $barcode->digikeyInvoiceNumber);
|
||||
$this->assertSame('PICK', $barcode->digikeyLabelType);
|
||||
$this->assertSame('7360988', $barcode->digikeyPartID);
|
||||
$this->assertSame('999999', $barcode->digikeyNA);
|
||||
$this->assertSame('0000000000000000000000000000000000000000000000000000000000000000000000000000000000000', $barcode->digikeyPadding);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem\Barcodes;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\Parts\PartLot;
|
||||
use App\Entity\Parts\StorageLocation;
|
||||
|
|
@ -57,31 +58,27 @@ class BarcodeContentGeneratorTest extends KernelTestCase
|
|||
$this->service = self::getContainer()->get(BarcodeContentGenerator::class);
|
||||
}
|
||||
|
||||
public function Barcode1DDataProvider(): \Iterator
|
||||
public static function Barcode1DDataProvider(): \Iterator
|
||||
{
|
||||
yield ['P0000', Part::class];
|
||||
yield ['L0000', PartLot::class];
|
||||
yield ['S0000', StorageLocation::class];
|
||||
}
|
||||
|
||||
public function Barcode2DDataProvider(): \Iterator
|
||||
public static function Barcode2DDataProvider(): \Iterator
|
||||
{
|
||||
yield ['/scan/part/0', Part::class];
|
||||
yield ['/scan/lot/0', PartLot::class];
|
||||
yield ['/scan/location/0', StorageLocation::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider Barcode1DDataProvider
|
||||
*/
|
||||
#[DataProvider('Barcode1DDataProvider')]
|
||||
public function testGet1DBarcodeContent(string $expected, string $class): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->get1DBarcodeContent(new $class()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider Barcode2DDataProvider
|
||||
*/
|
||||
#[DataProvider('Barcode2DDataProvider')]
|
||||
public function testGetURLContent(string $expected, string $class): void
|
||||
{
|
||||
$url = $this->service->getURLContent(new $class());
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Base\AbstractDBElement;
|
||||
use App\Entity\LabelSystem\LabelOptions;
|
||||
use App\Entity\LabelSystem\LabelSupportedElement;
|
||||
|
|
@ -70,9 +71,7 @@ class LabelGeneratorTest extends WebTestCase
|
|||
yield [LabelSupportedElement::STORELOCATION, StorageLocation::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider supportsDataProvider
|
||||
*/
|
||||
#[DataProvider('supportsDataProvider')]
|
||||
public function testSupports(LabelSupportedElement $type, string $class): void
|
||||
{
|
||||
$options = new LabelOptions();
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\Parts\PartLot;
|
||||
use App\Services\LabelSystem\LabelTextReplacer;
|
||||
|
|
@ -70,7 +71,7 @@ class LabelTextReplacerTest extends WebTestCase
|
|||
$this->target->setComment('P Comment');
|
||||
}
|
||||
|
||||
public function handlePlaceholderDataProvider(): \Iterator
|
||||
public static function handlePlaceholderDataProvider(): \Iterator
|
||||
{
|
||||
yield ['Part 1', '[[NAME]]'];
|
||||
yield ['P Description', '[[DESCRIPTION]]'];
|
||||
|
|
@ -82,7 +83,7 @@ class LabelTextReplacerTest extends WebTestCase
|
|||
yield ['Test [[NAME]]', 'Test [[NAME]]', 'Test [[NAME]]'];
|
||||
}
|
||||
|
||||
public function replaceDataProvider(): \Iterator
|
||||
public static function replaceDataProvider(): \Iterator
|
||||
{
|
||||
yield ['Part 1', '[[NAME]]'];
|
||||
yield ['TestPart 1', 'Test[[NAME]]'];
|
||||
|
|
@ -94,17 +95,13 @@ class LabelTextReplacerTest extends WebTestCase
|
|||
yield ['TEST[[ ]]TEST', 'TEST[[ ]]TEST'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider handlePlaceholderDataProvider
|
||||
*/
|
||||
#[DataProvider('handlePlaceholderDataProvider')]
|
||||
public function testHandlePlaceholder(string $expected, string $input): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->handlePlaceholder($input, $this->target));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider replaceDataProvider
|
||||
*/
|
||||
#[DataProvider('replaceDataProvider')]
|
||||
public function testReplace(string $expected, string $input): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->replace($input, $this->target));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem\PlaceholderProviders;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Base\AbstractDBElement;
|
||||
use App\Services\LabelSystem\PlaceholderProviders\AbstractDBElementProvider;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
|
@ -63,14 +64,12 @@ class AbstractElementProviderTest extends WebTestCase
|
|||
};
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
yield ['123', '[[ID]]'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testReplace(string $expected, string $placeholder): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->replace($placeholder, $this->target));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem\PlaceholderProviders;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Services\LabelSystem\PlaceholderProviders\GlobalProviders;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
|
@ -61,15 +62,13 @@ class GlobalProvidersTest extends WebTestCase
|
|||
$this->target = new Part();
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
yield ['Part-DB', '[[INSTALL_NAME]]'];
|
||||
yield ['anonymous', '[[USERNAME]]'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testReplace(string $expected, string $placeholder): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->replace($placeholder, $this->target));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem\PlaceholderProviders;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Contracts\NamedElementInterface;
|
||||
use App\Services\LabelSystem\PlaceholderProviders\NamedElementProvider;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
|
@ -66,14 +67,12 @@ class NamedElementProviderTest extends WebTestCase
|
|||
};
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
yield ['This is my Name', '[[NAME]]'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testReplace(string $expected, string $placeholder): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->replace($placeholder, $this->target));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem\PlaceholderProviders;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\Parts\PartLot;
|
||||
use App\Entity\Parts\StorageLocation;
|
||||
|
|
@ -85,7 +86,7 @@ class PartLotProviderTest extends WebTestCase
|
|||
$this->target->setOwner($user);
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
yield ['unknown', '[[LOT_ID]]'];
|
||||
yield ['Lot description', '[[LOT_NAME]]'];
|
||||
|
|
@ -101,9 +102,7 @@ class PartLotProviderTest extends WebTestCase
|
|||
yield ['user', '[[OWNER_USERNAME]]'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testReplace(string $expected, string $placeholder): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->replace($placeholder, $this->target));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem\PlaceholderProviders;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Parts\ManufacturingStatus;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use App\Entity\Parts\Category;
|
||||
|
|
@ -50,9 +52,7 @@ use App\Services\LabelSystem\PlaceholderProviders\PartProvider;
|
|||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
*/
|
||||
#[Group('DB')]
|
||||
class PartProviderTest extends WebTestCase
|
||||
{
|
||||
/**
|
||||
|
|
@ -87,7 +87,7 @@ class PartProviderTest extends WebTestCase
|
|||
$this->target->setComment('<b>Bold</b> *Italic*');
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
yield ['Node 2.1', '[[CATEGORY]]'];
|
||||
yield ['Node 2 → Node 2.1', '[[CATEGORY_FULL]]'];
|
||||
|
|
@ -105,9 +105,7 @@ class PartProviderTest extends WebTestCase
|
|||
yield ['Bold Italic', '[[COMMENT_T]]'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testReplace(string $expected, string $placeholder): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->replace($placeholder, $this->target));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem\PlaceholderProviders;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Contracts\TimeStampableInterface;
|
||||
use App\Services\LabelSystem\PlaceholderProviders\GlobalProviders;
|
||||
use App\Services\LabelSystem\PlaceholderProviders\TimestampableElementProvider;
|
||||
|
|
@ -59,33 +60,34 @@ class TimestampableElementProviderTest extends WebTestCase
|
|||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
\Locale::setDefault('en');
|
||||
\Locale::setDefault('en_US');
|
||||
$this->service = self::getContainer()->get(TimestampableElementProvider::class);
|
||||
$this->target = new class() implements TimeStampableInterface {
|
||||
$this->target = new class () implements TimeStampableInterface {
|
||||
public function getLastModified(): ?DateTime
|
||||
{
|
||||
return new \DateTime('2000-01-01');
|
||||
return new DateTime('2000-01-01');
|
||||
}
|
||||
|
||||
public function getAddedDate(): ?DateTime
|
||||
{
|
||||
return new \DateTime('2000-01-01');
|
||||
return new DateTime('2000-01-01');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
\Locale::setDefault('en');
|
||||
yield ['1/1/00, 12:00 AM', '[[LAST_MODIFIED]]'];
|
||||
yield ['1/1/00, 12:00 AM', '[[CREATION_DATE]]'];
|
||||
\Locale::setDefault('en_US');
|
||||
// Use IntlDateFormatter like the actual service does
|
||||
$formatter = new \IntlDateFormatter(\Locale::getDefault(), \IntlDateFormatter::SHORT, \IntlDateFormatter::SHORT);
|
||||
$expectedFormat = $formatter->format(new DateTime('2000-01-01'));
|
||||
yield [$expectedFormat, '[[LAST_MODIFIED]]'];
|
||||
yield [$expectedFormat, '[[CREATION_DATE]]'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testReplace(string $expected, string $placeholder): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->replace($placeholder, $this->target));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\LabelSystem;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\LabelSystem\LabelOptions;
|
||||
use App\Entity\LabelSystem\LabelProcessMode;
|
||||
use App\Entity\LabelSystem\LabelSupportedElement;
|
||||
|
|
@ -61,7 +62,7 @@ class SandboxedTwigFactoryTest extends WebTestCase
|
|||
$this->service = self::getContainer()->get(SandboxedTwigFactory::class);
|
||||
}
|
||||
|
||||
public function twigDataProvider(): \Iterator
|
||||
public static function twigDataProvider(): \Iterator
|
||||
{
|
||||
yield [' {% for i in range(1, 3) %}
|
||||
{{ part.id }}
|
||||
|
|
@ -94,7 +95,7 @@ class SandboxedTwigFactoryTest extends WebTestCase
|
|||
'];
|
||||
}
|
||||
|
||||
public function twigNotAllowedDataProvider(): \Iterator
|
||||
public static function twigNotAllowedDataProvider(): \Iterator
|
||||
{
|
||||
yield ['{% block test %} {% endblock %}'];
|
||||
yield ['{% deprecated test %}'];
|
||||
|
|
@ -103,9 +104,7 @@ class SandboxedTwigFactoryTest extends WebTestCase
|
|||
yield ['{{ part.setCategory(null) }}'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider twigDataProvider
|
||||
*/
|
||||
#[DataProvider('twigDataProvider')]
|
||||
public function testTwigFeatures(string $twig): void
|
||||
{
|
||||
$options = new LabelOptions();
|
||||
|
|
@ -123,9 +122,7 @@ class SandboxedTwigFactoryTest extends WebTestCase
|
|||
$this->assertIsString($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider twigNotAllowedDataProvider
|
||||
*/
|
||||
#[DataProvider('twigNotAllowedDataProvider')]
|
||||
public function testTwigForbidden(string $twig): void
|
||||
{
|
||||
$this->expectException(SecurityError::class);
|
||||
|
|
|
|||
|
|
@ -23,23 +23,22 @@ declare(strict_types=1);
|
|||
namespace App\Tests\Services\LogSystem;
|
||||
|
||||
use App\Services\LogSystem\EventCommentNeededHelper;
|
||||
use App\Services\LogSystem\EventCommentType;
|
||||
use App\Settings\SystemSettings\HistorySettings;
|
||||
use App\Tests\SettingsTestHelper;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class EventCommentNeededHelperTest extends TestCase
|
||||
{
|
||||
public function testIsCommentNeeded(): void
|
||||
{
|
||||
$service = new EventCommentNeededHelper(['part_edit', 'part_create']);
|
||||
$this->assertTrue($service->isCommentNeeded('part_edit'));
|
||||
$this->assertTrue($service->isCommentNeeded('part_create'));
|
||||
$this->assertFalse($service->isCommentNeeded('part_delete'));
|
||||
$this->assertFalse($service->isCommentNeeded('part_stock_operation'));
|
||||
}
|
||||
$settings = SettingsTestHelper::createSettingsDummy(HistorySettings::class);
|
||||
$settings->enforceComments = [EventCommentType::PART_CREATE, EventCommentType::PART_EDIT];
|
||||
|
||||
public function testIsCommentNeededInvalidTypeException(): void
|
||||
{
|
||||
$service = new EventCommentNeededHelper(['part_edit', 'part_create']);
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$service->isCommentNeeded('this_is_not_valid');
|
||||
$service = new EventCommentNeededHelper($settings);
|
||||
$this->assertTrue($service->isCommentNeeded(EventCommentType::PART_CREATE));
|
||||
$this->assertTrue($service->isCommentNeeded(EventCommentType::PART_EDIT));
|
||||
$this->assertFalse($service->isCommentNeeded(EventCommentType::DATASTRUCTURE_EDIT));
|
||||
$this->assertFalse($service->isCommentNeeded(EventCommentType::PART_STOCK_OPERATION));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
|
|
@ -17,7 +20,6 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace App\Tests\Services\LogSystem;
|
||||
|
||||
use App\Entity\LogSystem\ElementEditedLogEntry;
|
||||
|
|
@ -45,7 +47,7 @@ class TimeTravelTest extends KernelTestCase
|
|||
$undeletedCategory = $this->service->undeleteEntity(Category::class, 100);
|
||||
|
||||
$this->assertInstanceOf(Category::class, $undeletedCategory);
|
||||
$this->assertEquals(100, $undeletedCategory->getId());
|
||||
$this->assertSame(100, $undeletedCategory->getId());
|
||||
}
|
||||
|
||||
public function testApplyEntry(): void
|
||||
|
|
@ -63,8 +65,8 @@ class TimeTravelTest extends KernelTestCase
|
|||
|
||||
$this->service->applyEntry($category, $logEntry);
|
||||
|
||||
$this->assertEquals('Old Category', $category->getName());
|
||||
$this->assertEquals('Old Comment', $category->getComment());
|
||||
$this->assertSame('Old Category', $category->getName());
|
||||
$this->assertSame('Old Comment', $category->getComment());
|
||||
}
|
||||
|
||||
public function testRevertEntityToTimestamp(): void
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\Misc;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Services\Misc\FAIconGenerator;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
|
|
@ -41,7 +42,7 @@ class FAIconGeneratorTest extends WebTestCase
|
|||
$this->service = self::getContainer()->get(FAIconGenerator::class);
|
||||
}
|
||||
|
||||
public function fileExtensionDataProvider(): \Iterator
|
||||
public static function fileExtensionDataProvider(): \Iterator
|
||||
{
|
||||
yield ['pdf', 'fa-file-pdf'];
|
||||
yield ['jpeg','fa-file-image'];
|
||||
|
|
@ -95,9 +96,7 @@ class FAIconGeneratorTest extends WebTestCase
|
|||
yield ['fgd', 'fa-file'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider fileExtensionDataProvider
|
||||
*/
|
||||
#[DataProvider('fileExtensionDataProvider')]
|
||||
public function testFileExtensionToFAType(string $ext, string $expected): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->fileExtensionToFAType($ext), 'Failed for extension .'.$ext);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\Misc;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Services\Misc\RangeParser;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ class RangeParserTest extends WebTestCase
|
|||
$this->service = self::getContainer()->get(RangeParser::class);
|
||||
}
|
||||
|
||||
public function dataProvider(): \Iterator
|
||||
public static function dataProvider(): \Iterator
|
||||
{
|
||||
yield [[], ''];
|
||||
yield [[], ' '];
|
||||
|
|
@ -81,7 +82,7 @@ class RangeParserTest extends WebTestCase
|
|||
yield [[], '1, 2, test', true];
|
||||
}
|
||||
|
||||
public function validDataProvider(): \Iterator
|
||||
public static function validDataProvider(): \Iterator
|
||||
{
|
||||
yield [true, ''];
|
||||
yield [true, ' '];
|
||||
|
|
@ -96,9 +97,7 @@ class RangeParserTest extends WebTestCase
|
|||
yield [false, '1, 2 test'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProvider
|
||||
*/
|
||||
#[DataProvider('dataProvider')]
|
||||
public function testParse(array $expected, string $input, bool $must_throw = false): void
|
||||
{
|
||||
if ($must_throw) {
|
||||
|
|
@ -109,9 +108,7 @@ class RangeParserTest extends WebTestCase
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validDataProvider
|
||||
*/
|
||||
#[DataProvider('validDataProvider')]
|
||||
public function testIsValidRange(bool $expected, string $input): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->isValidRange($input));
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\Parameters;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Parameters\AbstractParameter;
|
||||
use App\Services\Parameters\ParameterExtractor;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
|
@ -56,7 +57,7 @@ class ParameterExtractorTest extends WebTestCase
|
|||
$this->service = self::getContainer()->get(ParameterExtractor::class);
|
||||
}
|
||||
|
||||
public function emptyDataProvider(): \Iterator
|
||||
public static function emptyDataProvider(): \Iterator
|
||||
{
|
||||
yield [''];
|
||||
yield [' '];
|
||||
|
|
@ -69,9 +70,7 @@ class ParameterExtractorTest extends WebTestCase
|
|||
yield ['A [link](https://demo.part-db.de) should not be matched'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider emptyDataProvider
|
||||
*/
|
||||
#[DataProvider('emptyDataProvider')]
|
||||
public function testShouldReturnEmpty(string $input): void
|
||||
{
|
||||
$this->assertEmpty($this->service->extractParameters($input));
|
||||
|
|
|
|||
|
|
@ -51,8 +51,7 @@ class PartsTableActionHandlerTest extends WebTestCase
|
|||
|
||||
foreach ($formats as $format) {
|
||||
$action = "export_{$format}";
|
||||
$result = $this->service->handleAction($action, $selected_parts, '1', '/test');
|
||||
|
||||
$result = $this->service->handleAction($action, $selected_parts, '1', '/test');
|
||||
$this->assertInstanceOf(RedirectResponse::class, $result);
|
||||
$this->assertStringContainsString('parts/export', $result->getTargetUrl());
|
||||
$this->assertStringContainsString("format={$format}", $result->getTargetUrl());
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\Parts;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\PriceInformations\Orderdetail;
|
||||
use App\Entity\PriceInformations\Pricedetail;
|
||||
|
|
@ -43,7 +44,7 @@ class PricedetailHelperTest extends WebTestCase
|
|||
$this->service = self::getContainer()->get(PricedetailHelper::class);
|
||||
}
|
||||
|
||||
public function maxDiscountAmountDataProvider(): ?\Generator
|
||||
public static function maxDiscountAmountDataProvider(): ?\Generator
|
||||
{
|
||||
$part = new Part();
|
||||
yield [$part, null, 'Part without any orderdetails failed!'];
|
||||
|
|
@ -81,9 +82,7 @@ class PricedetailHelperTest extends WebTestCase
|
|||
yield [$part, 10.0, 'Part with multiple orderdetails failed'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider maxDiscountAmountDataProvider
|
||||
*/
|
||||
#[DataProvider('maxDiscountAmountDataProvider')]
|
||||
public function testGetMaxDiscountAmount(Part $part, ?float $expected_result, string $message): void
|
||||
{
|
||||
$this->assertSame($expected_result, $this->service->getMaxDiscountAmount($part), $message);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\Trees;
|
||||
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use App\Entity\Attachments\AttachmentType;
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Helpers\Trees\TreeViewNode;
|
||||
|
|
@ -29,9 +30,7 @@ use App\Services\Trees\TreeViewGenerator;
|
|||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* @group DB
|
||||
*/
|
||||
#[Group('DB')]
|
||||
class TreeViewGeneratorTest extends WebTestCase
|
||||
{
|
||||
protected $em;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\UserSystem;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Entity\UserSystem\Group;
|
||||
use App\Entity\UserSystem\PermissionData;
|
||||
use App\Entity\UserSystem\User;
|
||||
|
|
@ -91,7 +92,7 @@ class PermissionManagerTest extends WebTestCase
|
|||
$this->group->method('getParent')->willReturn($parent_group);
|
||||
}
|
||||
|
||||
public function getPermissionNames(): \Iterator
|
||||
public static function getPermissionNames(): \Iterator
|
||||
{
|
||||
//List some permission names
|
||||
yield ['parts'];
|
||||
|
|
@ -101,9 +102,7 @@ class PermissionManagerTest extends WebTestCase
|
|||
yield ['tools'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getPermissionNames
|
||||
*/
|
||||
#[DataProvider('getPermissionNames')]
|
||||
public function testListOperationsForPermission($perm_name): void
|
||||
{
|
||||
$arr = $this->service->listOperationsForPermission($perm_name);
|
||||
|
|
|
|||
|
|
@ -90,9 +90,9 @@ class PermissionSchemaUpdaterTest extends WebTestCase
|
|||
|
||||
//Do an upgrade and afterward the move, add, and withdraw permissions should be set to ALLOW
|
||||
self::assertTrue($this->service->upgradeSchema($user, 1));
|
||||
self::assertEquals(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('parts_stock', 'move'));
|
||||
self::assertEquals(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('parts_stock', 'add'));
|
||||
self::assertEquals(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('parts_stock', 'withdraw'));
|
||||
self::assertSame(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('parts_stock', 'move'));
|
||||
self::assertSame(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('parts_stock', 'add'));
|
||||
self::assertSame(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('parts_stock', 'withdraw'));
|
||||
}
|
||||
|
||||
public function testUpgradeSchemaToVersion2(): void
|
||||
|
|
@ -106,9 +106,9 @@ class PermissionSchemaUpdaterTest extends WebTestCase
|
|||
|
||||
//After the upgrade all operations should be available under the name "projects" with the same values
|
||||
self::assertTrue($this->service->upgradeSchema($user, 2));
|
||||
self::assertEquals(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('projects', 'read'));
|
||||
self::assertEquals(PermissionData::INHERIT, $user->getPermissions()->getPermissionValue('projects', 'edit'));
|
||||
self::assertEquals(PermissionData::DISALLOW, $user->getPermissions()->getPermissionValue('projects', 'delete'));
|
||||
self::assertSame(PermissionData::ALLOW, $user->getPermissions()->getPermissionValue('projects', 'read'));
|
||||
self::assertSame(PermissionData::INHERIT, $user->getPermissions()->getPermissionValue('projects', 'edit'));
|
||||
self::assertSame(PermissionData::DISALLOW, $user->getPermissions()->getPermissionValue('projects', 'delete'));
|
||||
}
|
||||
|
||||
public function testUpgradeSchemaToVersion3(): void
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Tests\Services\UserSystem\TFA;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Services\UserSystem\TFA\BackupCodeGenerator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RuntimeException;
|
||||
|
|
@ -46,7 +47,7 @@ class BackupCodeGeneratorTest extends TestCase
|
|||
new BackupCodeGenerator(4, 10);
|
||||
}
|
||||
|
||||
public function codeLengthDataProvider(): \Iterator
|
||||
public static function codeLengthDataProvider(): \Iterator
|
||||
{
|
||||
yield [6];
|
||||
yield [8];
|
||||
|
|
@ -54,25 +55,21 @@ class BackupCodeGeneratorTest extends TestCase
|
|||
yield [16];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider codeLengthDataProvider
|
||||
*/
|
||||
#[DataProvider('codeLengthDataProvider')]
|
||||
public function testGenerateSingleCode(int $code_length): void
|
||||
{
|
||||
$generator = new BackupCodeGenerator($code_length, 10);
|
||||
$this->assertMatchesRegularExpression("/^([a-f0-9]){{$code_length}}\$/", $generator->generateSingleCode());
|
||||
}
|
||||
|
||||
public function codeCountDataProvider(): \Iterator
|
||||
public static function codeCountDataProvider(): \Iterator
|
||||
{
|
||||
yield [2];
|
||||
yield [8];
|
||||
yield [10];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider codeCountDataProvider
|
||||
*/
|
||||
#[DataProvider('codeCountDataProvider')]
|
||||
public function testGenerateCodeSet(int $code_count): void
|
||||
{
|
||||
$generator = new BackupCodeGenerator(8, $code_count);
|
||||
|
|
|
|||
59
tests/SettingsTestHelper.php
Normal file
59
tests/SettingsTestHelper.php
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/*
|
||||
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||
*
|
||||
* Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests;
|
||||
|
||||
use Jbtronics\SettingsBundle\Settings\Settings;
|
||||
use Jbtronics\SettingsBundle\Settings\ResettableSettingsInterface;
|
||||
use InvalidArgumentException;
|
||||
use ReflectionClass;
|
||||
|
||||
class SettingsTestHelper
|
||||
{
|
||||
/**
|
||||
* Creates a new dummy settings object for testing purposes.
|
||||
* It does not contain any embedded objects!
|
||||
* @template T of object
|
||||
* @param string $class
|
||||
* @phpstan-param class-string<T> $class
|
||||
* @return object
|
||||
* @phpstan-return T
|
||||
*/
|
||||
public static function createSettingsDummy(string $class): object
|
||||
{
|
||||
$reflection = new ReflectionClass($class);
|
||||
|
||||
//Check if it is a settings class (has a Settings attribute)
|
||||
if ($reflection->getAttributes(Settings::class) === []) {
|
||||
throw new InvalidArgumentException("The class $class is not a settings class!");
|
||||
}
|
||||
|
||||
$object = $reflection->newInstanceWithoutConstructor();
|
||||
|
||||
//If the object has some initialization logic, then call it
|
||||
if ($object instanceof ResettableSettingsInterface) {
|
||||
$object->resetToDefaultValues();
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace App\Tests\Twig;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use App\Twig\UserExtension;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
|
@ -36,7 +37,7 @@ class UserExtensionTest extends WebTestCase
|
|||
$this->service = self::getContainer()->get(UserExtension::class);
|
||||
}
|
||||
|
||||
public function removeLocaleFromPathDataSet(): ?\Generator
|
||||
public static function removeLocaleFromPathDataSet(): ?\Generator
|
||||
{
|
||||
yield ['/', '/de/'];
|
||||
yield ['/test', '/de/test'];
|
||||
|
|
@ -46,9 +47,7 @@ class UserExtensionTest extends WebTestCase
|
|||
yield ['/test/foo/bar?param1=val1¶m2=val2', '/de_DE/test/foo/bar?param1=val1¶m2=val2'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider removeLocaleFromPathDataSet
|
||||
*/
|
||||
#[DataProvider('removeLocaleFromPathDataSet')]
|
||||
public function testRemoveLocaleFromPath(string $expected, string $input): void
|
||||
{
|
||||
$this->assertSame($expected, $this->service->removeLocaleFromPath($input));
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ class ValidGoogleAuthCodeValidatorTest extends ConstraintValidatorTestCase
|
|||
return [];
|
||||
}
|
||||
|
||||
public function eraseCredentials()
|
||||
public function eraseCredentials(): void
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ declare(strict_types=1);
|
|||
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
require dirname(__DIR__).'/vendor/autoload.php';
|
||||
if (file_exists(dirname(__DIR__).'/config/bootstrap.php')) {
|
||||
require dirname(__DIR__).'/config/bootstrap.php';
|
||||
} elseif (method_exists(Dotenv::class, 'bootEnv')) {
|
||||
|
||||
if (method_exists(Dotenv::class, 'bootEnv')) {
|
||||
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
|
||||
}
|
||||
if ($_SERVER['APP_DEBUG']) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue