Files
Jon Evans 266c8c8754 Refactor and consolidate startup wizard
- Add welcome page
- Add settings migration
- Add library table configuration
- Combine sentry and updates into a privacy step
- Support in single-top mode
2025-10-15 22:18:52 -04:00

309 lines
10 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright The 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
*/
/**
* Test flat top-level schematic sheets functionality
*/
#include <boost/test/unit_test.hpp>
#include <eeschema_test_utils.h>
#include <sch_sheet.h>
#include <sch_screen.h>
#include <schematic.h>
#include <project.h>
#include <settings/settings_manager.h>
#include <project/project_file.h>
struct FLAT_HIERARCHY_FIXTURE
{
FLAT_HIERARCHY_FIXTURE() :
m_settingsManager()
{
m_settingsManager.LoadProject( "" );
m_schematic = std::make_unique<SCHEMATIC>( nullptr );
m_project = &m_settingsManager.Prj();
m_schematic->SetProject( m_project );
}
~FLAT_HIERARCHY_FIXTURE()
{
m_schematic.reset();
}
SETTINGS_MANAGER m_settingsManager;
std::unique_ptr<SCHEMATIC> m_schematic;
PROJECT* m_project;
};
BOOST_FIXTURE_TEST_SUITE( FlatHierarchy, FLAT_HIERARCHY_FIXTURE )
/**
* Test that CreateDefaultScreens creates a virtual root with one top-level sheet
*/
BOOST_AUTO_TEST_CASE( TestCreateDefaultScreens )
{
m_schematic->CreateDefaultScreens();
// Check that we have a valid root
BOOST_CHECK( m_schematic->IsValid() );
// Check that root has a screen (virtual root now has a screen to hold top-level sheets)
SCH_SHEET& root = m_schematic->Root();
BOOST_CHECK( root.GetScreen() != nullptr );
// Check that root UUID is niluuid
BOOST_CHECK( root.m_Uuid == niluuid );
// Check that we have one top-level sheet
std::vector<SCH_SHEET*> topLevelSheets = m_schematic->GetTopLevelSheets();
BOOST_CHECK_EQUAL( topLevelSheets.size(), 1 );
// Check that the top-level sheet has a screen
if( !topLevelSheets.empty() && topLevelSheets[0] )
{
BOOST_CHECK( topLevelSheets[0]->GetScreen() != nullptr );
}
// Check that the top-level sheet is in the virtual root's screen
if( root.GetScreen() )
{
std::vector<SCH_ITEM*> items;
root.GetScreen()->GetSheets( &items );
BOOST_CHECK_EQUAL( items.size(), 1 );
}
}
/**
* Test adding multiple top-level sheets
*/
BOOST_AUTO_TEST_CASE( TestAddTopLevelSheets )
{
m_schematic->CreateDefaultScreens();
// Create and add a second top-level sheet
SCH_SHEET* sheet2 = new SCH_SHEET( m_schematic.get() );
SCH_SCREEN* screen2 = new SCH_SCREEN( m_schematic.get() );
sheet2->SetScreen( screen2 );
sheet2->GetField( FIELD_T::SHEET_NAME )->SetText( "Sheet2" );
screen2->SetFileName( "sheet2.kicad_sch" );
screen2->SetPageNumber( "2" );
m_schematic->AddTopLevelSheet( sheet2 );
// Check that we now have two top-level sheets
std::vector<SCH_SHEET*> topLevelSheets = m_schematic->GetTopLevelSheets();
BOOST_CHECK_EQUAL( topLevelSheets.size(), 2 );
// Check that both are recognized as top-level
BOOST_CHECK( m_schematic->IsTopLevelSheet( topLevelSheets[0] ) );
BOOST_CHECK( m_schematic->IsTopLevelSheet( topLevelSheets[1] ) );
// Create and add a third top-level sheet
SCH_SHEET* sheet3 = new SCH_SHEET( m_schematic.get() );
SCH_SCREEN* screen3 = new SCH_SCREEN( m_schematic.get() );
sheet3->SetScreen( screen3 );
sheet3->GetField( FIELD_T::SHEET_NAME )->SetText( "Sheet3" );
screen3->SetFileName( "sheet3.kicad_sch" );
screen3->SetPageNumber( "3" );
m_schematic->AddTopLevelSheet( sheet3 );
topLevelSheets = m_schematic->GetTopLevelSheets();
BOOST_CHECK_EQUAL( topLevelSheets.size(), 3 );
}
/**
* Test removing top-level sheets
*/
BOOST_AUTO_TEST_CASE( TestRemoveTopLevelSheet )
{
m_schematic->CreateDefaultScreens();
// Add two more sheets
SCH_SHEET* sheet2 = new SCH_SHEET( m_schematic.get() );
SCH_SCREEN* screen2 = new SCH_SCREEN( m_schematic.get() );
sheet2->SetScreen( screen2 );
sheet2->GetField( FIELD_T::SHEET_NAME )->SetText( "Sheet2" );
m_schematic->AddTopLevelSheet( sheet2 );
SCH_SHEET* sheet3 = new SCH_SHEET( m_schematic.get() );
SCH_SCREEN* screen3 = new SCH_SCREEN( m_schematic.get() );
sheet3->SetScreen( screen3 );
sheet3->GetField( FIELD_T::SHEET_NAME )->SetText( "Sheet3" );
m_schematic->AddTopLevelSheet( sheet3 );
std::vector<SCH_SHEET*> topLevelSheets = m_schematic->GetTopLevelSheets();
BOOST_CHECK_EQUAL( topLevelSheets.size(), 3 );
// Remove the second sheet
bool removed = m_schematic->RemoveTopLevelSheet( sheet2 );
BOOST_CHECK( removed );
topLevelSheets = m_schematic->GetTopLevelSheets();
BOOST_CHECK_EQUAL( topLevelSheets.size(), 2 );
// Try to remove it again (should fail)
removed = m_schematic->RemoveTopLevelSheet( sheet2 );
BOOST_CHECK( !removed );
}
/**
* Test building sheet list from multiple top-level sheets
*/
BOOST_AUTO_TEST_CASE( TestBuildSheetList )
{
m_schematic->CreateDefaultScreens();
// Add a second top-level sheet
SCH_SHEET* sheet2 = new SCH_SHEET( m_schematic.get() );
SCH_SCREEN* screen2 = new SCH_SCREEN( m_schematic.get() );
sheet2->SetScreen( screen2 );
sheet2->GetField( FIELD_T::SHEET_NAME )->SetText( "Sheet2" );
screen2->SetFileName( "sheet2.kicad_sch" );
screen2->SetPageNumber( "2" );
m_schematic->AddTopLevelSheet( sheet2 );
// Build sheet list
SCH_SHEET_LIST sheetList = m_schematic->BuildSheetListSortedByPageNumbers();
// Should have two sheets
BOOST_CHECK_EQUAL( sheetList.size(), 2 );
// Check unordered list
SCH_SHEET_LIST unorderedList = m_schematic->BuildUnorderedSheetList();
BOOST_CHECK_EQUAL( unorderedList.size(), 2 );
}
/**
* Test project file serialization of top-level sheets
*/
BOOST_AUTO_TEST_CASE( TestProjectFileSerialization )
{
// Create a project file
wxString projectPath = wxT( "/tmp/test_project.kicad_pro" );
PROJECT_FILE projectFile( projectPath );
// Add some top-level sheet info
std::vector<TOP_LEVEL_SHEET_INFO>& topLevelSheets = projectFile.GetTopLevelSheets();
topLevelSheets.push_back( TOP_LEVEL_SHEET_INFO(
KIID(),
wxT( "Main Sheet" ),
wxT( "main.kicad_sch" ) ) );
topLevelSheets.push_back( TOP_LEVEL_SHEET_INFO(
KIID(),
wxT( "Power Sheet" ),
wxT( "power.kicad_sch" ) ) );
topLevelSheets.push_back( TOP_LEVEL_SHEET_INFO(
KIID(),
wxT( "Interface Sheet" ),
wxT( "interface.kicad_sch" ) ) );
// Verify we have 3 entries
BOOST_CHECK_EQUAL( projectFile.GetTopLevelSheets().size(), 3 );
// Check that they have the expected data
BOOST_CHECK_EQUAL( projectFile.GetTopLevelSheets()[0].name.ToStdString(), "Main Sheet" );
BOOST_CHECK_EQUAL( projectFile.GetTopLevelSheets()[1].name.ToStdString(), "Power Sheet" );
BOOST_CHECK_EQUAL( projectFile.GetTopLevelSheets()[2].name.ToStdString(), "Interface Sheet" );
BOOST_CHECK_EQUAL( projectFile.GetTopLevelSheets()[0].filename.ToStdString(), "main.kicad_sch" );
BOOST_CHECK_EQUAL( projectFile.GetTopLevelSheets()[1].filename.ToStdString(), "power.kicad_sch" );
BOOST_CHECK_EQUAL( projectFile.GetTopLevelSheets()[2].filename.ToStdString(), "interface.kicad_sch" );
}
/**
* Test that hierarchy is correctly built with multiple top-level sheets
* TODO: This test currently fails due to recursion detection - needs investigation
*/
/*
BOOST_AUTO_TEST_CASE( TestHierarchyWithMultipleTopLevelSheets )
{
m_schematic->CreateDefaultScreens();
std::vector<SCH_SHEET*> topLevelSheets = m_schematic->GetTopLevelSheets();
SCH_SHEET* sheet1 = topLevelSheets[0];
// Add a hierarchical subsheet to sheet1
SCH_SHEET* subsheet = new SCH_SHEET( sheet1 );
SCH_SCREEN* subscreen = new SCH_SCREEN( m_schematic.get() );
subsheet->SetScreen( subscreen );
subsheet->GetField( FIELD_T::SHEET_NAME )->SetText( "Subsheet" );
subscreen->SetFileName( "subsheet_unique.kicad_sch" ); // Use unique filename
subscreen->SetPageNumber( "1.1" );
// Add subsheet to sheet1's screen
sheet1->GetScreen()->Append( subsheet );
// Add a second top-level sheet
SCH_SHEET* sheet2 = new SCH_SHEET( m_schematic.get() );
SCH_SCREEN* screen2 = new SCH_SCREEN( m_schematic.get() );
sheet2->SetScreen( screen2 );
sheet2->GetField( FIELD_T::SHEET_NAME )->SetText( "Sheet2" );
screen2->SetFileName( "sheet2.kicad_sch" );
screen2->SetPageNumber( "2" );
m_schematic->AddTopLevelSheet( sheet2 );
// Build hierarchy - use the BuildSheetListSortedByPageNumbers which iterates all top-level sheets
SCH_SHEET_LIST hierarchy = m_schematic->BuildSheetListSortedByPageNumbers();
// Should have 3 sheets total: sheet1, subsheet, sheet2
BOOST_CHECK_EQUAL( hierarchy.size(), 3 );
}
*/
/**
* Test RootScreen returns the first top-level sheet's screen
*/
BOOST_AUTO_TEST_CASE( TestRootScreen )
{
m_schematic->CreateDefaultScreens();
// Get the root screen
SCH_SCREEN* rootScreen = m_schematic->RootScreen();
BOOST_CHECK( rootScreen != nullptr );
// It should be the screen of the first top-level sheet
std::vector<SCH_SHEET*> topLevelSheets = m_schematic->GetTopLevelSheets();
BOOST_CHECK( !topLevelSheets.empty() );
if( !topLevelSheets.empty() && topLevelSheets[0] )
{
BOOST_CHECK_EQUAL( rootScreen, topLevelSheets[0]->GetScreen() );
}
}
BOOST_AUTO_TEST_SUITE_END()