KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_footprint_library_adapter.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <atomic>
21#include <filesystem>
22#include <fstream>
23#include <algorithm>
24#include <iterator>
25#include <memory>
26#include <set>
27#include <thread>
28#include <vector>
29
30#ifdef __unix__
31#include <unistd.h>
32#endif
33
34#include <qa_utils/file_utils.h>
37
38#include <board.h>
39#include <footprint.h>
43#include <netinfo.h>
44#include <pad.h>
46
47
48namespace
49{
50
56class TEST_FOOTPRINT_LIBRARY_ADAPTER : public FOOTPRINT_LIBRARY_ADAPTER
57{
58public:
60
61 void SeedLoadError( const wxString& aNickname )
62 {
63 m_libraries[aNickname].status.load_status = LOAD_STATUS::LOAD_ERROR;
64 }
65
71 void SeedLoadedLibrary( const wxString& aNickname, const wxString& aUri )
72 {
73 LIBRARY_TABLE_ROW* row = m_rows.emplace_back( std::make_unique<LIBRARY_TABLE_ROW>() ).get();
74 row->SetNickname( aNickname );
75 row->SetType( wxS( "KiCad" ) );
76 row->SetURI( aUri );
77
78 LIB_DATA& data = m_libraries[aNickname];
80 data.plugin = std::make_unique<PCB_IO_KICAD_SEXPR>();
81 data.row = row;
82 }
83
84private:
85 std::vector<std::unique_ptr<LIBRARY_TABLE_ROW>> m_rows;
86};
87
88
90wxString getResistorLibPath()
91{
92 // qa/data/pcbnew/.. -> qa/data/libraries/Resistor_SMD.pretty
93 wxFileName fn( wxString::FromUTF8( KI_TEST::GetPcbnewTestDataDir() ), wxEmptyString );
94 fn.RemoveLastDir();
95 fn.AppendDir( wxS( "libraries" ) );
96 fn.AppendDir( wxS( "Resistor_SMD.pretty" ) );
97 return fn.GetPath();
98}
99
100} // namespace
101
102
103BOOST_AUTO_TEST_SUITE( FootprintLibraryAdapter )
104
105
106
114BOOST_AUTO_TEST_CASE( IsFootprintLibWritableHandlesFailedLoad )
115{
116 LIBRARY_MANAGER manager;
117 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
118
119 adapter.SeedLoadError( wxS( "BadLib" ) );
120
121 BOOST_CHECK_EQUAL( adapter.IsFootprintLibWritable( wxS( "BadLib" ) ), false );
122
123 // A library that was never even attempted must also be safe.
124 BOOST_CHECK_EQUAL( adapter.IsFootprintLibWritable( wxS( "NeverSeen" ) ), false );
125}
126
127
135BOOST_AUTO_TEST_CASE( SaveFootprintReadOnlyFilePropagatesError )
136{
137#ifdef __unix__
138 // The superuser ignores mode bits, so a read-only file stays writable and this path
139 // cannot be exercised.
140 if( ::geteuid() == 0 )
141 {
142 BOOST_TEST_MESSAGE( "Skipping read-only footprint save test when running as root." );
143 return;
144 }
145#endif
146
147 // FootprintSave validates the whole containing directory as a library, so it needs a
148 // private directory no unrelated .kicad_mod can pollute.
149 KI_TEST::SCOPED_TEMP_DIR tmpLib( "kicad_qa_adapter_save_readonly" );
150 const std::filesystem::path libPath = tmpLib.CreateChildDir( "kicad_qa_adapter_save_readonly.pretty" );
151
152 LIBRARY_MANAGER manager;
153 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
154
155 const wxString nickname = wxS( "scratch" );
156 adapter.SeedLoadedLibrary( nickname, libPath.string() );
157
158 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
159
160 FOOTPRINT* fp = new FOOTPRINT( board.get() );
161 board->Add( fp );
162 fp->SetFPID( LIB_ID( nickname, wxS( "readonly_fp" ) ) );
163
164 BOOST_REQUIRE( adapter.SaveFootprint( nickname, fp ) == FOOTPRINT_LIBRARY_ADAPTER::SAVE_OK );
165
166 std::filesystem::path savedFile = libPath / "readonly_fp.kicad_mod";
167 BOOST_REQUIRE( std::filesystem::exists( savedFile ) );
168
169 // Mark only the file read-only, mirroring the issue; the directory stays writable so the
170 // writability gate still passes and the temporary directory can unlink it.
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 );
175
176 BOOST_CHECK_THROW( adapter.SaveFootprint( nickname, fp ), IO_ERROR );
177}
178
179
185BOOST_AUTO_TEST_CASE( SavedFootprintCacheDoesNotRetainBoardNets )
186{
187 KI_TEST::SCOPED_TEMP_DIR tmpLib( "kicad_qa_adapter_cached_nets" );
188 const std::filesystem::path libPath = tmpLib.CreateChildDir( "kicad_qa_adapter_cached_nets.pretty" );
189
190 LIBRARY_MANAGER manager;
191 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
192
193 const wxString nickname = wxS( "CachedNets" );
194 adapter.SeedLoadedLibrary( nickname, libPath.string() );
195 adapter.RefreshLibraryIfChanged( nickname );
196
197 std::unique_ptr<BOARD> board = std::make_unique<BOARD>();
198 NETINFO_ITEM* net = new NETINFO_ITEM( board.get(), wxS( "SourceBoardNet" ), 1 );
199 board->Add( net );
200
201 FOOTPRINT* footprint = new FOOTPRINT( board.get() );
202 board->Add( footprint );
203 footprint->SetFPID( LIB_ID( nickname, wxS( "cached_nets" ) ) );
204
205 PAD* pad = new PAD( footprint );
207 pad->SetSize( PADSTACK::ALL_LAYERS, VECTOR2I( pcbIUScale.mmToIU( 1 ), pcbIUScale.mmToIU( 1 ) ) );
208 pad->SetLayerSet( LSET( { F_Cu } ) );
209 pad->SetNet( net );
210 footprint->Add( pad );
211
212 BOOST_REQUIRE( adapter.SaveFootprint( nickname, footprint ) == FOOTPRINT_LIBRARY_ADAPTER::SAVE_OK );
213
214 // The cache entry now outlives the board and every NETINFO_ITEM it owns, as it can when the
215 // user closes the source board before opening the footprint chooser.
216 board.reset();
217
218 std::unique_ptr<FOOTPRINT> loaded( adapter.LoadFootprint( nickname, wxS( "cached_nets" ), false ) );
219 BOOST_REQUIRE( loaded );
220 BOOST_REQUIRE_EQUAL( loaded->Pads().size(), 1u );
221 BOOST_CHECK_EQUAL( loaded->GetBoard(), nullptr );
222 BOOST_CHECK_EQUAL( loaded->Pads().front()->GetNet(), NETINFO_LIST::OrphanedItem() );
223}
224
225
226// Concurrency regression for the FP_CACHE heap corruption (Sentry 6819786130 / 6322230945 /
227// 7271165487): a writer churns the library while readers rebuild the cache, which races unserialized.
228BOOST_AUTO_TEST_CASE( ConcurrentPluginAccessIsSerialized )
229{
230 // Writable copy so the writer can churn the library and force concurrent cache rebuilds.
231 KI_TEST::SCOPED_TEMP_DIR tmpLib( "kicad_qa_adapter_concurrent" );
232 const std::filesystem::path libPath = tmpLib.CreateChildDir( "kicad_qa_adapter_concurrent.pretty" );
233
234 for( const auto& entry : std::filesystem::directory_iterator(
235 std::filesystem::path( getResistorLibPath().ToStdString() ) ) )
236 {
237 if( entry.is_regular_file() )
238 std::filesystem::copy_file( entry.path(), libPath / entry.path().filename() );
239 }
240
241 LIBRARY_MANAGER manager;
242 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
243
244 const wxString nickname = wxS( "Resistor_SMD" );
245 adapter.SeedLoadedLibrary( nickname, libPath.string() );
246
247 // Readers probe this; the writer only writes scratch names, so it always resolves.
248 const wxString stableFp = wxS( "R_0603_1608Metric" );
249
250 BOOST_REQUIRE( adapter.FootprintExists( nickname, stableFp ) );
251
252 constexpr int readerCount = 6;
253 constexpr int iterations = 40;
254
255 std::atomic<bool> sawMissing{ false };
256 std::atomic<bool> sawNullLoad{ false };
257 std::atomic<int> savedCount{ 0 };
258
259 // Release all threads together so readers and writer overlap deterministically.
260 std::atomic<int> ready{ 0 };
261 std::atomic<bool> go{ false };
262
263 auto waitForStart = [&]()
264 {
265 ready.fetch_add( 1 );
266
267 while( !go.load() )
268 std::this_thread::yield();
269 };
270
271 std::vector<std::thread> workers;
272 workers.reserve( readerCount + 1 );
273
274 for( int t = 0; t < readerCount; ++t )
275 {
276 workers.emplace_back(
277 [&]()
278 {
279 waitForStart();
280
281 for( int i = 0; i < iterations; ++i )
282 {
283 // Base-class path whose guard this change adds.
284 adapter.IsWritable( nickname );
285
286 if( !adapter.FootprintExists( nickname, stableFp ) )
287 sawMissing = true;
288
289 std::unique_ptr<FOOTPRINT> fp{ adapter.LoadFootprint( nickname, stableFp, false ) };
290
291 if( !fp )
292 sawNullLoad = true;
293 }
294 } );
295 }
296
297 workers.emplace_back(
298 [&]()
299 {
300 std::unique_ptr<FOOTPRINT> seed{ adapter.LoadFootprint( nickname, stableFp, false ) };
301
302 if( !seed )
303 {
304 sawNullLoad = true;
305 return;
306 }
307
308 waitForStart();
309
310 for( int i = 0; i < iterations; ++i )
311 {
312 // Each save bumps the library timestamp, forcing the next validateCache() to rebuild.
313 seed->SetFPID( LIB_ID( nickname, wxString::Format( wxS( "scratch_%d" ), i % 4 ) ) );
314
315 try
316 {
317 if( adapter.SaveFootprint( nickname, seed.get(), true ) == FOOTPRINT_LIBRARY_ADAPTER::SAVE_OK )
318 savedCount.fetch_add( 1 );
319 }
320 catch( const IO_ERROR& )
321 {
322 // Transient write failures are fine; a total failure trips savedCount below.
323 }
324 }
325 } );
326
327 while( ready.load() < readerCount + 1 )
328 std::this_thread::yield();
329
330 go.store( true );
331
332 for( std::thread& worker : workers )
333 worker.join();
334
335 BOOST_CHECK( !sawMissing.load() );
336 BOOST_CHECK( !sawNullLoad.load() );
337
338 // Confirm the writer churned the cache, else the readers never raced a rebuild.
339 BOOST_CHECK( savedCount.load() > 0 );
340}
341
342
343BOOST_AUTO_TEST_CASE( RefreshChangedLibrariesPicksUpExternalAddition )
344{
345 KI_TEST::SCOPED_TEMP_DIR tmpLib( "kicad_qa_adapter_stale" );
346 KI_TEST::SCOPED_TEMP_DIR tmpTable( "kicad_qa_adapter_stale_table" );
347
348 const std::filesystem::path libPath = tmpLib.CreateChildDir( "kicad_qa_adapter_stale.pretty" );
349
350 const std::filesystem::path source =
351 std::filesystem::path( getResistorLibPath().ToStdString() ) / "R_0402_1005Metric.kicad_mod";
352
353 std::filesystem::copy_file( source, libPath / "R_0402_1005Metric.kicad_mod" );
354
355 const wxString nickname = wxS( "StaleCheck" );
356
357 {
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";
362 }
363
364 LIBRARY_MANAGER manager;
365 manager.LoadProjectTables( tmpTable.PathStr(), { LIBRARY_TABLE_TYPE::FOOTPRINT } );
366
367 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
368 adapter.SeedLoadedLibrary( nickname, libPath.string() );
369
370 adapter.RefreshLibraryIfChanged( nickname );
371 BOOST_REQUIRE_EQUAL( adapter.GetFootprints( nickname, true ).size(), 1u );
372
373 std::filesystem::copy_file( source, libPath / "ZZ_PulledFootprint.kicad_mod" );
374
375 adapter.RefreshChangedLibraries();
376
377 bool found = false;
378
379 for( FOOTPRINT* fp : adapter.GetFootprints( nickname, true ) )
380 {
381 if( fp && fp->GetFPID().GetLibItemName().wx_str() == wxS( "ZZ_PulledFootprint" ) )
382 found = true;
383 }
384
385 BOOST_CHECK_MESSAGE( found, "a footprint added to the library on disk is missing from the listing" );
386}
387
388
389BOOST_AUTO_TEST_CASE( RefreshChangedLibrariesSkipsUnchangedLibraries )
390{
391 KI_TEST::SCOPED_TEMP_DIR tmpA( "kicad_qa_adapter_skip_a" );
392 KI_TEST::SCOPED_TEMP_DIR tmpB( "kicad_qa_adapter_skip_b" );
393 KI_TEST::SCOPED_TEMP_DIR tmpTable( "kicad_qa_adapter_skip_table" );
394
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" );
397
398 const std::filesystem::path source =
399 std::filesystem::path( getResistorLibPath().ToStdString() ) / "R_0402_1005Metric.kicad_mod";
400
401 std::filesystem::copy_file( source, libPathA / "R_0402_1005Metric.kicad_mod" );
402
403 for( int i = 0; i < 8; ++i )
404 {
405 std::filesystem::copy_file( source, libPathB / ( "R_" + std::to_string( i ) + ".kicad_mod" ) );
406 }
407
408 const wxString nickA = wxS( "SkipCheckA" );
409 const wxString nickB = wxS( "SkipCheckB" );
410
411 const std::filesystem::path tablePath = tmpTable.Path() / "fp-lib-table";
412
413 {
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";
420 }
421
422 LIBRARY_MANAGER manager;
423 manager.LoadProjectTables( tmpTable.PathStr(), { LIBRARY_TABLE_TYPE::FOOTPRINT } );
424
425 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
426 adapter.SeedLoadedLibrary( nickA, libPathA.string() );
427 adapter.SeedLoadedLibrary( nickB, libPathB.string() );
428
429 adapter.RefreshLibraryIfChanged( nickA );
430 adapter.RefreshLibraryIfChanged( nickB );
431
432 BOOST_REQUIRE_EQUAL( adapter.GetFootprints( nickA, true ).size(), 1u );
433 BOOST_REQUIRE_EQUAL( adapter.GetFootprints( nickB, true ).size(), 8u );
434
435 // Re-enumeration frees every footprint in the library and allocates replacements. A single
436 // address could be reused by chance, a whole vector of them could not.
437 std::vector<FOOTPRINT*> untouched = adapter.GetFootprints( nickB, true );
438
439 std::filesystem::copy_file( source, libPathA / "ZZ_Added.kicad_mod" );
440
441 adapter.RefreshChangedLibraries();
442
443 BOOST_CHECK_EQUAL( adapter.GetFootprints( nickA, true ).size(), 2u );
444 BOOST_CHECK_MESSAGE( adapter.GetFootprints( nickB, true ) == untouched, "an unchanged library was re-enumerated" );
445}
446
447
453BOOST_AUTO_TEST_CASE( EditorRoundTripKeepsFileUuids )
454{
455 KI_TEST::SCOPED_TEMP_DIR tmpLib( "kicad_qa_adapter_rt" );
456 KI_TEST::SCOPED_TEMP_DIR tmpTable( "kicad_qa_adapter_rt_table" );
457
458 const std::filesystem::path libPath = tmpLib.CreateChildDir( "kicad_qa_adapter_rt.pretty" );
459
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";
463
464 std::filesystem::copy_file( source, target );
465
466 const wxString nickname = wxS( "RoundTrip" );
467 const wxString fpName = wxS( "R_0402_1005Metric" );
468
469 {
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";
474 }
475
476 auto fileUuids =
477 []( const std::filesystem::path& aPath )
478 {
479 std::set<std::string> ids;
480 std::ifstream in( aPath );
481 std::string line;
482
483 while( std::getline( in, line ) )
484 {
485 size_t pos = line.find( "(uuid \"" );
486
487 if( pos != std::string::npos )
488 ids.insert( line.substr( pos + 7, 36 ) );
489 }
490
491 return ids;
492 };
493
494 const std::set<std::string> before = fileUuids( target );
495
496 LIBRARY_MANAGER manager;
497 manager.LoadProjectTables( tmpTable.PathStr(), { LIBRARY_TABLE_TYPE::FOOTPRINT } );
498
499 TEST_FOOTPRINT_LIBRARY_ADAPTER adapter( manager );
500 adapter.SeedLoadedLibrary( nickname, libPath.string() );
501
502 // Populates the preloaded-footprint cache the editor then loads through
503 adapter.RefreshLibraryIfChanged( nickname );
504
505 std::unique_ptr<FOOTPRINT> edited( adapter.LoadFootprint( nickname, fpName, true ) );
506 BOOST_REQUIRE( edited );
507
508 BOOST_REQUIRE( adapter.SaveFootprint( nickname, edited.get() ) == FOOTPRINT_LIBRARY_ADAPTER::SAVE_OK );
509
510 const std::set<std::string> after = fileUuids( target );
511
512 std::vector<std::string> common;
513 std::set_intersection( before.begin(), before.end(), after.begin(), after.end(),
514 std::back_inserter( common ) );
515
516 // Only the empty "Footprint" property is dropped on write; every other id must survive
517 BOOST_REQUIRE( !before.empty() );
518 BOOST_CHECK_EQUAL( after.size() + 1, before.size() );
519 BOOST_CHECK_MESSAGE( common.size() == after.size(),
520 "a load/save round trip through the editor path rewrote UUIDs in the .kicad_mod" );
521}
522
523
527BOOST_AUTO_TEST_CASE( RemovedLibraryStopsServingPreloadedFootprints )
528{
529 KI_TEST::SCOPED_TEMP_DIR tmpLib( "kicad_qa_adapter_removed_lib" );
530 KI_TEST::SCOPED_TEMP_DIR tmpTable( "kicad_qa_adapter_removed_lib_table" );
531
532 const std::filesystem::path libPath = tmpLib.CreateChildDir( "kicad_qa_adapter_removed_lib.pretty" );
533
534 const std::filesystem::path source =
535 std::filesystem::path( getResistorLibPath().ToStdString() ) / "R_0402_1005Metric.kicad_mod";
536
537 std::filesystem::copy_file( source, libPath / "R_0402_1005Metric.kicad_mod" );
538
539 const wxString nickname = wxS( "RemovedCheck" );
540
541 {
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";
546 }
547
548 LIBRARY_MANAGER manager;
549 manager.LoadProjectTables( tmpTable.PathStr(), { LIBRARY_TABLE_TYPE::FOOTPRINT } );
550
552 std::make_unique<TEST_FOOTPRINT_LIBRARY_ADAPTER>( manager ) );
553
554 std::optional<LIBRARY_MANAGER_ADAPTER*> adapterOpt = manager.Adapter( LIBRARY_TABLE_TYPE::FOOTPRINT );
555 BOOST_REQUIRE( adapterOpt.has_value() );
556 TEST_FOOTPRINT_LIBRARY_ADAPTER& adapter = *static_cast<TEST_FOOTPRINT_LIBRARY_ADAPTER*>( *adapterOpt );
557
558 adapter.SeedLoadedLibrary( nickname, libPath.string() );
559 adapter.RefreshLibraryIfChanged( nickname );
560 BOOST_REQUIRE_EQUAL( adapter.GetFootprints( nickname, true ).size(), 1u );
561
562 // Now remove the library from the table and reload the project tables.
563 {
564 std::ofstream table( tmpTable.Path() / "fp-lib-table" );
565 table << "(fp_lib_table\n (version 7)\n)\n";
566 }
567
568 manager.LoadProjectTables( tmpTable.PathStr(), { LIBRARY_TABLE_TYPE::FOOTPRINT } );
569
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 "
572 "footprints" );
573}
574
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
An interface to the global shared library manager that is schematic-specific and linked to one projec...
FOOTPRINT_LIBRARY_ADAPTER(LIBRARY_MANAGER &aManager)
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:418
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Adds an item to the container.
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.
Definition file_utils.h:64
const std::filesystem::path & Path() const
Get the path to the temporary directory as a std::filesystem::path.
Definition file_utils.h:61
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.
Definition lib_id.h:45
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
Handle the data for a net.
Definition netinfo.h:50
static NETINFO_ITEM * OrphanedItem()
NETINFO_ITEM meaning that there was no net assigned for an item, as there was no board storing net li...
Definition netinfo.h:289
static constexpr PCB_LAYER_ID ALL_LAYERS
! The layer identifier to use for the single defintion on normal padstacks
Definition padstack.h:179
Definition pad.h:61
static std::string ToStdString(const wxString &aStr)
std::string source
@ F_Cu
Definition layer_ids.h:60
std::string GetPcbnewTestDataDir()
Utility which returns a path to the data directory where the test board files are stored.
LIB_STATUS status
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
LOAD_STATUS load_status
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(IsFootprintLibWritableHandlesFailedLoad)
Regression test for a null-plugin dereference crash.
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
Definition vector2d.h:708