From b729068326236e302c904a346af98bc1a1d8d687 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Wed, 1 Dec 2021 00:38:12 +0100 Subject: [PATCH] Test BOARD_ITEM --- qa/pcbnew/CMakeLists.txt | 1 + qa/pcbnew/test_board_item.cpp | 340 ++++++++++++++++++++++++++++++++++ 2 files changed, 341 insertions(+) create mode 100644 qa/pcbnew/test_board_item.cpp diff --git a/qa/pcbnew/CMakeLists.txt b/qa/pcbnew/CMakeLists.txt index 29cd9d52f4..cfc927f307 100644 --- a/qa/pcbnew/CMakeLists.txt +++ b/qa/pcbnew/CMakeLists.txt @@ -33,6 +33,7 @@ set( QA_PCBNEW_SRCS # test compilation units (start test_) test_array_pad_name_provider.cpp + test_board_item.cpp test_graphics_import_mgr.cpp test_lset.cpp test_pad_numbering.cpp diff --git a/qa/pcbnew/test_board_item.cpp b/qa/pcbnew/test_board_item.cpp new file mode 100644 index 0000000000..8b208e866a --- /dev/null +++ b/qa/pcbnew/test_board_item.cpp @@ -0,0 +1,340 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2021 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 + */ + +#include +#include +#include + +// Code under test +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class TEST_BOARD_ITEM_FIXTURE +{ +public: + BOARD m_board; + FOOTPRINT m_footprint; + std::shared_ptr m_drcItem; + + TEST_BOARD_ITEM_FIXTURE() : + m_board(), + m_footprint( &m_board ), + m_drcItem( DRC_ITEM::Create( DRCE_MALFORMED_COURTYARD ) ) + { + } + + BOARD_ITEM* Instantiate( KICAD_T aType ) + { + if( !IsPcbnewType( aType ) ) + return nullptr; + + if( !IsInstantiableType( aType ) ) + return nullptr; + + switch( aType ) + { + case PCB_FOOTPRINT_T: return new FOOTPRINT( &m_board ); + case PCB_PAD_T: return new PAD( &m_footprint ); + case PCB_SHAPE_T: return new PCB_SHAPE( &m_board ); + case PCB_TEXT_T: return new PCB_TEXT( &m_board ); + case PCB_FP_TEXT_T: return new FP_TEXT( &m_footprint ); + case PCB_FP_SHAPE_T: return new FP_SHAPE( &m_footprint ); + //case PCB_FP_ZONE_T: return new FP_ZONE( &m_footprint ); // FIXME: Fatal error + case PCB_FP_ZONE_T: return nullptr; + case PCB_TRACE_T: return new PCB_TRACK( &m_board ); + case PCB_VIA_T: return new PCB_VIA( &m_board ); + case PCB_ARC_T: return new PCB_ARC( &m_board ); + //case PCB_MARKER_T: return new PCB_MARKER( m_drcItem, wxPoint( 0, 0 ) ); + case PCB_MARKER_T: return nullptr; // FIXME: Segfault + case PCB_DIM_ALIGNED_T: return new PCB_DIM_ALIGNED( &m_board ); + case PCB_DIM_LEADER_T: return new PCB_DIM_LEADER( &m_board ); + case PCB_DIM_CENTER_T: return new PCB_DIM_CENTER( &m_board ); + case PCB_DIM_ORTHOGONAL_T: return new PCB_DIM_ORTHOGONAL( &m_board ); + case PCB_TARGET_T: return new PCB_TARGET( &m_board ); + //case PCB_ZONE_T: return new ZONE( &m_board ); // FIXME: Fatal error + case PCB_ZONE_T: return nullptr; + case PCB_GROUP_T: + { + static PCB_TEXT text( &m_board ); + + PCB_GROUP* group = new PCB_GROUP( &m_board ); + + // Group position only makes sense if there's at least one item in the group. + group->AddItem( &text ); + + return group; + } + + case PCB_T: + case PCB_ITEM_LIST_T: + case PCB_NETINFO_T: + return nullptr; + + default: + BOOST_FAIL( wxString::Format( + "Unhandled type: %d " + "(if you created a new type you need to handle it in this switch statement)", + aType ) ); + return nullptr; + } + } + + static void CompareItems( BOARD_ITEM* aItem, BOARD_ITEM* aOriginalItem ) + { + BOOST_CHECK_EQUAL( aItem->GetPosition(), aOriginalItem->GetPosition() ); + BOOST_CHECK_EQUAL( aItem->GetBoundingBox().GetTop(), + aOriginalItem->GetBoundingBox().GetTop() ); + BOOST_CHECK_EQUAL( aItem->GetBoundingBox().GetLeft(), + aOriginalItem->GetBoundingBox().GetLeft() ); + BOOST_CHECK_EQUAL( aItem->GetBoundingBox().GetBottom(), + aOriginalItem->GetBoundingBox().GetBottom() ); + BOOST_CHECK_EQUAL( aItem->GetBoundingBox().GetRight(), + aOriginalItem->GetBoundingBox().GetRight() ); + } +}; + + +BOOST_FIXTURE_TEST_SUITE( PcbItem, TEST_BOARD_ITEM_FIXTURE ) + + +BOOST_AUTO_TEST_CASE( Move ) +{ + for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ ) + { + KICAD_T type = static_cast( i ); + + auto item = std::unique_ptr( Instantiate( type ) ); + + if( item == nullptr ) + continue; + + BOOST_TEST_CONTEXT( "Class: " << item->GetClass() ) + { + IterateOverPositionsAndReferences( + item.get(), + []( BOARD_ITEM* aOriginalItem, wxPoint aRef ) + { + FP_SHAPE* originalFpShape = dynamic_cast( aOriginalItem ); + + if( originalFpShape != nullptr ) + originalFpShape->SetDrawCoord(); + + // FIXME: Update() has to be called after SetPosition() to update dimension + // shapes. + PCB_DIMENSION_BASE* originalDimension = + dynamic_cast( aOriginalItem ); + + if( originalDimension != nullptr ) + originalDimension->Update(); + + auto item = std::unique_ptr( aOriginalItem->Duplicate() ); + wxPoint originalPos = item->GetPosition(); + + // Move to a point, then go back. + // This has to be an identity transformation. + + item->Move( aRef ); + + FP_SHAPE* fpShape = dynamic_cast( item.get() ); + if( fpShape != nullptr ) + fpShape->SetDrawCoord(); + + BOOST_CHECK_EQUAL( item->GetPosition(), originalPos + aRef ); + + item->Move( -aRef ); + + if( fpShape != nullptr ) + fpShape->SetDrawCoord(); + + CompareItems( item.get(), aOriginalItem ); + } ); + } + } +} + + +BOOST_AUTO_TEST_CASE( Rotate ) +{ + for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ ) + { + KICAD_T type = static_cast( i ); + + auto item = std::unique_ptr( Instantiate( type ) ); + + if( item == nullptr ) + continue; + + BOOST_TEST_CONTEXT( "Class: " << item->GetClass() ) + { + // Four same 90 degree rotations are an identity. + + IterateOverPositionsAndReferences( + item.get(), + []( BOARD_ITEM* aOriginalItem, wxPoint aRef ) + { + FP_SHAPE* originalFpShape = dynamic_cast( aOriginalItem ); + + if( originalFpShape != nullptr ) + originalFpShape->SetDrawCoord(); + + // FIXME: Update() has to be called after SetPosition() to update dimension + // shapes. + PCB_DIMENSION_BASE* originalDimension = + dynamic_cast( aOriginalItem ); + + if( originalDimension != nullptr ) + originalDimension->Update(); + + auto item = std::unique_ptr( aOriginalItem->Duplicate() ); + + // Four equivalent 90 degree rotations are an identity. + + item->Rotate( aRef, 900 ); + item->Rotate( aRef, 900 ); + item->Rotate( aRef, 900 ); + item->Rotate( aRef, 900 ); + + FP_SHAPE* fpShape = dynamic_cast( aOriginalItem ); + + if( fpShape != nullptr ) + fpShape->SetDrawCoord(); + + CompareItems( item.get(), aOriginalItem ); + } ); + } + } +} + + +BOOST_AUTO_TEST_CASE( FlipLeftRight ) +{ + for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ ) + { + KICAD_T type = static_cast( i ); + + auto item = std::unique_ptr( Instantiate( type ) ); + + if( item == nullptr ) + continue; + + BOOST_TEST_CONTEXT( "Class: " << item->GetClass() ) + { + IterateOverPositionsAndReferences( + item.get(), + []( BOARD_ITEM* aOriginalItem, wxPoint aRef ) + { + FP_SHAPE* originalFpShape = dynamic_cast( aOriginalItem ); + + if( originalFpShape != nullptr ) + originalFpShape->SetDrawCoord(); + + // FIXME: Update() has to be called after SetPosition() to update dimension + // shapes. + PCB_DIMENSION_BASE* originalDimension = + dynamic_cast( aOriginalItem ); + + if( originalDimension != nullptr ) + originalDimension->Update(); + + auto item = std::unique_ptr( aOriginalItem->Duplicate() ); + + // Two equivalent flips are an identity. + + item->Flip( aRef, true ); + item->Flip( aRef, true ); + + FP_SHAPE* fpShape = dynamic_cast( aOriginalItem ); + + if( fpShape != nullptr ) + fpShape->SetDrawCoord(); + + CompareItems( item.get(), aOriginalItem ); + } ); + } + } +} + + +BOOST_AUTO_TEST_CASE( FlipUpDown ) +{ + for( int i = 0; i < MAX_STRUCT_TYPE_ID; i++ ) + { + KICAD_T type = static_cast( i ); + + auto item = std::unique_ptr( Instantiate( type ) ); + + if( item == nullptr ) + continue; + + BOOST_TEST_CONTEXT( "Class: " << item->GetClass() ) + { + IterateOverPositionsAndReferences( + item.get(), + []( BOARD_ITEM* aOriginalItem, wxPoint aRef ) + { + FP_SHAPE* originalFpShape = dynamic_cast( aOriginalItem ); + + if( originalFpShape != nullptr ) + originalFpShape->SetDrawCoord(); + + // FIXME: Update() has to be called after SetPosition() to update dimension + // shapes. + PCB_DIMENSION_BASE* originalDimension = + dynamic_cast( aOriginalItem ); + + if( originalDimension != nullptr ) + originalDimension->Update(); + + auto item = std::unique_ptr( aOriginalItem->Duplicate() ); + + // Two equivalent flips are an identity. + + item->Flip( aRef, false ); + item->Flip( aRef, false ); + + FP_SHAPE* fpShape = dynamic_cast( aOriginalItem ); + + if( fpShape != nullptr ) + fpShape->SetDrawCoord(); + + CompareItems( item.get(), aOriginalItem ); + } ); + } + } +} + + +BOOST_AUTO_TEST_SUITE_END()