diff --git a/Documentation/development/testing.md b/Documentation/development/testing.md index be51c05c58..49756b1c9f 100644 --- a/Documentation/development/testing.md +++ b/Documentation/development/testing.md @@ -130,6 +130,15 @@ the triggering of a bug prior to fixing it. This is advantageous, not only from a "project history" perspective, but also to ensure that the test you write to catch the bug in question does, in fact, catch the bug in the first place. +### Assertions {#test-assertions} + +It is possible to check for assertions in unit tests. When running the unit +tests, `wxASSERT` calls are caught and re-thrown as exceptions. You can then use +the `CHECK_WX_ASSERT` macro to check this is called in Debug builds. In Release +builds, the check is not run, as `wxASSERT` is disabled in these builds. + +You can use this to ensure that code rejects invalid input correctly. + ## Python modules {#python-tests} The Pcbnew Python modules have some test programs in the `qa` directory. diff --git a/qa/eeschema/CMakeLists.txt b/qa/eeschema/CMakeLists.txt index 6880ab7b79..ae411de6bf 100644 --- a/qa/eeschema/CMakeLists.txt +++ b/qa/eeschema/CMakeLists.txt @@ -32,12 +32,20 @@ add_executable( qa_eeschema ../../common/colors.cpp ../../common/observable.cpp + # need the mock Pgm for many functions + mocks_eeschema.cpp + eeschema_test_utils.cpp + timestamp_test_utils.cpp # The main test entry points test_module.cpp test_eagle_plugin.cpp + test_lib_part.cpp + test_sch_pin.cpp + test_sch_sheet.cpp + test_sch_sheet_path.cpp # Older CMakes cannot link OBJECT libraries # https://cmake.org/pipermail/cmake/2013-November/056263.html diff --git a/qa/eeschema/lib_field_test_utils.h b/qa/eeschema/lib_field_test_utils.h new file mode 100644 index 0000000000..51288420fd --- /dev/null +++ b/qa/eeschema/lib_field_test_utils.h @@ -0,0 +1,122 @@ +/* + * 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 utils (e.g. print helpers and test predicates for LIB_FIELD objects + */ + +#ifndef QA_EESCHEMA_LIB_FIELD_TEST_UTILS__H +#define QA_EESCHEMA_LIB_FIELD_TEST_UTILS__H + +#include + +#include +#include + + +BOOST_TEST_PRINT_NAMESPACE_OPEN +{ +template <> +struct print_log_value +{ + inline void operator()( std::ostream& os, LIB_FIELD const& f ) + { + os << "LIB_FIELD[ " << f.GetName() << " ]"; + } +}; + +template <> +struct print_log_value +{ + inline void operator()( std::ostream& os, LIB_FIELDS const& f ) + { + os << "LIB_FIELDS[ " << f.size() << " ]"; + } +}; +} +BOOST_TEST_PRINT_NAMESPACE_CLOSE + + +namespace KI_TEST +{ + +/** + * Predicate to check a field name is as expected + * @param aField LIB_FIELD to check the name + * @param aExpectedName the expected field name + * @param aExpectedId the expected field id + * @return true if match + */ +bool FieldNameIdMatches( + const LIB_FIELD& aField, const std::string& aExpectedName, int aExpectedId ) +{ + bool ok = true; + const auto gotName = aField.GetName( false ); + + if( gotName != aExpectedName ) + { + BOOST_TEST_INFO( + "Field name mismatch: got '" << gotName << "', expected '" << aExpectedName ); + ok = false; + } + + const int gotId = aField.GetId(); + + if( gotId != aExpectedId ) + { + BOOST_TEST_INFO( "Field ID mismatch: got '" << gotId << "', expected '" << aExpectedId ); + ok = false; + } + + return ok; +} + +/** + * Predicate to check that the mandatory fields in a LIB_FIELDS object look sensible + * @param aFields the fields to check + * @return true if valid + */ +bool AreDefaultFieldsCorrect( const LIB_FIELDS& aFields ) +{ + const unsigned expectedCount = NumFieldType::MANDATORY_FIELDS; + if( aFields.size() < expectedCount ) + { + BOOST_TEST_INFO( + "Expected at least " << expectedCount << " fields, got " << aFields.size() ); + return false; + } + + bool ok = true; + + ok &= FieldNameIdMatches( aFields[0], "Reference", NumFieldType::REFERENCE ); + ok &= FieldNameIdMatches( aFields[1], "Value", NumFieldType::VALUE ); + ok &= FieldNameIdMatches( aFields[2], "Footprint", NumFieldType::FOOTPRINT ); + ok &= FieldNameIdMatches( aFields[3], "Datasheet", NumFieldType::DATASHEET ); + + return ok; +} + +} // namespace KI_TEST + +#endif // QA_EESCHEMA_LIB_FIELD_TEST_UTILS__H \ No newline at end of file diff --git a/qa/eeschema/mocks_eeschema.cpp b/qa/eeschema/mocks_eeschema.cpp new file mode 100644 index 0000000000..4b21eadc9c --- /dev/null +++ b/qa/eeschema/mocks_eeschema.cpp @@ -0,0 +1,141 @@ +/* + * 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 + */ + +#include +#include + +#include + +// The main sheet of the project +SCH_SHEET* g_RootSheet = nullptr; + +// a transform matrix, to display components in lib editor +TRANSFORM DefaultTransform = TRANSFORM( 1, 0, 0, -1 ); + +static struct IFACE : public KIFACE_I +{ + // Of course all are overloads, implementations of the KIFACE. + + IFACE( const char* aName, KIWAY::FACE_T aType ) : KIFACE_I( aName, aType ) + { + } + + bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits ) override + { + return true; + } + + void OnKifaceEnd() override + { + } + + wxWindow* CreateWindow( + wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override + { + assert( false ); + return nullptr; + } + + /** + * Function IfaceOrAddress + * return a pointer to the requested object. The safest way to use this + * is to retrieve a pointer to a static instance of an interface, similar to + * how the KIFACE interface is exported. But if you know what you are doing + * use it to retrieve anything you want. + * + * @param aDataId identifies which object you want the address of. + * + * @return void* - and must be cast into the know type. + */ + void* IfaceOrAddress( int aDataId ) override + { + return NULL; + } +} kiface( "mock_eeschema", KIWAY::FACE_SCH ); + +static struct PGM_MOCK_EESCHEMA_FRAME : public PGM_BASE +{ + bool OnPgmInit(); + + void OnPgmExit() + { + Kiway.OnKiwayEnd(); + + // Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl + // earlier than wxApp and earlier than static destruction would. + PGM_BASE::Destroy(); + } + + void MacOpenFile( const wxString& aFileName ) override + { + wxFileName filename( aFileName ); + + if( filename.FileExists() ) + { +#if 0 + // this pulls in EDA_DRAW_FRAME type info, which we don't want in + // the single_top link image. + KIWAY_PLAYER* frame = dynamic_cast( App().GetTopWindow() ); +#else + KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow(); +#endif + + if( frame ) + frame->OpenProjectFiles( std::vector( 1, aFileName ) ); + } + } +} program; + +PGM_BASE& Pgm() +{ + return program; +} + + +KIFACE_I& Kiface() +{ + return kiface; +} + + +static COLOR4D s_layerColor[LAYER_ID_COUNT]; + +COLOR4D GetLayerColor( SCH_LAYER_ID aLayer ) +{ + unsigned layer = ( aLayer ); + wxASSERT( layer < arrayDim( s_layerColor ) ); + return s_layerColor[layer]; +} + +void SetLayerColor( COLOR4D aColor, SCH_LAYER_ID aLayer ) +{ + // Do not allow non-background layers to be completely white. + // This ensures the BW printing recognizes that the colors should be + // printed black. + if( aColor == COLOR4D::WHITE && aLayer != LAYER_SCHEMATIC_BACKGROUND ) + aColor.Darken( 0.01 ); + + unsigned layer = aLayer; + wxASSERT( layer < arrayDim( s_layerColor ) ); + s_layerColor[layer] = aColor; +} \ No newline at end of file diff --git a/qa/eeschema/test_lib_part.cpp b/qa/eeschema/test_lib_part.cpp new file mode 100644 index 0000000000..10ecd9532d --- /dev/null +++ b/qa/eeschema/test_lib_part.cpp @@ -0,0 +1,206 @@ +/* + * 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 + +// Code under test +#include + +#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.GetAliasCount(), 1 ); + + // 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 ); +} + + +/** + * 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 ) ); +} + + +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 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 ); + } + } +} + + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/qa/eeschema/test_module.cpp b/qa/eeschema/test_module.cpp index 5dbce91ca6..732f88b7e2 100644 --- a/qa/eeschema/test_module.cpp +++ b/qa/eeschema/test_module.cpp @@ -30,11 +30,29 @@ #include +#include + +/* + * Simple function to handle a WX assertion and throw a real exception. + * + * This is useful when you want to check assertions fire in unit tests. + */ +void wxAssertThrower( const wxString& aFile, int aLine, const wxString& aFunc, + const wxString& aCond, const wxString& aMsg ) +{ + throw KI_TEST::WX_ASSERT_ERROR( aFile, aLine, aFunc, aCond, aMsg ); +} + bool init_unit_test() { boost::unit_test::framework::master_test_suite().p_name.value = "Common Eeschema module tests"; - return wxInitialize(); + + bool ok = wxInitialize(); + + wxSetAssertHandler( &wxAssertThrower ); + + return ok; } diff --git a/qa/eeschema/test_sch_pin.cpp b/qa/eeschema/test_sch_pin.cpp new file mode 100644 index 0000000000..a8d2d44844 --- /dev/null +++ b/qa/eeschema/test_sch_pin.cpp @@ -0,0 +1,159 @@ +/* + * 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 SCH_PIM + */ + +#include +#include +#include + +// Code under test +#include + +#include + +#include + + +class TEST_SCH_PIN_FIXTURE +{ +public: + TEST_SCH_PIN_FIXTURE() + : m_parent_part( "parent_part", nullptr ), + m_lib_pin( &m_parent_part ), + m_parent_comp( wxPoint( 0, 0 ), nullptr ), + m_sch_pin( &m_lib_pin, &m_parent_comp ) + { + // give the pin some kind of data we can use to test + m_lib_pin.SetNumber( "42" ); + m_lib_pin.SetName( "pinname" ); + m_lib_pin.SetType( ELECTRICAL_PINTYPE::PIN_INPUT ); + + SCH_SHEET_PATH path; + m_parent_comp.SetRef( &path, "U2" ); + } + + LIB_PART m_parent_part; + LIB_PIN m_lib_pin; + + SCH_COMPONENT m_parent_comp; + SCH_PIN m_sch_pin; +}; + + +/** + * Declare the test suite + */ +BOOST_FIXTURE_TEST_SUITE( SchPin, TEST_SCH_PIN_FIXTURE ) + +/** + * Check basic properties of an un-modified SCH_PIN object + */ +BOOST_AUTO_TEST_CASE( DefaultProperties ) +{ + BOOST_CHECK_EQUAL( m_sch_pin.GetParentComponent(), &m_parent_comp ); + BOOST_CHECK_EQUAL( m_sch_pin.GetLibPin(), &m_lib_pin ); + + BOOST_CHECK_EQUAL( m_sch_pin.GetPosition(), wxPoint( 0, 0 ) ); + + // These just forward to LIB_PIN for now, so this isn't very interesting + // but later we will want to test these functions for SCH_PIN's own functionality + BOOST_CHECK_EQUAL( m_sch_pin.IsVisible(), m_lib_pin.IsVisible() ); + BOOST_CHECK_EQUAL( m_sch_pin.GetName(), m_lib_pin.GetName() ); + BOOST_CHECK_EQUAL( m_sch_pin.GetNumber(), m_lib_pin.GetNumber() ); + BOOST_CHECK_EQUAL( m_sch_pin.GetType(), m_lib_pin.GetType() ); + BOOST_CHECK_EQUAL( m_sch_pin.IsPowerConnection(), m_lib_pin.IsPowerConnection() ); +} + +/** + * Check the assignment operator + */ +BOOST_AUTO_TEST_CASE( Assign ) +{ + SCH_PIN assigned = m_sch_pin; + + BOOST_CHECK_EQUAL( assigned.GetParentComponent(), &m_parent_comp ); +} + +/** + * Check the copy ctor + */ +BOOST_AUTO_TEST_CASE( Copy ) +{ + SCH_PIN copied( m_sch_pin ); + + BOOST_CHECK_EQUAL( copied.GetParentComponent(), &m_parent_comp ); +} + +/** + * Check the pin dangling flag + */ +BOOST_AUTO_TEST_CASE( PinDangling ) +{ + // dangles by default + BOOST_CHECK_EQUAL( m_sch_pin.IsDangling(), true ); + + // all you have to do to un-dangle is say so + m_sch_pin.SetIsDangling( false ); + BOOST_CHECK_EQUAL( m_sch_pin.IsDangling(), false ); + + // and the same to re-dangle + m_sch_pin.SetIsDangling( true ); + BOOST_CHECK_EQUAL( m_sch_pin.IsDangling(), true ); +} + +/** + * Check the pin labelling + */ +BOOST_AUTO_TEST_CASE( PinNumbering ) +{ + SCH_SHEET_PATH path; + + const wxString name = m_sch_pin.GetDefaultNetName( path ); + BOOST_CHECK_EQUAL( name, "Net-(U2-Pad42)" ); + + // do it again: this should now (transparently) go though the net name map + // can't really check directly, but coverage tools should see this + const wxString map_name = m_sch_pin.GetDefaultNetName( path ); + BOOST_CHECK_EQUAL( map_name, name ); +} + +/** + * Check the pin labelling when it's a power pin + */ +BOOST_AUTO_TEST_CASE( PinNumberingPower ) +{ + // but if we set is power... + m_lib_pin.SetType( ELECTRICAL_PINTYPE::PIN_POWER_IN ); + m_parent_part.SetPower(); + + // the name is just the pin name + SCH_SHEET_PATH path; + const wxString pwr_name = m_sch_pin.GetDefaultNetName( path ); + BOOST_CHECK_EQUAL( pwr_name, "pinname" ); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/qa/eeschema/test_sch_sheet.cpp b/qa/eeschema/test_sch_sheet.cpp new file mode 100644 index 0000000000..36fa54f9a1 --- /dev/null +++ b/qa/eeschema/test_sch_sheet.cpp @@ -0,0 +1,243 @@ +/* + * 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 SCH_SHEET + */ + +#include + +// Code under test +#include + +#include "timestamp_test_utils.h" + +#include + +class TEST_SCH_SHEET_FIXTURE +{ +public: + TEST_SCH_SHEET_FIXTURE() : m_sheet(), m_csheet( m_sheet ) + { + } + + SCH_SHEET m_sheet; + + ///> Can use when you need a const ref (lots of places need fixing here) + const SCH_SHEET& m_csheet; +}; + + +/** + * Print helper. + * Not a print_log_value because old Boosts don't like that in BOOST_CHECK_EQUAL_COLLECTIONS + */ +std::ostream& operator<<( std::ostream& os, DANGLING_END_ITEM const& d ) +{ + os << "DANGLING_END_ITEM[ type " << d.GetType() << " @(" << d.GetPosition().x << ", " + << d.GetPosition().y << "), item " << d.GetItem() << ", parent " << d.GetParent() << " ]"; + return os; +} + +bool operator==( const DANGLING_END_ITEM& aA, const DANGLING_END_ITEM& aB ) +{ + return aA.GetItem() == aB.GetItem() + && aA.GetPosition() == aB.GetPosition() + && aA.GetType() == aB.GetType() + && aA.GetParent() == aB.GetParent(); +} + +bool operator!=( const DANGLING_END_ITEM& aA, const DANGLING_END_ITEM& aB ) +{ + return !( aA == aB ); +} + +/** + * Declare the test suite + */ +BOOST_FIXTURE_TEST_SUITE( SchSheet, TEST_SCH_SHEET_FIXTURE ) + + +/** + * Check default properties + */ +BOOST_AUTO_TEST_CASE( Default ) +{ + BOOST_CHECK_EQUAL( m_csheet.GetPosition(), wxPoint( 0, 0 ) ); + + BOOST_CHECK_PREDICATE( KI_TEST::EndsInTimestamp, ( m_csheet.GetName().ToStdString() ) ); + + // it is it's own root sheet + BOOST_CHECK_EQUAL( m_sheet.GetRootSheet(), &m_sheet ); + BOOST_CHECK_EQUAL( m_sheet.CountSheets(), 1 ); + + BOOST_CHECK_EQUAL( m_csheet.GetScreenCount(), 0 ); + + BOOST_CHECK_EQUAL( m_sheet.ComponentCount(), 0 ); +} + +/** + * Test adding pins to a sheet + */ +BOOST_AUTO_TEST_CASE( AddPins ) +{ + const wxPoint pinPos{ 42, 13 }; + + // we should catch null insertions + CHECK_WX_ASSERT( m_sheet.AddPin( nullptr ) ); + + auto newPin = std::make_unique( &m_sheet, pinPos, "pinname" ); + + // can't be const because of RemovePin (?!) + SCH_SHEET_PIN& pinRef = *newPin; + + m_sheet.AddPin( newPin.release() ); + + // now we can find it in the list + BOOST_CHECK_EQUAL( m_sheet.HasPins(), true ); + BOOST_CHECK_EQUAL( m_sheet.HasPin( "pinname" ), true ); + BOOST_CHECK_EQUAL( m_sheet.HasPin( "PINname" ), true ); + + BOOST_CHECK_EQUAL( m_sheet.GetPin( pinPos ), &pinRef ); + + // check the actual list can be retrieved + // this should be const... + SCH_SHEET_PINS& pins = m_sheet.GetPins(); + BOOST_CHECK_EQUAL( &pins[0], &pinRef ); + + // catch the bad call + CHECK_WX_ASSERT( m_sheet.RemovePin( nullptr ) ); + + m_sheet.RemovePin( &pinRef ); + + // and it's gone + BOOST_CHECK_EQUAL( m_sheet.HasPins(), false ); + BOOST_CHECK_EQUAL( m_sheet.HasPin( "pinname" ), false ); + BOOST_CHECK_EQUAL( m_sheet.GetPin( pinPos ), nullptr ); +} + +/** + * Check that pins are added and renumbered to be unique + */ +BOOST_AUTO_TEST_CASE( PinRenumbering ) +{ + for( int i = 0; i < 5; ++i ) + { + auto pin = std::make_unique( &m_sheet, wxPoint{ i, i }, "name" ); + + // set the pins to have the same number going in + pin->SetNumber( 2 ); + + m_sheet.AddPin( pin.release() ); + } + + SCH_SHEET_PINS& pins = m_sheet.GetPins(); + + std::vector numbers; + + for( const auto& pin : pins ) + { + numbers.push_back( pin.GetNumber() ); + } + + // and now...they are all unique + BOOST_CHECK_PREDICATE( KI_TEST::CollectionHasNoDuplicates, ( numbers ) ); +} + + +struct TEST_END_CONN_PIN +{ + std::string m_pin_name; + wxPoint m_pos; +}; + + +/** + * Test the endpoint and connection point collections: we should be able to add pins, then + * have them appear as endpoints. + */ +BOOST_AUTO_TEST_CASE( EndconnectionPoints ) +{ + // x = zero because the pin is clamped to the left side by default + const std::vector pin_defs = { + { + "1name", + { 0, 13 }, + }, + { + "2name", + { 0, 130 }, + }, + }; + + // Insert the pins into the sheet + for( const auto& pin : pin_defs ) + { + m_sheet.AddPin( + std::make_unique( &m_sheet, pin.m_pos, pin.m_pin_name ).release() ); + } + + SCH_SHEET_PINS& pins = m_sheet.GetPins(); + + // make sure the pins made it in + BOOST_CHECK_EQUAL( pins.size(), pin_defs.size() ); + + // Check that the EndPoint getter gets the right things + { + std::vector expectedDangling; + + // Construct expected from the pin, not defs, as we need the pin address + for( auto& pin : pins ) + { + expectedDangling.emplace_back( + DANGLING_END_T::SHEET_LABEL_END, &pin, pin.GetPosition(), &pin ); + } + + std::vector dangling; + m_sheet.GetEndPoints( dangling ); + + BOOST_CHECK_EQUAL_COLLECTIONS( dangling.begin(), dangling.end(), expectedDangling.begin(), + expectedDangling.end() ); + } + + // And check the connection getter + { + std::vector expectedConnections; + + // we want to see every pin that we just added + for( const auto& pin : pin_defs ) + { + expectedConnections.push_back( pin.m_pos ); + } + + std::vector connections; + m_sheet.GetConnectionPoints( connections ); + + BOOST_CHECK_EQUAL_COLLECTIONS( connections.begin(), connections.end(), + expectedConnections.begin(), expectedConnections.end() ); + } +} + + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/qa/eeschema/test_sch_sheet_path.cpp b/qa/eeschema/test_sch_sheet_path.cpp new file mode 100644 index 0000000000..fa2ecc7bf9 --- /dev/null +++ b/qa/eeschema/test_sch_sheet_path.cpp @@ -0,0 +1,137 @@ +/* + * 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 SCH_SHEET_PATH + */ + +#include + +// Code under test +#include + +#include "timestamp_test_utils.h" + +#include + +#include + +class TEST_SCH_SHEET_PATH_FIXTURE +{ +public: + TEST_SCH_SHEET_PATH_FIXTURE() + { + for( unsigned i = 0; i < 4; ++i ) + { + m_sheets.emplace_back( wxPoint( i, i ) ); + + std::ostringstream ss; + ss << "Sheet" << i; + m_sheets[i].SetName( ss.str() ); + } + + // 0->1->2 + m_linear.push_back( &m_sheets[0] ); + m_linear.push_back( &m_sheets[1] ); + m_linear.push_back( &m_sheets[2] ); + } + + SCH_SHEET_PATH m_empty_path; + + /** + * We look at sheet 2 in the hierarchy: + * Sheets: 0 -> 1 -> 2 + */ + SCH_SHEET_PATH m_linear; + + /// handy store of SCH_SHEET objects + std::vector m_sheets; +}; + + +/** + * Declare the test suite + */ +BOOST_FIXTURE_TEST_SUITE( SchSheetPath, TEST_SCH_SHEET_PATH_FIXTURE ) + + +/** + * Check properties of an empty SCH_SHEET_PATH + */ +BOOST_AUTO_TEST_CASE( Empty ) +{ + BOOST_CHECK_EQUAL( m_empty_path.size(), 0 ); + + BOOST_CHECK_THROW( m_empty_path.at( 0 ), std::out_of_range ); + + BOOST_CHECK_EQUAL( m_empty_path.GetPageNumber(), 0 ); + + // These accessors return nullptr when empty (i.e. they don't crash) + BOOST_CHECK_EQUAL( m_empty_path.Last(), nullptr ); + BOOST_CHECK_EQUAL( m_empty_path.LastScreen(), nullptr ); + BOOST_CHECK_EQUAL( m_empty_path.LastDrawList(), nullptr ); + BOOST_CHECK_EQUAL( m_empty_path.FirstDrawList(), nullptr ); + + BOOST_CHECK_EQUAL( m_empty_path.Path(), "/" ); + BOOST_CHECK_EQUAL( m_empty_path.PathHumanReadable(), "/" ); +} + + +/** + * Check properties of a non-empty SCH_SHEET_PATH + */ +BOOST_AUTO_TEST_CASE( NonEmpty ) +{ + BOOST_CHECK_EQUAL( m_linear.size(), 3 ); + + BOOST_CHECK_EQUAL( m_linear.at( 0 ), &m_sheets[0] ); + BOOST_CHECK_EQUAL( m_linear.at( 1 ), &m_sheets[1] ); + BOOST_CHECK_EQUAL( m_linear.at( 2 ), &m_sheets[2] ); + + BOOST_CHECK_EQUAL( m_linear.GetPageNumber(), 0 ); + + BOOST_CHECK_EQUAL( m_linear.Last(), &m_sheets[2] ); + BOOST_CHECK_EQUAL( m_linear.LastScreen(), nullptr ); + BOOST_CHECK_EQUAL( m_linear.LastDrawList(), nullptr ); + BOOST_CHECK_EQUAL( m_linear.FirstDrawList(), nullptr ); + + // don't know what the timestamps will be, but we know the format: /<8 chars>/<8 chars>/ + BOOST_CHECK_PREDICATE( + KI_TEST::IsTimestampStringWithLevels, ( m_linear.Path().ToStdString() )( 2 ) ); + + // Sheet0 is the root sheet and isn't in the path + BOOST_CHECK_EQUAL( m_linear.PathHumanReadable(), "/Sheet1/Sheet2/" ); +} + + +BOOST_AUTO_TEST_CASE( Compare ) +{ + SCH_SHEET_PATH otherEmpty; + + BOOST_CHECK( m_empty_path == otherEmpty ); + + BOOST_CHECK( m_empty_path != m_linear ); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/qa/eeschema/timestamp_test_utils.cpp b/qa/eeschema/timestamp_test_utils.cpp new file mode 100644 index 0000000000..05f16d7250 --- /dev/null +++ b/qa/eeschema/timestamp_test_utils.cpp @@ -0,0 +1,82 @@ +/* + * 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 + */ + +#include "timestamp_test_utils.h" + +#include + +namespace KI_TEST +{ + +bool EndsInTimestamp( const std::string& aStr ) +{ + if( aStr.size() < 8 ) + { + BOOST_TEST_INFO( "Too short to be timestamp: " << aStr.size() ); + return false; + } + + return IsTimeStampish( aStr.end() - 8, aStr.end() ); +} + +bool IsTimestampStringWithLevels( const std::string& aStr, unsigned aLevels ) +{ + const unsigned tsLen = 8; + const unsigned levelLen = tsLen + 1; // add the / + + if( aStr.size() != aLevels * levelLen + 1 ) + { + BOOST_TEST_INFO( "String is the wrong length for " << aLevels << " levels." ); + return false; + } + + if( aStr[0] != '/' ) + { + BOOST_TEST_INFO( "Doesn't start with '/'" ); + return false; + } + + auto tsBegin = aStr.begin() + 1; + + for( unsigned i = 0; i < aLevels; i++ ) + { + if( !IsTimeStampish( tsBegin, tsBegin + tsLen ) ) + { + BOOST_TEST_INFO( "Not a timeStamp at level " + << i << ": " << std::string( tsBegin, tsBegin + tsLen ) ); + return false; + } + + if( *( tsBegin + tsLen ) != '/' ) + { + BOOST_TEST_INFO( "level doesn't end in '/'" ); + return false; + } + + tsBegin += levelLen; + } + + return true; +} + +} // namespace KI_TEST diff --git a/qa/eeschema/timestamp_test_utils.h b/qa/eeschema/timestamp_test_utils.h new file mode 100644 index 0000000000..519e4fd723 --- /dev/null +++ b/qa/eeschema/timestamp_test_utils.h @@ -0,0 +1,82 @@ +/* + * 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 + */ + +#ifndef QA_EESCHEMA_TIMESTAMP_TEST_UTILS__H +#define QA_EESCHEMA_TIMESTAMP_TEST_UTILS__H + +#include +#include + +/** + * @file + * Test utilities for timestamps + */ + +namespace KI_TEST +{ + +/** + * Predicate for checking a timestamp character + * @param aChr the character + * @return true if it's a valid timestamp char (0-9, A-F) + */ +inline bool IsTimeStampChar( char aChr ) +{ + return ( aChr >= 'A' && aChr <= 'F' ) || ( aChr >= '0' && aChr <= '9' ); +} + +/** + * Check if the string between the iterators looks like a timestamp (i.e. 8 hex digits) + */ +template +bool IsTimeStampish( const T& aBegin, const T& aEnd ) +{ + // Wrong length + if( aEnd != aBegin + 8 ) + return false; + + // Check all chars + return std::all_of( aBegin, aEnd, IsTimeStampChar ); +} + +/** + * Predicate to check if a string look like it ends in a timestamp + * @param aStr the string to check + * @return true if it does + */ +bool EndsInTimestamp( const std::string& aStr ); + +/** + * Predicate to check a string is a timestmap path format + * + * Eg. levels=2: /1234ABCD/9878DEFC/ + * + * @param aStr candidate string + * @param levels expected levels + * @return true if format matches + */ +bool IsTimestampStringWithLevels( const std::string& aStr, unsigned aLevels ); + +} // namespace KI_TEST + +#endif // QA_EESCHEMA_TIMESTAMP_TEST_UTILS__H \ No newline at end of file diff --git a/qa/unit_test_utils/CMakeLists.txt b/qa/unit_test_utils/CMakeLists.txt index 806aa59d41..80ca2f9dbd 100644 --- a/qa/unit_test_utils/CMakeLists.txt +++ b/qa/unit_test_utils/CMakeLists.txt @@ -29,6 +29,7 @@ find_package( Boost COMPONENTS unit_test_framework filesystem system REQUIRED ) set( SRCS unit_test_utils.cpp + wx_assert.cpp ) add_library( unit_test_utils STATIC ${SRCS} ) @@ -37,6 +38,7 @@ target_link_libraries( unit_test_utils PUBLIC ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} + ${wxWidgets_LIBRARIES} ) target_include_directories( unit_test_utils PUBLIC diff --git a/qa/unit_test_utils/include/unit_test_utils/unit_test_utils.h b/qa/unit_test_utils/include/unit_test_utils/unit_test_utils.h index 87c3f90733..1335197b00 100644 --- a/qa/unit_test_utils/include/unit_test_utils/unit_test_utils.h +++ b/qa/unit_test_utils/include/unit_test_utils/unit_test_utils.h @@ -27,9 +27,12 @@ #include #include +#include + #include #include +#include /** * If HAVE_EXPECTED_FAILURES is defined, this means that * boost::unit_test::expected_failures is available. @@ -130,6 +133,43 @@ BOOST_TEST_PRINT_NAMESPACE_CLOSE #endif + +BOOST_TEST_PRINT_NAMESPACE_OPEN +{ + +/** + * Boost print helper for generic vectors + */ +template +struct print_log_value> +{ + inline void operator()( std::ostream& os, std::vector const& aVec ) + { + os << "std::vector size " << aVec.size() << "["; + + for( const auto& i : aVec ) + { + os << "\n "; + print_log_value()( os, i ); + } + + os << "]"; + } +}; + +/** + * Boost print helper for wxPoint. Note operator<< for this type doesn't + * exist in non-DEBUG builds. + */ +template <> +struct print_log_value +{ + void operator()( std::ostream& os, wxPoint const& aVec ); +}; +} +BOOST_TEST_PRINT_NAMESPACE_CLOSE + + namespace KI_TEST { @@ -231,6 +271,19 @@ void CheckUnorderedMatches( } +/** + * Predicate to check a collection has no duplicate elements + */ +template +bool CollectionHasNoDuplicates( const T& aCollection ) +{ + T sorted = aCollection; + std::sort( sorted.begin(), sorted.end() ); + + return std::adjacent_find( sorted.begin(), sorted.end() ) == sorted.end(); +} + + /** * Get a simple string "aIn -> aOut". * @@ -251,6 +304,18 @@ std::string InOutString( const IN& aIn, const OUT& aOut ) return ss.str(); } +/** + * A test macro to check a wxASSERT is thrown. + * + * This only happens in DEBUG builds, so prevent test failures in Release builds + * by using this macro. + */ +#ifdef DEBUG +#define CHECK_WX_ASSERT( STATEMENT ) BOOST_CHECK_THROW( STATEMENT, KI_TEST::WX_ASSERT_ERROR ); +#else +#define CHECK_WX_ASSERT( STATEMENT ) +#endif + } // namespace KI_TEST #endif // UNIT_TEST_UTILS__H \ No newline at end of file diff --git a/qa/unit_test_utils/include/unit_test_utils/wx_assert.h b/qa/unit_test_utils/include/unit_test_utils/wx_assert.h new file mode 100644 index 0000000000..f25f5b3955 --- /dev/null +++ b/qa/unit_test_utils/include/unit_test_utils/wx_assert.h @@ -0,0 +1,67 @@ +/* + * 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 + */ + +#ifndef UNIT_TEST_UTILS_WX_ASSERT__H +#define UNIT_TEST_UTILS_WX_ASSERT__H + +#include + +#include +#include + +namespace KI_TEST +{ + +/** + * An exception class to represent a WX assertion. + * + * In normal programs, this is popped as a dialog, but in unit tests, it + * prints a fairly unhelpful stack trace and otherwise doesn't inform the + * test runner. + * + * We want to raise a formal exception to allow us to catch it with + * things like BOOST_CHECK_THROW if expected, or for the test case to fail if + * not expected. + */ +class WX_ASSERT_ERROR : public std::exception +{ +public: + WX_ASSERT_ERROR( const wxString& aFile, int aLine, const wxString& aFunc, const wxString& aCond, + const wxString& aMsg ); + + const char* what() const noexcept override; + + // Public, so catchers can have a look (though be careful as the function + // names can change over time!) + std::string m_file; + int m_line; + std::string m_func; + std::string m_cond; + std::string m_msg; + + std::string m_format_msg; +}; + +} // namespace KI_TEST + +#endif // UNIT_TEST_UTILS_WX_ASSERT__H \ No newline at end of file diff --git a/qa/unit_test_utils/unit_test_utils.cpp b/qa/unit_test_utils/unit_test_utils.cpp index e96ba6c09f..71550e564f 100644 --- a/qa/unit_test_utils/unit_test_utils.cpp +++ b/qa/unit_test_utils/unit_test_utils.cpp @@ -21,6 +21,15 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -/* - * Nothing here yet, but CMake requires *something*. - */ \ No newline at end of file +#include + +BOOST_TEST_PRINT_NAMESPACE_OPEN +{ + +void print_log_value::operator()( std::ostream& os, wxPoint const& aPt ) +{ + os << "WXPOINT[ x=\"" << aPt.x << "\" y=\"" << aPt.y << "\" ]"; +} + +} +BOOST_TEST_PRINT_NAMESPACE_CLOSE \ No newline at end of file diff --git a/qa/unit_test_utils/wx_assert.cpp b/qa/unit_test_utils/wx_assert.cpp new file mode 100644 index 0000000000..a34141c8a0 --- /dev/null +++ b/qa/unit_test_utils/wx_assert.cpp @@ -0,0 +1,52 @@ +/* + * 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 + */ + +#include + +#include + +namespace KI_TEST +{ +WX_ASSERT_ERROR::WX_ASSERT_ERROR( const wxString& aFile, int aLine, const wxString& aFunc, + const wxString& aCond, const wxString& aMsg ) + : m_file( aFile ), m_line( aLine ), m_func( aFunc ), m_cond( aCond ), m_msg( aMsg ) +{ + std::ostringstream ss; + + ss << "WX assertion in " << m_file << ":" << m_line << "\n" + << "in function " << m_func << "\n" + << "failed condition: " << m_cond; + + if( m_msg.size() ) + ss << "\n" + << "with message: " << m_msg; + + m_format_msg = ss.str(); +} + +const char* WX_ASSERT_ERROR::what() const noexcept +{ + return m_format_msg.c_str(); +} + +} // namespace KI_TEST \ No newline at end of file