KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_erc_lib_symbol_mismatch.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
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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 <boost/test/unit_test.hpp>
23#include <locale_io.h>
24#include <lib_symbol.h>
25#include <sch_screen.h>
26#include <sch_symbol.h>
27#include <reporter.h>
30#include <wx/string.h>
31#include <advanced_config.h>
32#include <erc/erc.h>
33#include <erc/erc_exclusion.h>
34#include <api/schematic/schematic_rules.pb.h>
35#include <set>
36#include <pgm_base.h>
37#include <project_sch.h>
41#include <wx/filename.h>
42#include <wx/file.h>
43#include <sch_marker.h>
44#include <sch_sheet.h>
45#include <scoped_set_reset.h>
46
54
55
56namespace
57{
58struct SCOPED_NATIVE_LIBRARY
59{
60 struct TABLE_RESTORE
61 {
62 LIBRARY_MANAGER& manager;
63 wxString directory;
64 ~TABLE_RESTORE() { manager.LoadProjectTables( directory, { LIBRARY_TABLE_TYPE::SYMBOL } ); }
65 };
66
67 static wxString PreviousDirectory( SYMBOL_LIBRARY_ADAPTER* aAdapter )
68 {
69 BOOST_REQUIRE( aAdapter );
70 const auto table = aAdapter->ProjectTable();
71 return table && *table ? wxFileName( ( *table )->Path() ).GetPath() : wxString();
72 }
73
74 explicit SCOPED_NATIVE_LIBRARY( PROJECT& aProject ) :
75 adapter( PROJECT_SCH::SymbolLibAdapter( &aProject ) ),
76 restore{ Pgm().GetLibraryManager(), PreviousDirectory( adapter ) }
77 {
78 const wxString directory = wxFileName::GetTempDir() + "/library-erc-" + KIID().AsString();
79 BOOST_REQUIRE( wxFileName::Mkdir( directory, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) );
80 wxFile tableFile( directory + "/sym-lib-table", wxFile::write );
81 BOOST_REQUIRE( tableFile.IsOpened() );
82 BOOST_REQUIRE( tableFile.Write( "(sym_lib_table (version 7))\n" ) );
83 tableFile.Close();
84 restore.manager.LoadProjectTables( directory, { LIBRARY_TABLE_TYPE::SYMBOL } );
85 LIBRARY_TABLE* table = adapter->ProjectTable().value_or( nullptr );
87 row = &table->InsertRow();
88 row->SetNickname( "NativeCapturedLibrary" );
89 row->SetURI( wxString( KI_TEST::GetEeschemaTestDataDir() ) + "libs/4xxx.kicad_sym" );
90 row->SetType( "KiCad" );
91 row->SetScope( LIBRARY_TABLE_SCOPE::PROJECT );
92 adapter->LoadOne( row->Nickname() );
93 BOOST_REQUIRE( adapter->IsLibraryLoaded( row->Nickname() ) );
94 external = adapter->LoadSymbol( row->Nickname(), "4001" );
95 BOOST_REQUIRE( external );
96 }
97
99 TABLE_RESTORE restore;
100 LIBRARY_TABLE_ROW* row = nullptr;
101 LIB_SYMBOL* external = nullptr;
102};
103}
104
105
106BOOST_AUTO_TEST_SUITE( ERCLibSymbolMismatch )
107
108BOOST_FIXTURE_TEST_CASE( LibraryIssuesPreserveSharedPathsAndExclusions, ERC_LIB_SYMBOL_MISMATCH_FIXTURE )
109{
110 LOCALE_IO locale;
111 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
112 SCOPED_SET_RESET restore( enabled, enabled );
113 KI_TEST::LoadSchematic( m_settingsManager, "issue23840/BusAndVectors", m_schematic );
114 std::vector<SCH_SHEET_PATH> paths;
115
116 for( const auto& path : m_schematic->Hierarchy() )
117 {
118 if( path.LastScreen()->GetFileName().EndsWith( "LEDs.kicad_sch" ) )
119 paths.push_back( path );
120 }
121
122 BOOST_REQUIRE_EQUAL( paths.size(), 2u );
123 SCH_SCREEN* screen = paths.front().LastScreen();
124 BOOST_REQUIRE( screen == paths.back().LastScreen() );
125 auto symbols = screen->Items().OfType( SCH_SYMBOL_T );
126 BOOST_REQUIRE( symbols.begin() != symbols.end() );
127 auto* symbol = static_cast<SCH_SYMBOL*>( *symbols.begin() );
128 BOOST_REQUIRE( symbol->GetLibSymbolRef() );
129 SCOPED_NATIVE_LIBRARY library( m_schematic->Project() );
130 const auto native = library.external->Flatten();
131 symbol->SetLibSymbol( new LIB_SYMBOL( *native ) );
132 symbol->GetLibSymbolRef()->SetKeyWords( "Native shared mismatch" );
133 m_schematic->ErcSettings().SetSeverity( ERCE_LIB_SYMBOL_ISSUES, RPT_SEVERITY_WARNING );
134 auto& exclusions = m_schematic->ErcSettings().m_ErcExclusions;
135 const auto markers = [&]( int aCode )
136 {
137 std::vector<SCH_MARKER*> result;
138
139 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
140 {
141 auto* marker = static_cast<SCH_MARKER*>( item );
142 const auto error = marker->GetRCItem();
143
144 if( error->GetErrorCode() == aCode && error->GetMainItemID() == symbol->m_Uuid )
145 result.push_back( marker );
146 }
147
148 return result;
149 };
150
152 {
153 symbol->SetLibId( code == ERCE_LIB_SYMBOL_ISSUES ? LIB_ID( "CapturedMissingLibrary", "NativeSymbol" )
154 : LIB_ID( library.row->Nickname(), "4001" ) );
155 m_schematic->ErcSettings().SetSeverity( code, RPT_SEVERITY_WARNING );
156 for( bool backend : { true, false } )
157 {
158 enabled = backend;
159 m_schematic->RebuildConnectivity();
160
161 for( bool historical : { false, true } )
162 {
163 exclusions.clear();
164 ERC_TESTER tester( m_schematic.get() );
165 tester.TestLibSymbolIssues();
166 BOOST_REQUIRE_EQUAL( markers( code ).size(), 2u );
167 std::set<KIID_PATH> seen;
168
169 for( SCH_MARKER* marker : markers( code ) )
170 {
171 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
172 BOOST_REQUIRE( error->IsSheetSpecific() );
173 BOOST_REQUIRE( error->MainItemHasSheetPath() );
174 const auto& markerPath = error->GetSpecificSheetPath().PathRef();
175 BOOST_CHECK( error->GetMainItemSheetPath().PathRef() == markerPath );
176 BOOST_CHECK( seen.insert( markerPath ).second );
177
178 if( markerPath == paths.front().PathRef() )
179 {
180 auto proto = ERC_EXCLUSION::FromMarker( *marker ).ToProto();
181
182 if( historical )
183 {
184 proto.mutable_marker()->clear_sheet_specific_path();
185 proto.mutable_marker()->clear_main_item_sheet_path();
186 }
187
188 auto exclusion = ERC_EXCLUSION::FromProto( proto );
189 exclusion.SetComment( "Retained library exclusion" );
190 exclusions.insert( exclusion );
191 }
192
193 screen->DeleteItem( marker );
194 }
195
196 const std::set<KIID_PATH> expectedPaths{ paths.front().PathRef(), paths.back().PathRef() };
197 BOOST_CHECK( seen == expectedPaths );
198 BOOST_REQUIRE_EQUAL( exclusions.size(), 1u );
199 tester.TestLibSymbolIssues();
200 m_schematic->ResolveERCExclusionsPostUpdate();
201 BOOST_REQUIRE_EQUAL( markers( code ).size(), 2u );
202
203 for( SCH_MARKER* marker : markers( code ) )
204 {
205 const auto error = std::static_pointer_cast<ERC_ITEM>( marker->GetRCItem() );
206 const bool expected = historical
207 || error->GetSpecificSheetPath().PathRef() == paths.front().PathRef();
208 BOOST_CHECK_EQUAL( marker->IsExcluded(), expected );
209 BOOST_CHECK_EQUAL( marker->GetComment(), expected ? wxString( "Retained library exclusion" )
210 : wxString() );
211 screen->DeleteItem( marker );
212 }
213 }
214 }
215 }
216
217}
218
219
220BOOST_FIXTURE_TEST_CASE( VariantExclusionsWithoutItemSheetPathStillApply, ERC_LIB_SYMBOL_MISMATCH_FIXTURE )
221{
222 LOCALE_IO locale;
223 auto& enabled = const_cast<ADVANCED_CFG&>( ADVANCED_CFG::GetCfg() ).m_ConnectivityEngine;
224 SCOPED_SET_RESET restore( enabled, false );
225 KI_TEST::LoadSchematic( m_settingsManager, "issue23840/BusAndVectors", m_schematic );
226 std::vector<SCH_SHEET_PATH> paths;
227
228 for( const auto& path : m_schematic->Hierarchy() )
229 {
230 if( path.LastScreen()->GetFileName().EndsWith( "LEDs.kicad_sch" ) )
231 paths.push_back( path );
232 }
233
234 BOOST_REQUIRE_EQUAL( paths.size(), 2u );
235 SCH_SCREEN* screen = paths.front().LastScreen();
236 BOOST_REQUIRE( screen == paths.back().LastScreen() );
237 auto symbols = screen->Items().OfType( SCH_SYMBOL_T );
238 BOOST_REQUIRE( symbols.begin() != symbols.end() );
239 auto* symbol = static_cast<SCH_SYMBOL*>( *symbols.begin() );
240 SCOPED_NATIVE_LIBRARY library( m_schematic->Project() );
241 const auto native = library.external->Flatten();
242 symbol->SetLibSymbol( new LIB_SYMBOL( *native ) );
243 symbol->SetLibId( LIB_ID( "Embedded", "Base" ) );
244 const LIB_ID alternate( library.row->Nickname(), "4001" );
245 const LIB_ID missing( library.row->Nickname(), "MissingVariantSymbol" );
246 const wxString variant = wxS( "Captured variant" );
247 m_schematic->AddVariant( variant );
248 symbol->SetVariantSymbolOverride( paths[0], variant, alternate );
249 symbol->SetVariantSymbolOverride( paths[1], variant, missing );
250 m_schematic->ErcSettings().SetSeverity( ERCE_VARIANT_SYMBOL_INVALID, RPT_SEVERITY_ERROR );
251 m_schematic->ErcSettings().SetSeverity( ERCE_VARIANT_SYMBOL_INCOMPATIBLE, RPT_SEVERITY_ERROR );
252 m_schematic->RebuildConnectivity();
253
254 symbol->GetLibSymbolRef()->SetUnitCount( native->GetUnitCount() + 1, false );
255
256 // Exclusions saved before variant markers carried the item's sheet path must still apply
257 ERC_TESTER tester( m_schematic.get() );
258 const int count = tester.TestVariantSymbols();
259 BOOST_REQUIRE_GT( count, 1 );
260 std::vector<SCH_MARKER*> legacy;
261
262 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
263 legacy.push_back( static_cast<SCH_MARKER*>( item ) );
264
265 for( SCH_MARKER* marker : legacy )
266 {
267 auto proto = ERC_EXCLUSION::FromMarker( *marker ).ToProto();
268 proto.mutable_marker()->clear_main_item_sheet_path();
269 m_schematic->ErcSettings().m_ErcExclusions.insert( ERC_EXCLUSION::FromProto( proto ) );
270 screen->DeleteItem( marker );
271 }
272
273 BOOST_REQUIRE_EQUAL( tester.TestVariantSymbols(), count );
274 m_schematic->ResolveERCExclusionsPostUpdate();
275 int excluded = 0;
276
277 for( SCH_ITEM* item : screen->Items().OfType( SCH_MARKER_T ) )
278 {
279 BOOST_CHECK( static_cast<SCH_MARKER*>( item )->IsExcluded() );
280 ++excluded;
281 }
282
283 BOOST_CHECK_EQUAL( excluded, count );
284}
285
286
288{
290
291 KI_TEST::LoadSchematic( m_settingsManager, wxString( "issue22371/issue22371" ), m_schematic );
292
293 std::string dataDir = KI_TEST::GetEeschemaTestDataDir();
294 wxString legacyLibPath = wxString( dataDir + "issue22371/lib.sch/74xx.lib" );
295
296 SCH_IO_KICAD_LEGACY_LIB_CACHE legacyCache( legacyLibPath );
297 legacyCache.Load();
298
299 const LIB_SYMBOL_MAP& symbols = legacyCache.GetSymbolMap();
300 auto it = symbols.find( "74LS00" );
301 BOOST_REQUIRE_MESSAGE( it != symbols.end(), "74LS00 not found in legacy library" );
302
303 std::unique_ptr<LIB_SYMBOL> flattenedLibSymbol = it->second->Flatten();
304
305 SCH_SCREENS screens( m_schematic->Root() );
306
307 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
308 {
309 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
310 {
311 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
312 LIB_SYMBOL* libSymbolInSchematic = symbol->GetLibSymbolRef().get();
313
314 if( !libSymbolInSchematic )
315 continue;
316
317 if( symbol->GetLibId().GetLibItemName() != "74LS00" )
318 continue;
319
320 int flags = ~SCH_ITEM::COMPARE_FLAGS::UUID;
321 flags &= ~SCH_ITEM::COMPARE_FLAGS::UNIT;
322 flags &= ~SCH_ITEM::COMPARE_FLAGS::IDENTITY;
323
324 int result = flattenedLibSymbol->Compare( *libSymbolInSchematic, flags );
325
327
328 // The default Compare Symbol settings should also not find changes
329 SCHEMATIC_SETTINGS defaultSettings( nullptr, "empty" );
330 int defaultFlags = defaultSettings.SymbolCompareFlags();
331
332 result = flattenedLibSymbol->Compare( *libSymbolInSchematic, defaultFlags );
333
335 return;
336 }
337 }
338
339 BOOST_FAIL( "No 74LS00 symbol found in schematic" );
340}
341
342
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:248
const kiapi::schematic::ErcExclusion & ToProto() const
static ERC_EXCLUSION FromMarker(const SCH_MARKER &aMarker)
static ERC_EXCLUSION FromProto(const kiapi::schematic::ErcExclusion &aMessage)
Runs the electrical rules checks and adds a SCH_MARKER for each violation.
Definition erc.h:60
int TestLibSymbolIssues()
Test symbols for changed library symbols and broken symbol library links.
Definition erc.cpp:2768
int TestVariantSymbols()
Test all variant symbol overrides for resolution and pin compatibility.
Definition erc.cpp:3185
Definition kiid.h:46
wxString AsString() const
Definition kiid.cpp:264
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
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
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
Define a library symbol object.
Definition lib_symbol.h:114
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
std::shared_ptr< RC_ITEM > GetRCItem() const
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:125
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
Definition project.h:63
These are loaded from Eeschema settings but then overwritten by the project settings.
A cache assistant for KiCad legacy symbol libraries.
const LIB_SYMBOL_MAP & GetSymbolMap() const
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:818
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:122
void DeleteItem(SCH_ITEM *aItem)
Remove aItem from the linked list and deletes the object.
Schematic symbol object.
Definition sch_symbol.h:73
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:163
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:182
RAII class that sets an value at construction and resets it to the original value at destruction.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
@ ERCE_VARIANT_SYMBOL_INCOMPATIBLE
Variant symbol override fails pin compatibility.
@ ERCE_LIB_SYMBOL_MISMATCH
Symbol doesn't match copy in library.
@ ERCE_LIB_SYMBOL_ISSUES
Symbol not found in active libraries.
@ ERCE_VARIANT_SYMBOL_INVALID
Variant symbol override LIB_ID cannot be resolved.
bool m_ConnectivityEngine
Use the schematic connectivity engine instead of CONNECTION_GRAPH.
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
std::string GetEeschemaTestDataDir()
Get the configured location of Eeschema test data.
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
std::vector< FAB_LAYER_COLOR > dummy
std::map< wxString, LIB_SYMBOL *, LibSymbolMapSort > LIB_SYMBOL_MAP
Symbol library map sorted by the symbol name.
BOOST_FIXTURE_TEST_CASE(ServerStartsAndResponds, API_SERVER_E2E_FIXTURE)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_FIXTURE_TEST_CASE(LibraryIssuesPreserveSharedPathsAndExclusions, ERC_LIB_SYMBOL_MISMATCH_FIXTURE)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
std::string path
VECTOR3I expected(15, 30, 45)
wxString result
Test unit parsing edge cases and error handling.
BOOST_CHECK_EQUAL(result, "25.4")
@ SCH_SYMBOL_T
Definition typeinfo.h:168
@ SCH_MARKER_T
Definition typeinfo.h:154