mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-03-01 12:59:36 +00:00
Add partdb:kicad:populate command for bulk KiCad path assignment
Console command that populates KiCad footprint/symbol paths on Footprint and Category entities based on name-to-library mappings. Supports dry-run, force overwrite, and list modes. Includes 130+ footprint mappings and 30+ category symbol mappings for KiCad 9.x standard libraries.
This commit is contained in:
parent
9178154986
commit
43fe3da19f
2 changed files with 771 additions and 0 deletions
276
tests/Command/PopulateKicadCommandTest.php
Normal file
276
tests/Command/PopulateKicadCommandTest.php
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Command;
|
||||
|
||||
use App\Command\PopulateKicadCommand;
|
||||
use App\Entity\Parts\Category;
|
||||
use App\Entity\Parts\Footprint;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class PopulateKicadCommandTest extends KernelTestCase
|
||||
{
|
||||
private CommandTester $commandTester;
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
self::bootKernel();
|
||||
$application = new Application(self::$kernel);
|
||||
|
||||
$command = $application->find('partdb:kicad:populate');
|
||||
$this->commandTester = new CommandTester($command);
|
||||
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
|
||||
}
|
||||
|
||||
public function testListOption(): void
|
||||
{
|
||||
$this->commandTester->execute(['--list' => true]);
|
||||
|
||||
$output = $this->commandTester->getDisplay();
|
||||
|
||||
// Should show footprints and categories tables
|
||||
$this->assertStringContainsString('Current Footprint KiCad Values', $output);
|
||||
$this->assertStringContainsString('Current Category KiCad Values', $output);
|
||||
$this->assertStringContainsString('ID', $output);
|
||||
$this->assertStringContainsString('Name', $output);
|
||||
|
||||
$this->assertEquals(0, $this->commandTester->getStatusCode());
|
||||
}
|
||||
|
||||
public function testDryRunDoesNotModifyDatabase(): void
|
||||
{
|
||||
// Create a test footprint without KiCad value
|
||||
$footprint = new Footprint();
|
||||
$footprint->setName('SOT-23');
|
||||
$this->entityManager->persist($footprint);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$footprintId = $footprint->getId();
|
||||
|
||||
// Run in dry-run mode
|
||||
$this->commandTester->execute(['--dry-run' => true, '--footprints' => true]);
|
||||
|
||||
$output = $this->commandTester->getDisplay();
|
||||
$this->assertStringContainsString('DRY RUN MODE', $output);
|
||||
$this->assertStringContainsString('SOT-23', $output);
|
||||
|
||||
// Clear entity manager to force reload from DB
|
||||
$this->entityManager->clear();
|
||||
|
||||
// Verify footprint was NOT updated in the database
|
||||
$reloadedFootprint = $this->entityManager->find(Footprint::class, $footprintId);
|
||||
$this->assertNull($reloadedFootprint->getEdaInfo()->getKicadFootprint());
|
||||
|
||||
// Cleanup
|
||||
$this->entityManager->remove($reloadedFootprint);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function testFootprintMappingUpdatesCorrectly(): void
|
||||
{
|
||||
// Create test footprints
|
||||
$footprint1 = new Footprint();
|
||||
$footprint1->setName('SOT-23');
|
||||
|
||||
$footprint2 = new Footprint();
|
||||
$footprint2->setName('0805');
|
||||
|
||||
$footprint3 = new Footprint();
|
||||
$footprint3->setName('DIP-8');
|
||||
|
||||
$this->entityManager->persist($footprint1);
|
||||
$this->entityManager->persist($footprint2);
|
||||
$this->entityManager->persist($footprint3);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$ids = [$footprint1->getId(), $footprint2->getId(), $footprint3->getId()];
|
||||
|
||||
// Run the command
|
||||
$this->commandTester->execute(['--footprints' => true]);
|
||||
|
||||
$output = $this->commandTester->getDisplay();
|
||||
$this->assertEquals(0, $this->commandTester->getStatusCode());
|
||||
|
||||
// Clear and reload
|
||||
$this->entityManager->clear();
|
||||
|
||||
// Verify mappings were applied
|
||||
$reloaded1 = $this->entityManager->find(Footprint::class, $ids[0]);
|
||||
$this->assertEquals('Package_TO_SOT_SMD:SOT-23', $reloaded1->getEdaInfo()->getKicadFootprint());
|
||||
|
||||
$reloaded2 = $this->entityManager->find(Footprint::class, $ids[1]);
|
||||
$this->assertEquals('Resistor_SMD:R_0805_2012Metric', $reloaded2->getEdaInfo()->getKicadFootprint());
|
||||
|
||||
$reloaded3 = $this->entityManager->find(Footprint::class, $ids[2]);
|
||||
$this->assertEquals('Package_DIP:DIP-8_W7.62mm', $reloaded3->getEdaInfo()->getKicadFootprint());
|
||||
|
||||
// Cleanup
|
||||
$this->entityManager->remove($reloaded1);
|
||||
$this->entityManager->remove($reloaded2);
|
||||
$this->entityManager->remove($reloaded3);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function testSkipsExistingValuesWithoutForce(): void
|
||||
{
|
||||
// Create footprint with existing value
|
||||
$footprint = new Footprint();
|
||||
$footprint->setName('SOT-23');
|
||||
$footprint->getEdaInfo()->setKicadFootprint('Custom:MyFootprint');
|
||||
$this->entityManager->persist($footprint);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$footprintId = $footprint->getId();
|
||||
|
||||
// Run without --force
|
||||
$this->commandTester->execute(['--footprints' => true]);
|
||||
|
||||
$this->entityManager->clear();
|
||||
|
||||
// Should keep original value
|
||||
$reloaded = $this->entityManager->find(Footprint::class, $footprintId);
|
||||
$this->assertEquals('Custom:MyFootprint', $reloaded->getEdaInfo()->getKicadFootprint());
|
||||
|
||||
// Cleanup
|
||||
$this->entityManager->remove($reloaded);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function testForceOptionOverwritesExistingValues(): void
|
||||
{
|
||||
// Create footprint with existing value
|
||||
$footprint = new Footprint();
|
||||
$footprint->setName('SOT-23');
|
||||
$footprint->getEdaInfo()->setKicadFootprint('Custom:MyFootprint');
|
||||
$this->entityManager->persist($footprint);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$footprintId = $footprint->getId();
|
||||
|
||||
// Run with --force
|
||||
$this->commandTester->execute(['--footprints' => true, '--force' => true]);
|
||||
|
||||
$this->entityManager->clear();
|
||||
|
||||
// Should overwrite with mapped value
|
||||
$reloaded = $this->entityManager->find(Footprint::class, $footprintId);
|
||||
$this->assertEquals('Package_TO_SOT_SMD:SOT-23', $reloaded->getEdaInfo()->getKicadFootprint());
|
||||
|
||||
// Cleanup
|
||||
$this->entityManager->remove($reloaded);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function testCategoryMappingUpdatesCorrectly(): void
|
||||
{
|
||||
// Create test categories
|
||||
$category1 = new Category();
|
||||
$category1->setName('Resistors');
|
||||
|
||||
$category2 = new Category();
|
||||
$category2->setName('LED Indicators');
|
||||
|
||||
$category3 = new Category();
|
||||
$category3->setName('Zener Diodes');
|
||||
|
||||
$this->entityManager->persist($category1);
|
||||
$this->entityManager->persist($category2);
|
||||
$this->entityManager->persist($category3);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$ids = [$category1->getId(), $category2->getId(), $category3->getId()];
|
||||
|
||||
// Run the command
|
||||
$this->commandTester->execute(['--categories' => true]);
|
||||
|
||||
$this->assertEquals(0, $this->commandTester->getStatusCode());
|
||||
|
||||
// Clear and reload
|
||||
$this->entityManager->clear();
|
||||
|
||||
// Verify mappings were applied (using pattern matching)
|
||||
$reloaded1 = $this->entityManager->find(Category::class, $ids[0]);
|
||||
$this->assertEquals('Device:R', $reloaded1->getEdaInfo()->getKicadSymbol());
|
||||
|
||||
$reloaded2 = $this->entityManager->find(Category::class, $ids[1]);
|
||||
$this->assertEquals('Device:LED', $reloaded2->getEdaInfo()->getKicadSymbol());
|
||||
|
||||
$reloaded3 = $this->entityManager->find(Category::class, $ids[2]);
|
||||
$this->assertEquals('Device:D_Zener', $reloaded3->getEdaInfo()->getKicadSymbol());
|
||||
|
||||
// Cleanup
|
||||
$this->entityManager->remove($reloaded1);
|
||||
$this->entityManager->remove($reloaded2);
|
||||
$this->entityManager->remove($reloaded3);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function testUnmappedFootprintsAreListed(): void
|
||||
{
|
||||
// Create footprint with no mapping
|
||||
$footprint = new Footprint();
|
||||
$footprint->setName('CustomPackage-XYZ');
|
||||
$this->entityManager->persist($footprint);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$footprintId = $footprint->getId();
|
||||
|
||||
// Run the command
|
||||
$this->commandTester->execute(['--footprints' => true]);
|
||||
|
||||
$output = $this->commandTester->getDisplay();
|
||||
|
||||
// Should list the unmapped footprint
|
||||
$this->assertStringContainsString('No mapping found', $output);
|
||||
$this->assertStringContainsString('CustomPackage-XYZ', $output);
|
||||
|
||||
// Cleanup
|
||||
$this->entityManager->clear();
|
||||
$reloaded = $this->entityManager->find(Footprint::class, $footprintId);
|
||||
$this->entityManager->remove($reloaded);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function testBothFootprintsAndCategoriesUpdatedByDefault(): void
|
||||
{
|
||||
// Create one of each
|
||||
$footprint = new Footprint();
|
||||
$footprint->setName('TO-220');
|
||||
$this->entityManager->persist($footprint);
|
||||
|
||||
$category = new Category();
|
||||
$category->setName('Capacitors');
|
||||
$this->entityManager->persist($category);
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
$footprintId = $footprint->getId();
|
||||
$categoryId = $category->getId();
|
||||
|
||||
// Run without specific options (should do both)
|
||||
$this->commandTester->execute([]);
|
||||
|
||||
$output = $this->commandTester->getDisplay();
|
||||
$this->assertStringContainsString('Updating Footprint Entities', $output);
|
||||
$this->assertStringContainsString('Updating Category Entities', $output);
|
||||
|
||||
$this->entityManager->clear();
|
||||
|
||||
// Both should be updated
|
||||
$reloadedFootprint = $this->entityManager->find(Footprint::class, $footprintId);
|
||||
$this->assertEquals('Package_TO_SOT_THT:TO-220-3_Vertical', $reloadedFootprint->getEdaInfo()->getKicadFootprint());
|
||||
|
||||
$reloadedCategory = $this->entityManager->find(Category::class, $categoryId);
|
||||
$this->assertEquals('Device:C', $reloadedCategory->getEdaInfo()->getKicadSymbol());
|
||||
|
||||
// Cleanup
|
||||
$this->entityManager->remove($reloadedFootprint);
|
||||
$this->entityManager->remove($reloadedCategory);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue