Implement new native netlist QA test

This commit is contained in:
Jon Evans 2020-05-18 22:40:13 -04:00
parent 1c2ef8678c
commit f7578eb038
9 changed files with 276 additions and 39 deletions

View File

@ -536,6 +536,11 @@ public:
return m_aliases; return m_aliases;
} }
const std::vector<COMPONENT_INSTANCE_REFERENCE>& GetSymbolInstances() const
{
return m_symbolInstances;
}
#if defined(DEBUG) #if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override; void Show( int nestLevel, std::ostream& os ) const override;
#endif #endif

View File

@ -696,7 +696,7 @@ SCH_SHEET_PATH* SCH_SHEET_LIST::FindSheetForScreen( SCH_SCREEN* aScreen )
void SCH_SHEET_LIST::UpdateSymbolInstances( void SCH_SHEET_LIST::UpdateSymbolInstances(
std::vector<COMPONENT_INSTANCE_REFERENCE>& aSymbolInstances ) const std::vector<COMPONENT_INSTANCE_REFERENCE>& aSymbolInstances )
{ {
SCH_REFERENCE_LIST symbolInstances; SCH_REFERENCE_LIST symbolInstances;
@ -709,7 +709,7 @@ void SCH_SHEET_LIST::UpdateSymbolInstances(
wxString path = symbolInstances[i].GetPath(); wxString path = symbolInstances[i].GetPath();
auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(), auto it = std::find_if( aSymbolInstances.begin(), aSymbolInstances.end(),
[ path ]( COMPONENT_INSTANCE_REFERENCE& r )->bool [ path ]( const COMPONENT_INSTANCE_REFERENCE& r ) -> bool
{ {
return path == r.m_Path.AsString(); return path == r.m_Path.AsString();
} }

View File

@ -453,7 +453,7 @@ public:
* WARNING: Do not call this on anything other than the full hierarchy. * WARNING: Do not call this on anything other than the full hierarchy.
* @param aSymbolInstances is the symbol path information loaded from the root schematic. * @param aSymbolInstances is the symbol path information loaded from the root schematic.
*/ */
void UpdateSymbolInstances( std::vector<COMPONENT_INSTANCE_REFERENCE>& aSymbolInstances ); void UpdateSymbolInstances( const std::vector<COMPONENT_INSTANCE_REFERENCE>& aSymbolInstances );
std::vector<KIID_PATH> GetPaths() const; std::vector<KIID_PATH> GetPaths() const;

View File

@ -61,7 +61,7 @@ void COMPONENT::SetModule( MODULE* aModule )
COMPONENT_NET COMPONENT::m_emptyNet; COMPONENT_NET COMPONENT::m_emptyNet;
const COMPONENT_NET& COMPONENT::GetNet( const wxString& aPinName ) const COMPONENT_NET& COMPONENT::GetNet( const wxString& aPinName ) const
{ {
for( unsigned i = 0; i < m_nets.size(); i++ ) for( unsigned i = 0; i < m_nets.size(); i++ )
{ {

View File

@ -136,7 +136,7 @@ public:
const COMPONENT_NET& GetNet( unsigned aIndex ) const { return m_nets[aIndex]; } const COMPONENT_NET& GetNet( unsigned aIndex ) const { return m_nets[aIndex]; }
const COMPONENT_NET& GetNet( const wxString& aPinName ); const COMPONENT_NET& GetNet( const wxString& aPinName ) const;
void SortPins() { sort( m_nets.begin(), m_nets.end() ); } void SortPins() { sort( m_nets.begin(), m_nets.end() ); }

View File

@ -24,6 +24,13 @@
include_directories( BEFORE ${INC_BEFORE} ) include_directories( BEFORE ${INC_BEFORE} )
include_directories(
${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/pcbnew
${INC_AFTER}
)
set( QA_EESCHEMA_SRCS set( QA_EESCHEMA_SRCS
# stuff from common which is needed...why? # stuff from common which is needed...why?
${CMAKE_SOURCE_DIR}/common/colors.cpp ${CMAKE_SOURCE_DIR}/common/colors.cpp
@ -44,6 +51,7 @@ set( QA_EESCHEMA_SRCS
test_eagle_plugin.cpp test_eagle_plugin.cpp
test_lib_arc.cpp test_lib_arc.cpp
test_lib_part.cpp test_lib_part.cpp
test_netlists.cpp
test_sch_pin.cpp test_sch_pin.cpp
test_sch_rtree.cpp test_sch_rtree.cpp
test_sch_sheet.cpp test_sch_sheet.cpp
@ -76,6 +84,7 @@ add_dependencies( qa_eeschema eeschema )
target_link_libraries( qa_eeschema target_link_libraries( qa_eeschema
common common
pcbcommon
kimath kimath
qa_utils qa_utils
unit_test_utils unit_test_utils
@ -102,13 +111,3 @@ set_source_files_properties( eeschema_test_utils.cpp PROPERTIES
kicad_add_boost_test( qa_eeschema eeschema ) kicad_add_boost_test( qa_eeschema eeschema )
# eeschema netlist tests
# technically this doesn't depend on KICAD_SCRIPTING but if we have that, we know we have Python.
if( KICAD_SCRIPTING_MODULES AND KICAD_NETLIST_QA )
add_test( NAME qa_netlist
COMMAND ${PYTHON_EXECUTABLE} test_netlists.py ${CMAKE_BINARY_DIR}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
endif()

View File

@ -1,15 +1,15 @@
(export (version "D") (export (version "D")
(design (design
(source "/home/jon/work/kicad-master/qa/eeschema/data/netlists/test_global_promotion_2/test_global_promotion_2.sch") (source "test_global_promotion_2.kicad_sch")
(date "Sun 19 Apr 2020 18:19:54 EDT") (date "Sat 23 May 2020 16:07:49 EDT")
(tool "Eeschema (5.99.0-1348-g327eb1c7c-dirty)") (tool "Eeschema (5.99.0-1765-g3487670f2-dirty)")
(sheet (number "1") (name "/") (tstamps "/") (sheet (number "1") (name "/") (tstamps "/")
(title_block (title_block
(title) (title)
(company) (company)
(rev) (rev)
(date) (date)
(source "test_global_promotion_2.sch") (source "test_global_promotion_2.kicad_sch")
(comment (number "1") (value "")) (comment (number "1") (value ""))
(comment (number "2") (value "")) (comment (number "2") (value ""))
(comment (number "3") (value "")) (comment (number "3") (value ""))
@ -25,7 +25,7 @@
(company) (company)
(rev) (rev)
(date) (date)
(source "subsheet.sch") (source "subsheet.kicad_sch")
(comment (number "1") (value "")) (comment (number "1") (value ""))
(comment (number "2") (value "")) (comment (number "2") (value ""))
(comment (number "3") (value "")) (comment (number "3") (value ""))
@ -41,7 +41,7 @@
(company) (company)
(rev) (rev)
(date) (date)
(source "subsheet.sch") (source "subsheet.kicad_sch")
(comment (number "1") (value "")) (comment (number "1") (value ""))
(comment (number "2") (value "")) (comment (number "2") (value ""))
(comment (number "3") (value "")) (comment (number "3") (value ""))
@ -102,8 +102,7 @@
(fp "Connector*:*_1x??_*")) (fp "Connector*:*_1x??_*"))
(fields (fields
(field (name "Reference") "J") (field (name "Reference") "J")
(field (name "Value") "Conn_01x03_Male") (field (name "Value") "Conn_01x03_Male"))
(field (name "Datasheet") "~"))
(pins (pins
(pin (num "1") (name "Pin_1") (type "passive")) (pin (num "1") (name "Pin_1") (type "passive"))
(pin (num "2") (name "Pin_2") (type "passive")) (pin (num "2") (name "Pin_2") (type "passive"))
@ -115,28 +114,23 @@
(fp "R_*")) (fp "R_*"))
(fields (fields
(field (name "Reference") "R") (field (name "Reference") "R")
(field (name "Value") "R") (field (name "Value") "R"))
(field (name "Datasheet") "~"))
(pins (pins
(pin (num "1") (name "~") (type "passive")) (pin (num "1") (name "~") (type "passive"))
(pin (num "2") (name "~") (type "passive"))))) (pin (num "2") (name "~") (type "passive")))))
(libraries (libraries)
(library (logical "Connector")
(uri "/home/jon/kicad-library/kicad-symbols//Connector.lib"))
(library (logical "Device")
(uri "/home/jon/kicad-library/kicad-symbols//Device.lib")))
(nets (nets
(net (code "1") (name "/LIVE") (net (code "1") (name "/LIVE")
(node (ref "J2") (pin "1") (pinfunction "Pin_1")) (node (ref "J2") (pin "2") (pinfunction "Pin_2"))
(node (ref "R1") (pin "1")) (node (ref "R3") (pin "1"))
(node (ref "R2") (pin "1"))) (node (ref "R4") (pin "1")))
(net (code "2") (name "/LIVE_1") (net (code "2") (name "/LIVE_1")
(node (ref "J1") (pin "2") (pinfunction "Pin_2")) (node (ref "J1") (pin "2") (pinfunction "Pin_2"))
(node (ref "R4") (pin "2"))) (node (ref "R4") (pin "2")))
(net (code "3") (name "/LIVE_2") (net (code "3") (name "/LIVE_2")
(node (ref "J2") (pin "2") (pinfunction "Pin_2")) (node (ref "J2") (pin "1") (pinfunction "Pin_1"))
(node (ref "R3") (pin "1")) (node (ref "R1") (pin "1"))
(node (ref "R4") (pin "1"))) (node (ref "R2") (pin "1")))
(net (code "4") (name "/NEUTRAL") (net (code "4") (name "/NEUTRAL")
(node (ref "J2") (pin "3") (pinfunction "Pin_3")) (node (ref "J2") (pin "3") (pinfunction "Pin_3"))
(node (ref "R1") (pin "2")) (node (ref "R1") (pin "2"))
@ -145,4 +139,4 @@
(node (ref "J1") (pin "1") (pinfunction "Pin_1")) (node (ref "J1") (pin "1") (pinfunction "Pin_1"))
(node (ref "R2") (pin "2"))) (node (ref "R2") (pin "2")))
(net (code "6") (name "Net-(J1-Pad3)") (net (code "6") (name "Net-(J1-Pad3)")
(node (ref "J1") (pin "3") (pinfunction "Pin_3"))))) (node (ref "J1") (pin "3") (pinfunction "Pin_3")))))

View File

@ -28,8 +28,6 @@
#include <sch_edit_frame.h> #include <sch_edit_frame.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
// The main sheet of the project
SCH_SHEET* g_RootSheet = nullptr;
// a transform matrix, to display components in lib editor // a transform matrix, to display components in lib editor
TRANSFORM DefaultTransform = TRANSFORM( 1, 0, 0, -1 ); TRANSFORM DefaultTransform = TRANSFORM( 1, 0, 0, -1 );

View File

@ -0,0 +1,241 @@
/*
* 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 <wildcards_and_files_ext.h>
class TEST_NETLISTS_FIXTURE
{
public:
TEST_NETLISTS_FIXTURE() :
m_schematic( &m_project )
{
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;
///> Dummy project
PROJECT m_project;
SCH_PLUGIN* m_pi;
};
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_project.SetProjectFullName( pro.GetFullPath() );
m_project.SetElem( PROJECT::ELEM_SCH_PART_LIBS, nullptr );
m_schematic.Reset();
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_SUITE_END()