kicad-source/qa/eeschema/test_netlists.cpp
Jon Evans 487aa37d2e Connectivity: don't rename things multiple times in subsheets
Depending on what order the subgraphs are processed in, it's
possible to hit a case where the parent sheet renames a bus
member before the bus neighbor renaming logic runs.  In this
case, we don't want to apply the bus neighbor logic as it will
break connectivity to the parent sheet if that bus was not
also renamed (for example, if the hier ports only make net
connections and not bus connections)

Fixes https://gitlab.com/kicad/code/kicad/-/issues/6887
2020-12-29 16:42:30 -05:00

263 lines
6.9 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <unit_test_utils/unit_test_utils.h>
#include "eeschema_test_utils.h"
#include <connection_graph.h>
#include <netlist_exporter_kicad.h>
#include <netlist_reader/netlist_reader.h>
#include <netlist_reader/pcb_netlist.h>
#include <project.h>
#include <sch_io_mgr.h>
#include <sch_sheet.h>
#include <schematic.h>
#include <settings/settings_manager.h>
#include <wildcards_and_files_ext.h>
class TEST_NETLISTS_FIXTURE
{
public:
TEST_NETLISTS_FIXTURE() :
m_schematic( nullptr ),
m_manager( true )
{
m_pi = SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD );
}
void loadSchematic( const wxString& aBaseName );
wxString getNetlistFileName( bool aTest = false );
void writeNetlist();
void compareNetlists();
void cleanup();
void doNetlistTest( const wxString& aBaseName );
///> Schematic to load
SCHEMATIC m_schematic;
SCH_PLUGIN* m_pi;
SETTINGS_MANAGER m_manager;
};
static wxString getSchematicFile( const wxString& aBaseName )
{
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
fn.AppendDir( "netlists" );
fn.AppendDir( aBaseName );
fn.SetName( aBaseName );
fn.SetExt( KiCadSchematicFileExtension );
return fn.GetFullPath();
}
void TEST_NETLISTS_FIXTURE::loadSchematic( const wxString& aBaseName )
{
wxString fn = getSchematicFile( aBaseName );
BOOST_TEST_MESSAGE( fn );
wxFileName pro( fn );
pro.SetExt( ProjectFileExtension );
m_manager.LoadProject( pro.GetFullPath() );
m_manager.Prj().SetElem( PROJECT::ELEM_SCH_PART_LIBS, nullptr );
m_schematic.Reset();
m_schematic.SetProject( &m_manager.Prj() );
m_schematic.SetRoot( m_pi->Load( fn, &m_schematic ) );
BOOST_REQUIRE_EQUAL( m_pi->GetError().IsEmpty(), true );
m_schematic.CurrentSheet().push_back( &m_schematic.Root() );
SCH_SCREENS screens( m_schematic.Root() );
for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
screen->UpdateLocalLibSymbolLinks();
SCH_SHEET_LIST sheets = m_schematic.GetSheets();
// Restore all of the loaded symbol instances from the root sheet screen.
sheets.UpdateSymbolInstances( m_schematic.RootScreen()->GetSymbolInstances() );
sheets.AnnotatePowerSymbols();
// NOTE: This is required for multi-unit symbols to be correct
// Normally called from SCH_EDIT_FRAME::FixupJunctions() but could be refactored
for( SCH_SHEET_PATH& sheet : sheets )
sheet.UpdateAllScreenReferences();
// NOTE: SchematicCleanUp is not called; QA schematics must already be clean or else
// SchematicCleanUp must be freed from its UI dependencies.
m_schematic.ConnectionGraph()->Recalculate( sheets, true );
}
wxString TEST_NETLISTS_FIXTURE::getNetlistFileName( bool aTest )
{
wxFileName netFile = m_schematic.Prj().GetProjectFullName();
if( aTest )
netFile.SetName( netFile.GetName() + "_test" );
netFile.SetExt( NetlistFileExtension );
return netFile.GetFullPath();
}
void TEST_NETLISTS_FIXTURE::writeNetlist()
{
auto exporter = std::make_unique<NETLIST_EXPORTER_KICAD>( &m_schematic );
BOOST_REQUIRE_EQUAL( exporter->WriteNetlist( getNetlistFileName( true ), 0 ), true );
}
void TEST_NETLISTS_FIXTURE::compareNetlists()
{
NETLIST golden;
NETLIST test;
{
std::unique_ptr<NETLIST_READER> netlistReader( NETLIST_READER::GetNetlistReader(
&golden, getNetlistFileName(), wxEmptyString ) );
BOOST_REQUIRE_NO_THROW( netlistReader->LoadNetlist() );
}
{
std::unique_ptr<NETLIST_READER> netlistReader( NETLIST_READER::GetNetlistReader(
&test, getNetlistFileName( true ), wxEmptyString ) );
BOOST_REQUIRE_NO_THROW( netlistReader->LoadNetlist() );
}
// Number of components should match
BOOST_REQUIRE_EQUAL( golden.GetCount(), test.GetCount() );
for( unsigned i = 0; i < golden.GetCount(); i++ )
{
COMPONENT* goldenComp = golden.GetComponent( i );
COMPONENT* refComp = test.GetComponentByReference( goldenComp->GetReference() );
// Retrieval by reference
BOOST_REQUIRE_NE( refComp, nullptr );
// Retrieval by KIID
COMPONENT* pathComp = test.GetComponentByPath( goldenComp->GetPath() );
BOOST_REQUIRE_NE( pathComp, nullptr );
// We should have found the same component
BOOST_REQUIRE_EQUAL( refComp->GetReference(), pathComp->GetReference() );
// And that component should have the same number of attached nets
BOOST_REQUIRE_EQUAL( goldenComp->GetNetCount(), refComp->GetNetCount() );
for( unsigned net = 0; net < goldenComp->GetNetCount(); net++ )
{
const COMPONENT_NET& goldenNet = goldenComp->GetNet( net );
const COMPONENT_NET& testNet = refComp->GetNet( net );
// The two nets at the same index should be identical
BOOST_REQUIRE_EQUAL( goldenNet.GetPinName(), testNet.GetPinName() );
BOOST_REQUIRE_EQUAL( goldenNet.GetNetName(), testNet.GetNetName() );
}
}
}
void TEST_NETLISTS_FIXTURE::cleanup()
{
wxRemoveFile( getNetlistFileName( true ) );
}
void TEST_NETLISTS_FIXTURE::doNetlistTest( const wxString& aBaseName )
{
loadSchematic( aBaseName );
writeNetlist();
compareNetlists();
cleanup();
}
BOOST_FIXTURE_TEST_SUITE( Netlists, TEST_NETLISTS_FIXTURE )
BOOST_AUTO_TEST_CASE( FindPlugin )
{
BOOST_CHECK_NE( m_pi, nullptr );
}
BOOST_AUTO_TEST_CASE( GlobalPromotion )
{
doNetlistTest( "test_global_promotion" );
}
BOOST_AUTO_TEST_CASE( GlobalPromotion2 )
{
doNetlistTest( "test_global_promotion_2" );
}
BOOST_AUTO_TEST_CASE( Video )
{
doNetlistTest( "video" );
}
BOOST_AUTO_TEST_CASE( ComplexHierarchy )
{
doNetlistTest( "complex_hierarchy" );
}
BOOST_AUTO_TEST_CASE( WeakVectorBusDisambiguation )
{
doNetlistTest( "weak_vector_bus_disambiguation" );
}
BOOST_AUTO_TEST_CASE( BusJunctions )
{
doNetlistTest( "bus_junctions" );
}
BOOST_AUTO_TEST_CASE( HierRenaming )
{
doNetlistTest( "test_hier_renaming" );
}
BOOST_AUTO_TEST_SUITE_END()