61 void SeedLoadError(
const wxString& aNickname )
71 void SeedLoadedLibrary(
const wxString& aNickname,
const wxString& aUri )
73 LIBRARY_TABLE_ROW* row = m_rows.emplace_back( std::make_unique<LIBRARY_TABLE_ROW>() ).get();
78 LIB_DATA& data = m_libraries[aNickname];
80 data.
plugin = std::make_unique<PCB_IO_KICAD_SEXPR>();
85 std::vector<std::unique_ptr<LIBRARY_TABLE_ROW>> m_rows;
90wxString getResistorLibPath()
95 fn.AppendDir( wxS(
"libraries" ) );
96 fn.AppendDir( wxS(
"Resistor_SMD.pretty" ) );
117 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
119 adapter.SeedLoadError( wxS(
"BadLib" ) );
124 BOOST_CHECK_EQUAL( adapter.IsFootprintLibWritable( wxS(
"NeverSeen" ) ),
false );
140 if( ::geteuid() == 0 )
150 const std::filesystem::path libPath = tmpLib.
CreateChildDir(
"kicad_qa_adapter_save_readonly.pretty" );
153 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
155 const wxString nickname = wxS(
"scratch" );
156 adapter.SeedLoadedLibrary( nickname, libPath.string() );
158 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
166 std::filesystem::path savedFile = libPath /
"readonly_fp.kicad_mod";
171 std::filesystem::permissions( savedFile,
172 std::filesystem::perms::owner_write | std::filesystem::perms::group_write
173 | std::filesystem::perms::others_write,
174 std::filesystem::perm_options::remove );
176 BOOST_CHECK_THROW( adapter.SaveFootprint( nickname, fp ),
IO_ERROR );
188 const std::filesystem::path libPath = tmpLib.
CreateChildDir(
"kicad_qa_adapter_cached_nets.pretty" );
191 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
193 const wxString nickname = wxS(
"CachedNets" );
194 adapter.SeedLoadedLibrary( nickname, libPath.string() );
195 adapter.RefreshLibraryIfChanged( nickname );
197 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
202 board->Add( footprint );
203 footprint->
SetFPID(
LIB_ID( nickname, wxS(
"cached_nets" ) ) );
218 std::unique_ptr<FOOTPRINT> loaded( adapter.LoadFootprint( nickname, wxS(
"cached_nets" ),
false ) );
220 BOOST_REQUIRE_EQUAL( loaded->Pads().size(), 1u );
232 const std::filesystem::path libPath = tmpLib.
CreateChildDir(
"kicad_qa_adapter_concurrent.pretty" );
234 for(
const auto& entry : std::filesystem::directory_iterator(
235 std::filesystem::path( getResistorLibPath().
ToStdString() ) ) )
237 if( entry.is_regular_file() )
238 std::filesystem::copy_file( entry.path(), libPath / entry.path().filename() );
242 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
244 const wxString nickname = wxS(
"Resistor_SMD" );
245 adapter.SeedLoadedLibrary( nickname, libPath.string() );
248 const wxString stableFp = wxS(
"R_0603_1608Metric" );
250 BOOST_REQUIRE( adapter.FootprintExists( nickname, stableFp ) );
252 constexpr int readerCount = 6;
253 constexpr int iterations = 40;
255 std::atomic<bool> sawMissing{
false };
256 std::atomic<bool> sawNullLoad{
false };
257 std::atomic<int> savedCount{ 0 };
260 std::atomic<int> ready{ 0 };
261 std::atomic<bool> go{
false };
263 auto waitForStart = [&]()
265 ready.fetch_add( 1 );
268 std::this_thread::yield();
271 std::vector<std::thread> workers;
272 workers.reserve( readerCount + 1 );
274 for(
int t = 0; t < readerCount; ++t )
276 workers.emplace_back(
281 for(
int i = 0; i < iterations; ++i )
284 adapter.IsWritable( nickname );
286 if( !adapter.FootprintExists( nickname, stableFp ) )
289 std::unique_ptr<FOOTPRINT> fp{ adapter.LoadFootprint( nickname, stableFp,
false ) };
297 workers.emplace_back(
300 std::unique_ptr<FOOTPRINT> seed{ adapter.LoadFootprint( nickname, stableFp,
false ) };
310 for(
int i = 0; i < iterations; ++i )
313 seed->SetFPID(
LIB_ID( nickname, wxString::Format( wxS(
"scratch_%d" ), i % 4 ) ) );
318 savedCount.fetch_add( 1 );
327 while( ready.load() < readerCount + 1 )
328 std::this_thread::yield();
332 for( std::thread& worker : workers )
335 BOOST_CHECK( !sawMissing.load() );
336 BOOST_CHECK( !sawNullLoad.load() );
339 BOOST_CHECK( savedCount.load() > 0 );
348 const std::filesystem::path libPath = tmpLib.
CreateChildDir(
"kicad_qa_adapter_stale.pretty" );
350 const std::filesystem::path
source =
351 std::filesystem::path( getResistorLibPath().
ToStdString() ) /
"R_0402_1005Metric.kicad_mod";
353 std::filesystem::copy_file(
source, libPath /
"R_0402_1005Metric.kicad_mod" );
355 const wxString nickname = wxS(
"StaleCheck" );
358 std::ofstream
table( tmpTable.
Path() /
"fp-lib-table" );
359 table <<
"(fp_lib_table\n (version 7)\n";
360 table <<
" (lib (name \"" << nickname.ToStdString() <<
"\")(type \"KiCad\")(uri \""
361 << libPath.string() <<
"\")(options \"\")(descr \"\"))\n)\n";
367 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
368 adapter.SeedLoadedLibrary( nickname, libPath.string() );
370 adapter.RefreshLibraryIfChanged( nickname );
371 BOOST_REQUIRE_EQUAL( adapter.GetFootprints( nickname,
true ).size(), 1u );
373 std::filesystem::copy_file(
source, libPath /
"ZZ_PulledFootprint.kicad_mod" );
375 adapter.RefreshChangedLibraries();
379 for(
FOOTPRINT* fp : adapter.GetFootprints( nickname,
true ) )
381 if( fp && fp->GetFPID().GetLibItemName().wx_str() == wxS(
"ZZ_PulledFootprint" ) )
385 BOOST_CHECK_MESSAGE( found,
"a footprint added to the library on disk is missing from the listing" );
395 const std::filesystem::path libPathA = tmpA.
CreateChildDir(
"kicad_qa_adapter_skip_a.pretty" );
396 const std::filesystem::path libPathB = tmpB.
CreateChildDir(
"kicad_qa_adapter_skip_b.pretty" );
398 const std::filesystem::path
source =
399 std::filesystem::path( getResistorLibPath().
ToStdString() ) /
"R_0402_1005Metric.kicad_mod";
401 std::filesystem::copy_file(
source, libPathA /
"R_0402_1005Metric.kicad_mod" );
403 for(
int i = 0; i < 8; ++i )
405 std::filesystem::copy_file(
source, libPathB / (
"R_" + std::to_string( i ) +
".kicad_mod" ) );
408 const wxString nickA = wxS(
"SkipCheckA" );
409 const wxString nickB = wxS(
"SkipCheckB" );
411 const std::filesystem::path tablePath = tmpTable.
Path() /
"fp-lib-table";
414 std::ofstream
table( tablePath );
415 table <<
"(fp_lib_table\n (version 7)\n";
416 table <<
" (lib (name \"" << nickA.ToStdString() <<
"\")(type \"KiCad\")(uri \"" << libPathA.string()
417 <<
"\")(options \"\")(descr \"\"))\n";
418 table <<
" (lib (name \"" << nickB.ToStdString() <<
"\")(type \"KiCad\")(uri \"" << libPathB.string()
419 <<
"\")(options \"\")(descr \"\"))\n)\n";
425 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
426 adapter.SeedLoadedLibrary( nickA, libPathA.string() );
427 adapter.SeedLoadedLibrary( nickB, libPathB.string() );
429 adapter.RefreshLibraryIfChanged( nickA );
430 adapter.RefreshLibraryIfChanged( nickB );
432 BOOST_REQUIRE_EQUAL( adapter.GetFootprints( nickA,
true ).size(), 1u );
433 BOOST_REQUIRE_EQUAL( adapter.GetFootprints( nickB,
true ).size(), 8u );
437 std::vector<FOOTPRINT*> untouched = adapter.GetFootprints( nickB,
true );
439 std::filesystem::copy_file(
source, libPathA /
"ZZ_Added.kicad_mod" );
441 adapter.RefreshChangedLibraries();
444 BOOST_CHECK_MESSAGE( adapter.GetFootprints( nickB,
true ) == untouched,
"an unchanged library was re-enumerated" );
458 const std::filesystem::path libPath = tmpLib.
CreateChildDir(
"kicad_qa_adapter_rt.pretty" );
460 const std::filesystem::path
source =
461 std::filesystem::path( getResistorLibPath().
ToStdString() ) /
"R_0402_1005Metric.kicad_mod";
462 const std::filesystem::path target = libPath /
"R_0402_1005Metric.kicad_mod";
464 std::filesystem::copy_file(
source, target );
466 const wxString nickname = wxS(
"RoundTrip" );
467 const wxString fpName = wxS(
"R_0402_1005Metric" );
470 std::ofstream
table( tmpTable.
Path() /
"fp-lib-table" );
471 table <<
"(fp_lib_table\n (version 7)\n";
472 table <<
" (lib (name \"" << nickname.ToStdString() <<
"\")(type \"KiCad\")(uri \""
473 << libPath.string() <<
"\")(options \"\")(descr \"\"))\n)\n";
477 [](
const std::filesystem::path& aPath )
479 std::set<std::string> ids;
480 std::ifstream in( aPath );
483 while( std::getline( in, line ) )
485 size_t pos = line.find(
"(uuid \"" );
487 if( pos != std::string::npos )
488 ids.insert( line.substr( pos + 7, 36 ) );
494 const std::set<std::string> before = fileUuids( target );
499 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
500 adapter.SeedLoadedLibrary( nickname, libPath.string() );
503 adapter.RefreshLibraryIfChanged( nickname );
505 std::unique_ptr<FOOTPRINT> edited( adapter.LoadFootprint( nickname, fpName,
true ) );
510 const std::set<std::string> after = fileUuids( target );
512 std::vector<std::string> common;
513 std::set_intersection( before.begin(), before.end(), after.begin(), after.end(),
514 std::back_inserter( common ) );
519 BOOST_CHECK_MESSAGE( common.size() == after.size(),
520 "a load/save round trip through the editor path rewrote UUIDs in the .kicad_mod" );
532 const std::filesystem::path libPath = tmpLib.
CreateChildDir(
"kicad_qa_adapter_removed_lib.pretty" );
534 const std::filesystem::path
source =
535 std::filesystem::path( getResistorLibPath().
ToStdString() ) /
"R_0402_1005Metric.kicad_mod";
537 std::filesystem::copy_file(
source, libPath /
"R_0402_1005Metric.kicad_mod" );
539 const wxString nickname = wxS(
"RemovedCheck" );
542 std::ofstream
table( tmpTable.
Path() /
"fp-lib-table" );
543 table <<
"(fp_lib_table\n (version 7)\n";
544 table <<
" (lib (name \"" << nickname.ToStdString() <<
"\")(type \"KiCad\")(uri \"" << libPath.string()
545 <<
"\")(options \"\")(descr \"\"))\n)\n";
552 std::make_unique<TEST_FOOTPRINT_LIBRARY_ADAPTER>( manager ) );
556 TEST_FOOTPRINT_LIBRARY_ADAPTER& adapter = *
static_cast<TEST_FOOTPRINT_LIBRARY_ADAPTER*
>( *adapterOpt );
558 adapter.SeedLoadedLibrary( nickname, libPath.string() );
559 adapter.RefreshLibraryIfChanged( nickname );
560 BOOST_REQUIRE_EQUAL( adapter.GetFootprints( nickname,
true ).size(), 1u );
564 std::ofstream
table( tmpTable.
Path() /
"fp-lib-table" );
565 table <<
"(fp_lib_table\n (version 7)\n)\n";
570 FOOTPRINT* fp = adapter.LoadFootprint( nickname, wxS(
"R_0402_1005Metric" ),
false );
571 BOOST_CHECK_MESSAGE( !fp,
"a library removed from the table must not keep serving preloaded "
constexpr EDA_IU_SCALE pcbIUScale
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
wxString PathStr() const
Get the path to the temporary directory as a wxString.
const std::filesystem::path & Path() const
Get the path to the temporary directory as a std::filesystem::path.
std::filesystem::path CreateChildDir(const wxString &aName) const
Create and return the path to a direct child directory.
std::optional< LIBRARY_MANAGER_ADAPTER * > Adapter(LIBRARY_TABLE_TYPE aType) const
void RegisterAdapter(LIBRARY_TABLE_TYPE aType, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > &&aAdapter)
void LoadProjectTables(std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
(Re)loads the project library tables in the given list, or all tables if no list is given
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetURI(const wxString &aUri)
A logical library item identifier and consists of various portions much like a URI.
LSET is a set of PCB_LAYER_IDs.
Handle the data for a net.
static NETINFO_ITEM * OrphanedItem()
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
static std::string ToStdString(const wxString &aStr)
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
std::unique_ptr< IO_BASE > plugin
Never destroyed while holding the map's mutex; a plugin's worker thread may be blocked on it.
const LIBRARY_TABLE_ROW * row
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST_MESSAGE("Polyline has "<< chain.PointCount()<< " points")
BOOST_CHECK_EQUAL(result, "25.4")
VECTOR2< int32_t > VECTOR2I