kicad-source/qa/eeschema/test_lib_part.cpp
Wayne Stambaugh 54f066fed7 Implement simple inheritance for library symbols.
This change completely removes the LIB_ALIAS design pattern an replaces
it by allowing LIB_PART objects to inherit from other LIB_PART objects.
The initial implementation only allows for single inheritance and only
supports the mandatory fields in the derived part because that is all
that the current symbol library file format will support.  Once the new
file format is implemented and saving to the old file format is deprecated,
more complex inheritance will be added.  The LIB_ALIAS information saved
in the document files was move into the LIB_PART object.  This change
impacts virtually every part of the schematic and symbol library editor
code so this commit message is woefully incomplete.

REMOVE: Removed the symbol aliases concept from the schematic and symbol
editors and the symbol viewer.

NEW: Replace the symbol alias concept with simple inheritance that allows
a library symbol to be derived from another library symbol.
2019-12-06 11:33:52 -05:00

405 lines
13 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2019 KiCad Developers, see CHANGELOG.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 2
* 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, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file
* Test suite for LIB_PART
*/
#include <unit_test_utils/unit_test_utils.h>
// Code under test
#include <class_libentry.h>
#include <lib_rectangle.h>
#include <lib_arc.h>
#include <lib_pin.h>
#include "lib_field_test_utils.h"
class TEST_LIB_PART_FIXTURE
{
public:
TEST_LIB_PART_FIXTURE() : m_part_no_data( "part_name", nullptr )
{
}
///> Part with no extra data set
LIB_PART m_part_no_data;
};
/**
* Declare the test suite
*/
BOOST_FIXTURE_TEST_SUITE( LibPart, TEST_LIB_PART_FIXTURE )
/**
* Check that we can get the basic properties out as expected
*/
BOOST_AUTO_TEST_CASE( DefaultProperties )
{
BOOST_CHECK_EQUAL( m_part_no_data.GetName(), "part_name" );
// Didn't set a library, so this is empty
BOOST_CHECK_EQUAL( m_part_no_data.GetLibraryName(), "" );
BOOST_CHECK_EQUAL( m_part_no_data.GetLib(), nullptr );
// only get the root
BOOST_CHECK_EQUAL( m_part_no_data.IsRoot(), true );
BOOST_CHECK_EQUAL( m_part_no_data.IsAlias(), false );
BOOST_CHECK_EQUAL( m_part_no_data.SharedPtr().use_count(), 2 );
// no sub units
BOOST_CHECK_EQUAL( m_part_no_data.GetUnitCount(), 1 );
BOOST_CHECK_EQUAL( m_part_no_data.IsMulti(), false );
// no conversion
BOOST_CHECK_EQUAL( m_part_no_data.HasConversion(), false );
}
/**
* Check the drawings on a "blank" LIB_PART
*/
BOOST_AUTO_TEST_CASE( DefaultDrawings )
{
// default drawings exist
BOOST_CHECK_EQUAL( m_part_no_data.GetDrawItems().size(), 4 );
BOOST_CHECK_EQUAL( m_part_no_data.GetNextDrawItem( NULL, LIB_PIN_T ), (LIB_ITEM*)NULL );
}
/**
* Check the default fields are present as expected
*/
BOOST_AUTO_TEST_CASE( DefaultFields )
{
LIB_FIELDS fields;
m_part_no_data.GetFields( fields );
// Should get the 4 default fields
BOOST_CHECK_PREDICATE( KI_TEST::AreDefaultFieldsCorrect, ( fields ) );
// but no more (we didn't set them)
BOOST_CHECK_EQUAL( fields.size(), NumFieldType::MANDATORY_FIELDS );
// also check the default field accessors
BOOST_CHECK_PREDICATE( KI_TEST::FieldNameIdMatches,
( m_part_no_data.GetReferenceField() )( "Reference" )( NumFieldType::REFERENCE ) );
BOOST_CHECK_PREDICATE( KI_TEST::FieldNameIdMatches,
( m_part_no_data.GetValueField() )( "Value" )( NumFieldType::VALUE ) );
BOOST_CHECK_PREDICATE( KI_TEST::FieldNameIdMatches,
( m_part_no_data.GetFootprintField() )( "Footprint" )( NumFieldType::FOOTPRINT ) );
}
/**
* Test adding fields to a LIB_PART
*/
BOOST_AUTO_TEST_CASE( AddedFields )
{
LIB_FIELDS fields;
m_part_no_data.GetFields( fields );
// Ctor takes non-const ref (?!)
const std::string newFieldName = "new_field";
wxString nonConstNewFieldName = newFieldName;
fields.push_back( LIB_FIELD( 42, nonConstNewFieldName ) );
// fairly roundabout way to add a field, but it is what it is
m_part_no_data.SetFields( fields );
// Should get the 4 default fields
BOOST_CHECK_PREDICATE( KI_TEST::AreDefaultFieldsCorrect, ( fields ) );
// and our new one
BOOST_REQUIRE_EQUAL( fields.size(), NumFieldType::MANDATORY_FIELDS + 1 );
BOOST_CHECK_PREDICATE( KI_TEST::FieldNameIdMatches,
( fields[NumFieldType::MANDATORY_FIELDS] )( newFieldName )( 42 ) );
// Check by-id lookup
LIB_FIELD* gotNewField = m_part_no_data.GetField( 42 );
BOOST_REQUIRE_NE( gotNewField, nullptr );
BOOST_CHECK_PREDICATE( KI_TEST::FieldNameIdMatches, ( *gotNewField )( newFieldName )( 42 ) );
// Check by-name lookup
gotNewField = m_part_no_data.FindField( newFieldName );
BOOST_REQUIRE_NE( gotNewField, nullptr );
BOOST_CHECK_PREDICATE( KI_TEST::FieldNameIdMatches, ( *gotNewField )( newFieldName )( 42 ) );
}
/**
* Test adding draw items to a LIB_PART
*/
BOOST_AUTO_TEST_CASE( AddedDrawItems )
{
}
struct TEST_LIB_PART_SUBREF_CASE
{
int m_index;
bool m_addSep;
std::string m_expSubRef;
};
/**
* Test the subreference indexing
*/
BOOST_AUTO_TEST_CASE( SubReference )
{
const std::vector<TEST_LIB_PART_SUBREF_CASE> cases = {
{
1,
false,
"A",
},
{
2,
false,
"B",
},
{
26,
false,
"Z",
},
{
27,
false,
"AA",
},
{ // haven't configured a separator, so should be nothing
1,
true,
"A",
},
};
for( const auto& c : cases )
{
BOOST_TEST_CONTEXT(
"Subref: " << c.m_index << ", " << c.m_addSep << " -> '" << c.m_expSubRef << "'" )
{
const auto subref = m_part_no_data.SubReference( c.m_index, c.m_addSep );
BOOST_CHECK_EQUAL( subref, c.m_expSubRef );
}
}
}
/**
* Check the compare method.
*/
BOOST_AUTO_TEST_CASE( Compare )
{
// Identical root part to m_part_no_data sans time stamp.
LIB_PART testPart( "part_name" );
// Self comparison test.
BOOST_CHECK_EQUAL( m_part_no_data.Compare( m_part_no_data ), 0 );
// Test for identical LIB_PART.
BOOST_CHECK_EQUAL( m_part_no_data.Compare( testPart ), 0 );
// Test name.
testPart.SetName( "tart_name" );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
testPart.SetName( "cart_name" );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
testPart.SetName( "part_name" );
// LIB_ID comparison tests.
LIB_ID id = testPart.GetLibId();
id.SetLibItemName( "tart_name" );
testPart.SetLibId( id );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
id.SetLibItemName( "cart_name" );
testPart.SetLibId( id );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
id.SetLibItemName( "part_name" );
testPart.SetLibId( id );
// Unit count comparison tests.
testPart.SetUnitCount( 2 );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
testPart.SetUnitCount( 1 );
m_part_no_data.SetUnitCount( 2 );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.SetUnitCount( 1 );
// Options flag comparison tests.
testPart.SetPower();
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
testPart.SetNormal();
m_part_no_data.SetPower();
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.SetNormal();
// Draw item list size comparison tests.
testPart.AddDrawItem( new LIB_RECTANGLE( &testPart ) );
m_part_no_data.AddDrawItem( new LIB_RECTANGLE( &m_part_no_data ) );
BOOST_CHECK_EQUAL( m_part_no_data.Compare( testPart ), 0 );
m_part_no_data.RemoveDrawItem( m_part_no_data.GetNextDrawItem( nullptr, LIB_RECTANGLE_T ) );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
testPart.RemoveDrawItem( testPart.GetNextDrawItem( nullptr, LIB_RECTANGLE_T ) );
m_part_no_data.AddDrawItem( new LIB_RECTANGLE( &m_part_no_data ) );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.RemoveDrawItem( m_part_no_data.GetNextDrawItem( nullptr, LIB_RECTANGLE_T ) );
// Draw item list contents comparison tests.
testPart.AddDrawItem( new LIB_RECTANGLE( &testPart ) );
m_part_no_data.AddDrawItem( new LIB_ARC( &m_part_no_data ) );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
m_part_no_data.RemoveDrawItem( m_part_no_data.GetNextDrawItem( nullptr, LIB_ARC_T ) );
m_part_no_data.AddDrawItem( new LIB_PIN( &m_part_no_data ) );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.RemoveDrawItem( m_part_no_data.GetNextDrawItem( nullptr, LIB_PIN_T ) );
testPart.RemoveDrawItem( testPart.GetNextDrawItem( nullptr, LIB_RECTANGLE_T ) );
// Footprint filter array comparison tests.
wxArrayString footPrintFilters;
BOOST_CHECK( m_part_no_data.GetFootprints() == footPrintFilters );
footPrintFilters.Add( "b" );
testPart.SetFootprintFilters( footPrintFilters );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
m_part_no_data.SetFootprintFilters( footPrintFilters );
footPrintFilters.Clear();
testPart.SetFootprintFilters( footPrintFilters );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
footPrintFilters.Clear();
m_part_no_data.SetFootprintFilters( footPrintFilters );
testPart.SetFootprintFilters( footPrintFilters );
// Description string tests.
m_part_no_data.SetDescription( "b" );
testPart.SetDescription( "b" );
BOOST_CHECK_EQUAL( m_part_no_data.Compare( testPart ), 0 );
m_part_no_data.SetDescription( "a" );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
m_part_no_data.SetDescription( "c" );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.SetDescription( wxEmptyString );
testPart.SetDescription( wxEmptyString );
// Key word string tests.
m_part_no_data.SetKeyWords( "b" );
testPart.SetKeyWords( "b" );
BOOST_CHECK_EQUAL( m_part_no_data.Compare( testPart ), 0 );
m_part_no_data.SetKeyWords( "a" );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
m_part_no_data.SetKeyWords( "c" );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.SetKeyWords( wxEmptyString );
testPart.SetKeyWords( wxEmptyString );
// Documentation file string tests.
m_part_no_data.SetDocFileName( "b" );
testPart.SetDocFileName( "b" );
BOOST_CHECK_EQUAL( m_part_no_data.Compare( testPart ), 0 );
m_part_no_data.SetDocFileName( "a" );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
m_part_no_data.SetDocFileName( "c" );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.SetDocFileName( wxEmptyString );
testPart.SetDocFileName( wxEmptyString );
// Pin name offset comparison tests.
testPart.SetPinNameOffset( testPart.GetPinNameOffset() + 1 );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
testPart.SetPinNameOffset( testPart.GetPinNameOffset() - 2 );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
testPart.SetPinNameOffset( testPart.GetPinNameOffset() + 1 );
// Units locked flag comparision tests.
testPart.LockUnits( true );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
testPart.LockUnits( false );
m_part_no_data.LockUnits( true );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
m_part_no_data.LockUnits( false );
// Show pin names flag comparison tests.
m_part_no_data.SetShowPinNames( false );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
m_part_no_data.SetShowPinNames( true );
testPart.SetShowPinNames( false );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
testPart.SetShowPinNames( true );
// Show pin numbers flag comparison tests.
m_part_no_data.SetShowPinNumbers( false );
BOOST_CHECK( m_part_no_data.Compare( testPart ) < 0 );
m_part_no_data.SetShowPinNumbers( true );
testPart.SetShowPinNumbers( false );
BOOST_CHECK( m_part_no_data.Compare( testPart ) > 0 );
testPart.SetShowPinNumbers( true );
// Time stamp comparison tests.
}
/**
* Check inheritance support.
*/
BOOST_AUTO_TEST_CASE( Inheritance )
{
std::unique_ptr< LIB_PART > parent( new LIB_PART( "parent" ) );
BOOST_CHECK( parent->IsRoot() );
std::unique_ptr< LIB_PART > child1( new LIB_PART( "child1", parent.get() ) );
BOOST_CHECK( child1->IsAlias() );
PART_SPTR parentRef = child1->GetParent().lock();
BOOST_CHECK( parentRef );
BOOST_CHECK( parentRef == parent->SharedPtr() );
BOOST_CHECK_EQUAL( parent->SharedPtr().use_count(), 3 );
BOOST_CHECK_EQUAL( child1->GetUnitCount(), 1 );
parent->SetUnitCount( 4 );
BOOST_CHECK_EQUAL( child1->GetUnitCount(), 4 );
child1->SetParent();
BOOST_CHECK_EQUAL( child1->GetUnitCount(), 1 );
parentRef.reset();
BOOST_CHECK_EQUAL( parent->SharedPtr().use_count(), 2 );
}
/**
* Check the copy constructor.
*/
BOOST_AUTO_TEST_CASE( CopyConstructor )
{
std::shared_ptr< LIB_PART > copy( new LIB_PART( m_part_no_data ) );
BOOST_CHECK( m_part_no_data == *copy.get() );
}
BOOST_AUTO_TEST_SUITE_END()