mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2024-11-22 04:05:02 +00:00
653d85f9fc
Mostly intended right now for allowing testing of library tables to help with testing chained loading, but it also decouples the idea of a library table from on-disk files in general. All current (real) lib table implementations continue to use the file-based IO. This could be made more general (not just for tables) if really needed.
389 lines
9.8 KiB
C++
389 lines
9.8 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2018-2019 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 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_TABLE_BASE
|
|
*
|
|
* This test is of a abstract class, so we will implement a cut-down
|
|
* version and only test the core logic. Tests of the concrete implementations's
|
|
* own logic should be done in the relevant tests.
|
|
*/
|
|
|
|
#include <qa_utils/wx_utils/unit_test_utils.h>
|
|
|
|
// Code under test
|
|
#include <lib_table_base.h>
|
|
|
|
namespace
|
|
{
|
|
|
|
/**
|
|
* A very simple implementation of #LIB_TABLE_IO that does nothing.
|
|
*
|
|
* If needed, this could be extended to provide some basic functionality
|
|
* like providing test data to be read.
|
|
*/
|
|
class DUMMY_LIB_TABLE_IO : public LIB_TABLE_IO
|
|
{
|
|
public:
|
|
std::unique_ptr<LINE_READER> GetReader( const wxString& aURI ) const override
|
|
{
|
|
return std::make_unique<STRING_LINE_READER>( "", "DUMMY_LIB_TABLE_IO Data" );
|
|
}
|
|
|
|
bool CanSaveToUri( const wxString& aURI ) const override
|
|
{
|
|
// Always return true, it'll just write to a dummy string
|
|
return true;
|
|
}
|
|
|
|
bool UrisAreEquivalent( const wxString& aURI1, const wxString& aURI2 ) const override
|
|
{
|
|
return aURI1 == aURI2;
|
|
}
|
|
|
|
std::unique_ptr<OUTPUTFORMATTER> GetWriter( const wxString& aURI ) const override
|
|
{
|
|
return std::make_unique<STRING_FORMATTER>();
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* A concrete implementation of #LIB_TABLE_ROW that implements
|
|
* the minimum interface.
|
|
*/
|
|
class TEST_LIB_TABLE_ROW : public LIB_TABLE_ROW
|
|
{
|
|
public:
|
|
TEST_LIB_TABLE_ROW( const wxString& aNick, const wxString& aURI, const wxString& aOptions,
|
|
const wxString& aDescr )
|
|
: LIB_TABLE_ROW( aNick, aURI, aOptions, aDescr )
|
|
{
|
|
}
|
|
|
|
const wxString GetType() const override
|
|
{
|
|
return m_type;
|
|
}
|
|
|
|
void SetType( const wxString& aType ) override
|
|
{
|
|
m_type = aType;
|
|
}
|
|
|
|
private:
|
|
LIB_TABLE_ROW* do_clone() const override
|
|
{
|
|
return new TEST_LIB_TABLE_ROW( *this );
|
|
}
|
|
|
|
wxString m_type;
|
|
};
|
|
|
|
|
|
/**
|
|
* A concrete implementation of #LIB_TABLE that implements
|
|
* the minimum interface for testing.
|
|
*
|
|
* Notably, the Parse/Format functions are not used, as there is no "real"
|
|
* format to read/write.
|
|
*/
|
|
class TEST_LIB_TABLE : public LIB_TABLE
|
|
{
|
|
public:
|
|
TEST_LIB_TABLE( LIB_TABLE* aFallback = nullptr ) :
|
|
LIB_TABLE( aFallback, std::make_unique<DUMMY_LIB_TABLE_IO>() )
|
|
{
|
|
}
|
|
|
|
PROJECT::ELEM ProjectElementType() override // from _ELEM
|
|
{
|
|
// Doesn't really matter what this is
|
|
return PROJECT::ELEM::FPTBL;
|
|
}
|
|
|
|
private:
|
|
void Parse( LIB_TABLE_LEXER* aLexer ) override
|
|
{
|
|
// Do nothing, we won't parse anything. Parse testing of actual data
|
|
// will happen in the relevant other tests.
|
|
}
|
|
|
|
void Format( OUTPUTFORMATTER* aOutput, int aIndentLevel ) const override
|
|
{
|
|
// do nothing, we don't need to test this function
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Simple structure to contain data to set up a single #TEST_LIB_TABLE_ROW
|
|
*/
|
|
struct LIB_ROW_DEFINITION
|
|
{
|
|
std::string m_nickname;
|
|
std::string m_uri;
|
|
std::string m_description;
|
|
bool m_enabled;
|
|
};
|
|
|
|
|
|
// clang-format off
|
|
/**
|
|
* Set-up data for the re-used library row definitions.
|
|
*/
|
|
static const std::vector<LIB_ROW_DEFINITION> main_lib_defs = {
|
|
{
|
|
"Lib1",
|
|
"://lib/1",
|
|
"The first library",
|
|
true,
|
|
},
|
|
{
|
|
"Lib2",
|
|
"://lib/2",
|
|
"The second library",
|
|
true,
|
|
},
|
|
{
|
|
"Lib3",
|
|
"://lib/3",
|
|
"The third library",
|
|
false,
|
|
},
|
|
};
|
|
|
|
static const std::vector<LIB_ROW_DEFINITION> fallback_lib_defs = {
|
|
{
|
|
"FallbackLib1",
|
|
"://lib/fb1",
|
|
"The first fallback library",
|
|
true,
|
|
},
|
|
{
|
|
"FallbackLib2",
|
|
"://lib/fb2",
|
|
"The second fallback library",
|
|
false,
|
|
},
|
|
};
|
|
// clang-format on
|
|
|
|
|
|
/**
|
|
* Reusable test fixture with some basic pre-filled tables.
|
|
*/
|
|
struct LIB_TABLE_TEST_FIXTURE
|
|
{
|
|
LIB_TABLE_TEST_FIXTURE() : m_mainTableWithFb( &m_fallbackTable )
|
|
{
|
|
for( const auto& lib : main_lib_defs )
|
|
{
|
|
m_mainTableNoFb.InsertRow( makeRowFromDef( lib ).release() );
|
|
m_mainTableWithFb.InsertRow( makeRowFromDef( lib ).release() );
|
|
}
|
|
|
|
for( const auto& lib : fallback_lib_defs )
|
|
{
|
|
m_fallbackTable.InsertRow( makeRowFromDef( lib ).release() );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper to construct a new #TEST_LIB_TABLE_ROW from a definition struct
|
|
*/
|
|
std::unique_ptr<TEST_LIB_TABLE_ROW> makeRowFromDef( const LIB_ROW_DEFINITION& aDef )
|
|
{
|
|
auto row = std::make_unique<TEST_LIB_TABLE_ROW>(
|
|
aDef.m_nickname, aDef.m_uri, "", aDef.m_description );
|
|
|
|
row->SetEnabled( aDef.m_enabled );
|
|
|
|
return row;
|
|
}
|
|
|
|
/// Table with some enabled and disabled libs, no fallback provided
|
|
TEST_LIB_TABLE m_mainTableNoFb;
|
|
|
|
/// Identical to m_mainTableNoFb, but with a fallback
|
|
TEST_LIB_TABLE m_mainTableWithFb;
|
|
|
|
/// The table that m_mainTableWithFb falls back to.
|
|
TEST_LIB_TABLE m_fallbackTable;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
/**
|
|
* Declare the test suite
|
|
*/
|
|
BOOST_FIXTURE_TEST_SUITE( LibTable, LIB_TABLE_TEST_FIXTURE )
|
|
|
|
/**
|
|
* Check an empty table behaves correctly
|
|
*/
|
|
BOOST_AUTO_TEST_CASE( Empty )
|
|
{
|
|
TEST_LIB_TABLE table;
|
|
|
|
// Tables start out empty
|
|
BOOST_CHECK_EQUAL( table.GetCount(), 0 );
|
|
BOOST_CHECK_EQUAL( true, table.IsEmpty() );
|
|
}
|
|
|
|
|
|
/**
|
|
* Check size and emptiness on tables with fallback
|
|
*/
|
|
BOOST_AUTO_TEST_CASE( EmptyWithFallback )
|
|
{
|
|
// Fall back though another empty table to the real fallback
|
|
TEST_LIB_TABLE interposer_table( &m_fallbackTable );
|
|
TEST_LIB_TABLE table( &interposer_table );
|
|
|
|
// Table has no elements...
|
|
BOOST_CHECK_EQUAL( table.GetCount(), 0 );
|
|
|
|
// But it's not empty if we include the fallback
|
|
BOOST_CHECK_EQUAL( false, table.IsEmpty( true ) );
|
|
}
|
|
|
|
|
|
/**
|
|
* Check table equality function
|
|
*/
|
|
BOOST_AUTO_TEST_CASE( Equal )
|
|
{
|
|
// writing a boot print is a bit of faff, so just use BOOST_CHECK_EQUAL and bools
|
|
|
|
// These two are identical, except the fallback (which isn't checked)
|
|
BOOST_CHECK_EQUAL( true, m_mainTableNoFb == m_mainTableWithFb );
|
|
BOOST_CHECK_EQUAL( false, m_mainTableNoFb != m_mainTableWithFb );
|
|
|
|
// Modify one of them
|
|
m_mainTableWithFb.At( 1 ).SetNickName( "NewNickname" );
|
|
BOOST_CHECK_EQUAL( false, m_mainTableNoFb == m_mainTableWithFb );
|
|
BOOST_CHECK_EQUAL( true, m_mainTableNoFb != m_mainTableWithFb );
|
|
|
|
// And check unequal (against empty)
|
|
TEST_LIB_TABLE empty_table;
|
|
BOOST_CHECK_EQUAL( false, m_mainTableNoFb == empty_table );
|
|
BOOST_CHECK_EQUAL( true, m_mainTableNoFb != empty_table );
|
|
}
|
|
|
|
|
|
/**
|
|
* Test indexing into the main table
|
|
*/
|
|
BOOST_AUTO_TEST_CASE( Indexing )
|
|
{
|
|
// Filled with the right row count
|
|
BOOST_CHECK_EQUAL( m_mainTableNoFb.GetCount(), 3 );
|
|
|
|
const auto& row0 = m_mainTableNoFb.At( 0 );
|
|
BOOST_CHECK_EQUAL( row0.GetNickName(), "Lib1" );
|
|
|
|
const auto& row1 = m_mainTableNoFb.At( 1 );
|
|
BOOST_CHECK_EQUAL( row1.GetNickName(), "Lib2" );
|
|
|
|
// disable, but still in the index
|
|
const auto& row2 = m_mainTableNoFb.At( 2 );
|
|
BOOST_CHECK_EQUAL( row2.GetNickName(), "Lib3" );
|
|
|
|
// check correct handling of out-of-bounds
|
|
// TODO: this doesn't work with boost::ptr_vector - that only asserts
|
|
// BOOST_CHECK_THROW( m_mainTableNoFb.At( 3 ), std::out_of_range );
|
|
}
|
|
|
|
|
|
/**
|
|
* Test retrieval of libs by nickname
|
|
*/
|
|
BOOST_AUTO_TEST_CASE( HasLibrary )
|
|
{
|
|
BOOST_CHECK_EQUAL( true, m_mainTableNoFb.HasLibrary( "Lib1" ) );
|
|
|
|
// disabled lib can be "not found" if checkEnabled is set
|
|
BOOST_CHECK_EQUAL( true, m_mainTableNoFb.HasLibrary( "Lib3" ) );
|
|
BOOST_CHECK_EQUAL( false, m_mainTableNoFb.HasLibrary( "Lib3", true ) );
|
|
|
|
BOOST_CHECK_EQUAL( false, m_mainTableNoFb.HasLibrary( "NotPresent" ) );
|
|
}
|
|
|
|
|
|
/**
|
|
* Test retrieval of libs by nickname
|
|
*/
|
|
BOOST_AUTO_TEST_CASE( Descriptions )
|
|
{
|
|
BOOST_CHECK_EQUAL( "The first library", m_mainTableNoFb.GetDescription( "Lib1" ) );
|
|
|
|
// disabled lib works
|
|
BOOST_CHECK_EQUAL( "The third library", m_mainTableNoFb.GetDescription( "Lib3" ) );
|
|
}
|
|
|
|
|
|
/**
|
|
* Test retrieval of libs by URI
|
|
*/
|
|
BOOST_AUTO_TEST_CASE( URIs )
|
|
{
|
|
BOOST_CHECK_EQUAL( "://lib/1", m_mainTableNoFb.GetFullURI( "Lib1" ) );
|
|
|
|
const LIB_TABLE_ROW* row = m_mainTableNoFb.FindRowByURI( "://lib/1" );
|
|
|
|
// should be found
|
|
BOOST_CHECK_NE( nullptr, row );
|
|
|
|
if( row )
|
|
{
|
|
BOOST_CHECK_EQUAL( "Lib1", row->GetNickName() );
|
|
}
|
|
|
|
row = m_mainTableNoFb.FindRowByURI( "this_uri_is_not_found" );
|
|
|
|
BOOST_CHECK_EQUAL( nullptr, row );
|
|
}
|
|
|
|
|
|
/**
|
|
* Test retrieval of the logical libs function
|
|
*/
|
|
BOOST_AUTO_TEST_CASE( LogicalLibs )
|
|
{
|
|
auto logical_libs = m_mainTableNoFb.GetLogicalLibs();
|
|
|
|
// The enabled library nicknames
|
|
const std::vector<wxString> exp_libs = {
|
|
"Lib1",
|
|
"Lib2",
|
|
};
|
|
|
|
BOOST_CHECK_EQUAL_COLLECTIONS(
|
|
logical_libs.begin(), logical_libs.end(), exp_libs.begin(), exp_libs.end() );
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|