Browse Source

Add some QA tests

Created basic tests for:
- Notification Manager
- Clipboard
- File history
- Filename Resolver
- Hotkey store
- Collector
- Reporters
pull/18/head
Seth Hillbrand 4 months ago
parent
commit
321b5793a2
  1. 7
      common/paths.cpp
  2. 8
      include/paths.h
  3. 8
      qa/tests/common/CMakeLists.txt
  4. 374
      qa/tests/common/test_clipboard.cpp
  5. 601
      qa/tests/common/test_collector.cpp
  6. 79
      qa/tests/common/test_hotkey_store.cpp
  7. 65
      qa/tests/common/test_notifications_manager.cpp
  8. 478
      qa/tests/common/test_reporting.cpp

7
common/paths.cpp

@ -30,13 +30,6 @@
#include <macros.h>
#include <wx_filename.h>
// lowercase or pretty case depending on platform
#if defined( __WXMAC__ ) || defined( __WXMSW__ )
#define KICAD_PATH_STR wxT( "KiCad" )
#else
#define KICAD_PATH_STR wxT( "kicad" )
#endif
void PATHS::getUserDocumentPath( wxFileName& aPath )
{

8
include/paths.h

@ -30,6 +30,14 @@
#define UNIX_STRING_DIR_SEP wxT( "/" )
#define WIN_STRING_DIR_SEP wxT( "\\" )
// lowercase or pretty case depending on platform
#if defined( __WXMAC__ ) || defined( __WXMSW__ )
#define KICAD_PATH_STR wxT( "KiCad" )
#else
#define KICAD_PATH_STR wxT( "kicad" )
#endif
/**
* Helper class to centralize the paths used throughout kicad
*/

8
qa/tests/common/CMakeLists.txt

@ -33,6 +33,7 @@ set( QA_COMMON_SRCS
test_array_axis.cpp
test_base_set.cpp
test_bitmap_base.cpp
test_collector.cpp
test_color4d.cpp
test_coroutine.cpp
test_eda_shape.cpp
@ -40,18 +41,21 @@ set( QA_COMMON_SRCS
test_embedded_file_compress.cpp
test_file_history.cpp
test_filename_resolver.cpp
test_hotkey_store.cpp
test_increment.cpp
test_ki_any.cpp
test_lib_table.cpp
test_markup_parser.cpp
test_kicad_string.cpp
test_kicad_stroke_font.cpp
test_kiid.cpp
test_layer_ids.cpp
test_layer_range.cpp
test_lib_table.cpp
test_lset.cpp
test_markup_parser.cpp
test_notifications_manager.cpp
test_property.cpp
test_property_holder.cpp
test_reporting.cpp
test_refdes_utils.cpp
test_richio.cpp
test_text_attributes.cpp

374
qa/tests/common/test_clipboard.cpp

@ -0,0 +1,374 @@
/*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <boost/test/unit_test.hpp>
#include <clipboard.h>
#include <wx/clipbrd.h>
#include <wx/image.h>
#include <wx/string.h>
#include <wx/filename.h>
#include <wx/mstream.h>
#include <vector>
BOOST_AUTO_TEST_SUITE( ClipboardTests )
BOOST_AUTO_TEST_CASE( SaveClipboard_BasicText )
{
std::string testText = "Basic clipboard test";
bool result = SaveClipboard( testText );
if( result )
{
std::string retrieved = GetClipboardUTF8();
BOOST_CHECK_EQUAL( retrieved, testText );
}
// Note: Test may fail on headless systems where clipboard isn't available
}
BOOST_AUTO_TEST_CASE( SaveClipboard_EmptyString )
{
std::string emptyText = "";
bool result = SaveClipboard( emptyText );
if( result )
{
std::string retrieved = GetClipboardUTF8();
BOOST_CHECK_EQUAL( retrieved, emptyText );
}
}
BOOST_AUTO_TEST_CASE( SaveClipboard_UTF8Characters )
{
std::string utf8Text = "Héllo Wörld! 你好 🚀";
bool result = SaveClipboard( utf8Text );
if( result )
{
std::string retrieved = GetClipboardUTF8();
BOOST_CHECK_EQUAL( retrieved, utf8Text );
}
}
BOOST_AUTO_TEST_CASE( SaveClipboard_LargeText )
{
std::string largeText( 10000, 'A' );
largeText += "END";
bool result = SaveClipboard( largeText );
if( result )
{
std::string retrieved = GetClipboardUTF8();
BOOST_CHECK_EQUAL( retrieved, largeText );
}
}
BOOST_AUTO_TEST_CASE( SaveClipboard_SpecialCharacters )
{
std::string specialText = "Line1\nLine2\tTabbed\r\nWindows newline";
bool result = SaveClipboard( specialText );
if( result )
{
std::string retrieved = GetClipboardUTF8();
BOOST_CHECK_EQUAL( retrieved, specialText );
}
}
BOOST_AUTO_TEST_CASE( GetClipboardUTF8_EmptyClipboard )
{
// Clear clipboard first
if( wxTheClipboard->Open() )
{
wxTheClipboard->Clear();
wxTheClipboard->Close();
}
std::string result = GetClipboardUTF8();
BOOST_CHECK( result.empty() );
}
BOOST_AUTO_TEST_CASE( GetClipboardUTF8_NonTextData )
{
// This test verifies behavior when clipboard contains non-text data
// Implementation depends on system behavior - may return empty string
std::string result = GetClipboardUTF8();
// No specific assertion - just ensure it doesn't crash
BOOST_CHECK( true );
}
BOOST_AUTO_TEST_CASE( SaveTabularData_SimpleGrid )
{
std::vector<std::vector<wxString>> testData = {
{ wxS("A1"), wxS("B1"), wxS("C1") },
{ wxS("A2"), wxS("B2"), wxS("C2") },
{ wxS("A3"), wxS("B3"), wxS("C3") }
};
bool result = SaveTabularDataToClipboard( testData );
if( result )
{
std::vector<std::vector<wxString>> retrieved;
bool parseResult = GetTabularDataFromClipboard( retrieved );
if( parseResult )
{
BOOST_CHECK_EQUAL( retrieved.size(), testData.size() );
for( size_t i = 0; i < testData.size() && i < retrieved.size(); ++i )
{
BOOST_CHECK_EQUAL( retrieved[i].size(), testData[i].size() );
for( size_t j = 0; j < testData[i].size() && j < retrieved[i].size(); ++j )
{
BOOST_CHECK_EQUAL( retrieved[i][j], testData[i][j] );
}
}
}
}
}
BOOST_AUTO_TEST_CASE( SaveTabularData_EmptyGrid )
{
std::vector<std::vector<wxString>> emptyData;
bool result = SaveTabularDataToClipboard( emptyData );
if( result )
{
std::vector<std::vector<wxString>> retrieved;
bool parseResult = GetTabularDataFromClipboard( retrieved );
if( parseResult )
{
BOOST_CHECK( retrieved.empty() );
}
}
}
BOOST_AUTO_TEST_CASE( SaveTabularData_SingleCell )
{
std::vector<std::vector<wxString>> singleCell = {
{ wxS("OnlyCell") }
};
bool result = SaveTabularDataToClipboard( singleCell );
if( result )
{
std::vector<std::vector<wxString>> retrieved;
bool parseResult = GetTabularDataFromClipboard( retrieved );
if( parseResult )
{
BOOST_CHECK_EQUAL( retrieved.size(), 1 );
BOOST_CHECK_EQUAL( retrieved[0].size(), 1 );
BOOST_CHECK_EQUAL( retrieved[0][0], wxS("OnlyCell") );
}
}
}
BOOST_AUTO_TEST_CASE( SaveTabularData_WithCommas )
{
std::vector<std::vector<wxString>> dataWithCommas = {
{ wxS("Value, with comma"), wxS("Normal") },
{ wxS("Another, comma"), wxS("Also normal") }
};
bool result = SaveTabularDataToClipboard( dataWithCommas );
if( result )
{
std::vector<std::vector<wxString>> retrieved;
bool parseResult = GetTabularDataFromClipboard( retrieved );
if( parseResult )
{
BOOST_CHECK_EQUAL( retrieved.size(), dataWithCommas.size() );
for( size_t i = 0; i < dataWithCommas.size() && i < retrieved.size(); ++i )
{
BOOST_CHECK_EQUAL( retrieved[i].size(), dataWithCommas[i].size() );
for( size_t j = 0; j < dataWithCommas[i].size() && j < retrieved[i].size(); ++j )
{
BOOST_CHECK_EQUAL( retrieved[i][j], dataWithCommas[i][j] );
}
}
}
}
}
BOOST_AUTO_TEST_CASE( SaveTabularData_WithQuotes )
{
std::vector<std::vector<wxString>> dataWithQuotes = {
{ wxS("\"Quoted value\""), wxS("Normal") },
{ wxS("Value with \"inner\" quotes"), wxS("Plain") }
};
bool result = SaveTabularDataToClipboard( dataWithQuotes );
if( result )
{
std::vector<std::vector<wxString>> retrieved;
bool parseResult = GetTabularDataFromClipboard( retrieved );
if( parseResult )
{
BOOST_CHECK_EQUAL( retrieved.size(), dataWithQuotes.size() );
// Note: Exact quote handling depends on CSV parser implementation
}
}
}
BOOST_AUTO_TEST_CASE( SaveTabularData_WithNewlines )
{
std::vector<std::vector<wxString>> dataWithNewlines = {
{ wxS("Line1\nLine2"), wxS("Normal") },
{ wxS("Single line"), wxS("Another\nmultiline") }
};
bool result = SaveTabularDataToClipboard( dataWithNewlines );
if( result )
{
std::vector<std::vector<wxString>> retrieved;
bool parseResult = GetTabularDataFromClipboard( retrieved );
if( parseResult )
{
BOOST_CHECK_EQUAL( retrieved.size(), dataWithNewlines.size() );
// Note: Newline handling depends on CSV parser implementation
}
}
}
BOOST_AUTO_TEST_CASE( SaveTabularData_IrregularGrid )
{
std::vector<std::vector<wxString>> irregularData = {
{ wxS("A1"), wxS("B1"), wxS("C1"), wxS("D1") },
{ wxS("A2"), wxS("B2") },
{ wxS("A3"), wxS("B3"), wxS("C3") }
};
bool result = SaveTabularDataToClipboard( irregularData );
if( result )
{
std::vector<std::vector<wxString>> retrieved;
bool parseResult = GetTabularDataFromClipboard( retrieved );
if( parseResult )
{
BOOST_CHECK_EQUAL( retrieved.size(), irregularData.size() );
// Each row should maintain its individual size
for( size_t i = 0; i < irregularData.size() && i < retrieved.size(); ++i )
{
for( size_t j = 0; j < irregularData[i].size() && j < retrieved[i].size(); ++j )
{
BOOST_CHECK_EQUAL( retrieved[i][j], irregularData[i][j] );
}
}
}
}
}
BOOST_AUTO_TEST_CASE( GetTabularDataFromClipboard_InvalidData )
{
// Save non-tabular text to clipboard
std::string invalidText = "This is not tabular data\nJust some text";
SaveClipboard( invalidText );
std::vector<std::vector<wxString>> retrieved;
bool result = GetTabularDataFromClipboard( retrieved );
// Should either parse as single-column data or return appropriate result
// Exact behavior depends on AutoDecodeCSV implementation
BOOST_CHECK( true ); // Test that it doesn't crash
}
BOOST_AUTO_TEST_CASE( GetImageFromClipboard_NoImage )
{
// Clear clipboard
if( wxTheClipboard->Open() )
{
wxTheClipboard->Clear();
wxTheClipboard->Close();
}
std::unique_ptr<wxImage> image = GetImageFromClipboard();
BOOST_CHECK( !image || !image->IsOk() );
}
BOOST_AUTO_TEST_CASE( GetImageFromClipboard_TextInClipboard )
{
// Put text in clipboard
SaveClipboard( "This is text, not an image" );
std::unique_ptr<wxImage> image = GetImageFromClipboard();
BOOST_CHECK( !image || !image->IsOk() );
}
BOOST_AUTO_TEST_CASE( Clipboard_MultipleSaveOperations )
{
// Test multiple sequential save operations
std::vector<std::string> testStrings = {
"First string",
"Second string with 特殊字符",
"Third string\nwith\nnewlines",
""
};
for( const auto& testString : testStrings )
{
bool saved = SaveClipboard( testString );
if( saved )
{
std::string retrieved = GetClipboardUTF8();
BOOST_CHECK_EQUAL( retrieved, testString );
}
}
}
BOOST_AUTO_TEST_CASE( Clipboard_ConcurrentAccess )
{
// Test that clipboard operations are properly synchronized
std::string testText1 = "Concurrent test 1";
std::string testText2 = "Concurrent test 2";
bool result1 = SaveClipboard( testText1 );
bool result2 = SaveClipboard( testText2 );
if( result2 )
{
std::string retrieved = GetClipboardUTF8();
BOOST_CHECK_EQUAL( retrieved, testText2 ); // Should have the last saved value
}
}
BOOST_AUTO_TEST_CASE( Clipboard_FlushBehavior )
{
// Test that Flush() allows data to persist after the application
std::string persistentText = "This should persist after flush";
bool result = SaveClipboard( persistentText );
if( result )
{
// Data should still be available
std::string retrieved = GetClipboardUTF8();
BOOST_CHECK_EQUAL( retrieved, persistentText );
}
}
BOOST_AUTO_TEST_SUITE_END()

601
qa/tests/common/test_collector.cpp

@ -0,0 +1,601 @@
/*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <boost/test/unit_test.hpp>
#include <collector.h>
#include <eda_item.h>
#include <vector>
#include <ostream>
// Mock EDA_ITEM for testing
class TEST_EDA_ITEM : public EDA_ITEM
{
public:
TEST_EDA_ITEM( KICAD_T aType ) : EDA_ITEM( aType ) {}
wxString GetClass() const override { return wxT("TEST_EDA_ITEM"); }
// Minimal required implementations for abstract methods
EDA_ITEM* Clone() const override { return new TEST_EDA_ITEM( Type() ); }
};
// Test collector that implements Inspect
class TEST_COLLECTOR : public COLLECTOR
{
public:
TEST_COLLECTOR() : m_inspectCalls( 0 ), m_shouldCollect( true ) {}
INSPECT_RESULT Inspect( EDA_ITEM* aTestItem, void* aTestData ) override
{
m_inspectCalls++;
if( m_shouldCollect && aTestItem )
{
// Only collect items of specified types if scan types are set
if( !m_scanTypes.empty() )
{
for( KICAD_T type : m_scanTypes )
{
if( aTestItem->Type() == type )
{
Append( aTestItem );
break;
}
}
}
else
{
Append( aTestItem );
}
}
return INSPECT_RESULT::CONTINUE;
}
int GetInspectCalls() const { return m_inspectCalls; }
void SetShouldCollect( bool aShouldCollect ) { m_shouldCollect = aShouldCollect; }
private:
int m_inspectCalls;
bool m_shouldCollect;
};
// Add this for Boost test output of INSPECT_RESULT
std::ostream& operator<<( std::ostream& os, const INSPECT_RESULT& result )
{
switch( result )
{
case INSPECT_RESULT::CONTINUE: os << "CONTINUE"; break;
case INSPECT_RESULT::QUIT: os << "QUIT"; break;
default: os << "UNKNOWN"; break;
}
return os;
}
BOOST_AUTO_TEST_SUITE( CollectorTests )
BOOST_AUTO_TEST_CASE( Constructor_DefaultValues )
{
COLLECTOR collector;
BOOST_CHECK_EQUAL( collector.GetCount(), 0 );
BOOST_CHECK_EQUAL( collector.m_Threshold, 0 );
BOOST_CHECK_EQUAL( collector.m_MenuCancelled, false );
BOOST_CHECK( !collector.HasAdditionalItems() );
}
BOOST_AUTO_TEST_CASE( Append_SingleItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item( PCB_T );
collector.Append( &item );
BOOST_CHECK_EQUAL( collector.GetCount(), 1 );
BOOST_CHECK_EQUAL( collector[0], &item );
}
BOOST_AUTO_TEST_CASE( Append_MultipleItems )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Append( &item3 );
BOOST_CHECK_EQUAL( collector.GetCount(), 3 );
BOOST_CHECK_EQUAL( collector[0], &item1 );
BOOST_CHECK_EQUAL( collector[1], &item2 );
BOOST_CHECK_EQUAL( collector[2], &item3 );
}
BOOST_AUTO_TEST_CASE( Append_NullItem )
{
COLLECTOR collector;
collector.Append( nullptr );
BOOST_CHECK_EQUAL( collector.GetCount(), 1 );
BOOST_CHECK_EQUAL( collector[0], nullptr );
}
BOOST_AUTO_TEST_CASE( Empty_ClearsList )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
collector.Append( &item1 );
collector.Append( &item2 );
BOOST_CHECK_EQUAL( collector.GetCount(), 2 );
collector.Empty();
BOOST_CHECK_EQUAL( collector.GetCount(), 0 );
}
BOOST_AUTO_TEST_CASE( Remove_ByIndex_ValidIndex )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Append( &item3 );
collector.Remove( 1 ); // Remove middle item
BOOST_CHECK_EQUAL( collector.GetCount(), 2 );
BOOST_CHECK_EQUAL( collector[0], &item1 );
BOOST_CHECK_EQUAL( collector[1], &item3 );
}
BOOST_AUTO_TEST_CASE( Remove_ByIndex_FirstItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Remove( 0 );
BOOST_CHECK_EQUAL( collector.GetCount(), 1 );
BOOST_CHECK_EQUAL( collector[0], &item2 );
}
BOOST_AUTO_TEST_CASE( Remove_ByIndex_LastItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Remove( 1 );
BOOST_CHECK_EQUAL( collector.GetCount(), 1 );
BOOST_CHECK_EQUAL( collector[0], &item1 );
}
BOOST_AUTO_TEST_CASE( Remove_ByPointer_ExistingItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Append( &item3 );
collector.Remove( &item2 );
BOOST_CHECK_EQUAL( collector.GetCount(), 2 );
BOOST_CHECK_EQUAL( collector[0], &item1 );
BOOST_CHECK_EQUAL( collector[1], &item3 );
}
BOOST_AUTO_TEST_CASE( Remove_ByPointer_NonExistingItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Remove( &item3 ); // Not in collection
BOOST_CHECK_EQUAL( collector.GetCount(), 2 );
BOOST_CHECK_EQUAL( collector[0], &item1 );
BOOST_CHECK_EQUAL( collector[1], &item2 );
}
BOOST_AUTO_TEST_CASE( Remove_ByPointer_DuplicateItems )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
collector.Append( &item1 );
collector.Append( &item1 );
collector.Append( &item1 );
collector.Remove( &item1 );
BOOST_CHECK_EQUAL( collector.GetCount(), 0 ); // All instances should be removed
}
BOOST_AUTO_TEST_CASE( Transfer_ByIndex_ValidIndex )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Append( &item3 );
collector.Transfer( 1 );
BOOST_CHECK_EQUAL( collector.GetCount(), 2 );
BOOST_CHECK_EQUAL( collector[0], &item1 );
BOOST_CHECK_EQUAL( collector[1], &item3 );
BOOST_CHECK( collector.HasAdditionalItems() );
}
BOOST_AUTO_TEST_CASE( Transfer_ByPointer_ExistingItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Append( &item3 );
collector.Transfer( &item2 );
BOOST_CHECK_EQUAL( collector.GetCount(), 2 );
BOOST_CHECK_EQUAL( collector[0], &item1 );
BOOST_CHECK_EQUAL( collector[1], &item3 );
BOOST_CHECK( collector.HasAdditionalItems() );
}
BOOST_AUTO_TEST_CASE( Transfer_ByPointer_NonExistingItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Transfer( &item3 ); // Not in collection
BOOST_CHECK_EQUAL( collector.GetCount(), 2 );
BOOST_CHECK( !collector.HasAdditionalItems() );
}
BOOST_AUTO_TEST_CASE( Combine_RestoresBackupItems )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Append( &item3 );
collector.Transfer( &item2 );
collector.Transfer( &item3 );
BOOST_CHECK_EQUAL( collector.GetCount(), 1 );
BOOST_CHECK( collector.HasAdditionalItems() );
collector.Combine();
BOOST_CHECK_EQUAL( collector.GetCount(), 3 );
BOOST_CHECK( !collector.HasAdditionalItems() );
BOOST_CHECK_EQUAL( collector[0], &item1 );
BOOST_CHECK_EQUAL( collector[1], &item2 );
BOOST_CHECK_EQUAL( collector[2], &item3 );
}
BOOST_AUTO_TEST_CASE( Combine_EmptyBackupList )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
collector.Append( &item1 );
BOOST_CHECK( !collector.HasAdditionalItems() );
collector.Combine();
BOOST_CHECK_EQUAL( collector.GetCount(), 1 );
BOOST_CHECK( !collector.HasAdditionalItems() );
}
BOOST_AUTO_TEST_CASE( OperatorBrackets_ValidIndex )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
collector.Append( &item1 );
collector.Append( &item2 );
BOOST_CHECK_EQUAL( collector[0], &item1 );
BOOST_CHECK_EQUAL( collector[1], &item2 );
}
BOOST_AUTO_TEST_CASE( OperatorBrackets_InvalidIndex )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
collector.Append( &item1 );
BOOST_CHECK_EQUAL( collector[1], nullptr ); // Out of bounds
BOOST_CHECK_EQUAL( collector[-1], nullptr ); // Negative index
BOOST_CHECK_EQUAL( collector[100], nullptr ); // Large index
}
BOOST_AUTO_TEST_CASE( OperatorBrackets_EmptyCollector )
{
COLLECTOR collector;
BOOST_CHECK_EQUAL( collector[0], nullptr );
}
BOOST_AUTO_TEST_CASE( HasItem_ExistingItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
collector.Append( &item1 );
collector.Append( &item2 );
BOOST_CHECK( collector.HasItem( &item1 ) );
BOOST_CHECK( collector.HasItem( &item2 ) );
}
BOOST_AUTO_TEST_CASE( HasItem_NonExistingItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
BOOST_CHECK( !collector.HasItem( &item3 ) );
}
BOOST_AUTO_TEST_CASE( HasItem_NullItem )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
collector.Append( &item1 );
collector.Append( nullptr );
BOOST_CHECK( collector.HasItem( nullptr ) );
}
BOOST_AUTO_TEST_CASE( HasItem_EmptyCollector )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
BOOST_CHECK( !collector.HasItem( &item1 ) );
}
BOOST_AUTO_TEST_CASE( CountType_SingleType )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_T );
TEST_EDA_ITEM item3( PCB_VIA_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Append( &item3 );
BOOST_CHECK_EQUAL( collector.CountType( PCB_T ), 2 );
BOOST_CHECK_EQUAL( collector.CountType( PCB_VIA_T ), 1 );
BOOST_CHECK_EQUAL( collector.CountType( PCB_TRACE_T ), 0 );
}
BOOST_AUTO_TEST_CASE( CountType_EmptyCollector )
{
COLLECTOR collector;
BOOST_CHECK_EQUAL( collector.CountType( PCB_T ), 0 );
}
BOOST_AUTO_TEST_CASE( SetScanTypes_Basic )
{
COLLECTOR collector;
std::vector<KICAD_T> types = { PCB_T, PCB_VIA_T };
collector.SetScanTypes( types );
// No direct way to test this, but it should not crash
BOOST_CHECK( true );
}
BOOST_AUTO_TEST_CASE( SetRefPos_Basic )
{
COLLECTOR collector;
VECTOR2I refPos( 100, 200 );
collector.SetRefPos( refPos );
// No direct way to test this, but it should not crash
BOOST_CHECK( true );
}
BOOST_AUTO_TEST_CASE( Iterator_BeginEnd )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
collector.Append( &item1 );
collector.Append( &item2 );
collector.Append( &item3 );
std::vector<EDA_ITEM*> items;
for( auto iter = collector.begin(); iter != collector.end(); ++iter )
{
items.push_back( *iter );
}
BOOST_CHECK_EQUAL( items.size(), 3 );
BOOST_CHECK_EQUAL( items[0], &item1 );
BOOST_CHECK_EQUAL( items[1], &item2 );
BOOST_CHECK_EQUAL( items[2], &item3 );
}
BOOST_AUTO_TEST_CASE( Iterator_RangeBasedFor )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
collector.Append( &item1 );
collector.Append( &item2 );
std::vector<EDA_ITEM*> items;
for( EDA_ITEM* item : collector )
{
items.push_back( item );
}
BOOST_CHECK_EQUAL( items.size(), 2 );
BOOST_CHECK_EQUAL( items[0], &item1 );
BOOST_CHECK_EQUAL( items[1], &item2 );
}
BOOST_AUTO_TEST_CASE( Iterator_ConstIterator )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
collector.Append( &item1 );
const COLLECTOR& constCollector = collector;
std::vector<const EDA_ITEM*> items;
for( auto iter = constCollector.begin(); iter != constCollector.end(); ++iter )
{
items.push_back( *iter );
}
BOOST_CHECK_EQUAL( items.size(), 1 );
BOOST_CHECK_EQUAL( items[0], &item1 );
}
BOOST_AUTO_TEST_CASE( Inspect_BasicFunctionality )
{
TEST_COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
INSPECT_RESULT result = collector.Inspect( &item1, nullptr );
BOOST_CHECK_EQUAL( result, INSPECT_RESULT::CONTINUE );
BOOST_CHECK_EQUAL( collector.GetInspectCalls(), 1 );
BOOST_CHECK_EQUAL( collector.GetCount(), 1 );
}
BOOST_AUTO_TEST_CASE( Inspect_WithScanTypes )
{
TEST_COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
std::vector<KICAD_T> scanTypes = { PCB_T, PCB_VIA_T };
collector.SetScanTypes( scanTypes );
collector.Inspect( &item1, nullptr ); // Should be collected
collector.Inspect( &item2, nullptr ); // Should be collected
collector.Inspect( &item3, nullptr ); // Should NOT be collected
BOOST_CHECK_EQUAL( collector.GetCount(), 2 );
BOOST_CHECK( collector.HasItem( &item1 ) );
BOOST_CHECK( collector.HasItem( &item2 ) );
BOOST_CHECK( !collector.HasItem( &item3 ) );
}
BOOST_AUTO_TEST_CASE( ComplexWorkflow_TransferAndCombine )
{
COLLECTOR collector;
TEST_EDA_ITEM item1( PCB_T );
TEST_EDA_ITEM item2( PCB_VIA_T );
TEST_EDA_ITEM item3( PCB_TRACE_T );
TEST_EDA_ITEM item4( PCB_PAD_T );
// Add items
collector.Append( &item1 );
collector.Append( &item2 );
collector.Append( &item3 );
collector.Append( &item4 );
BOOST_CHECK_EQUAL( collector.GetCount(), 4 );
// Transfer some items
collector.Transfer( &item2 );
collector.Transfer( &item4 );
BOOST_CHECK_EQUAL( collector.GetCount(), 2 );
BOOST_CHECK( collector.HasAdditionalItems() );
// Remove one remaining item
collector.Remove( &item1 );
BOOST_CHECK_EQUAL( collector.GetCount(), 1 );
// Combine back
collector.Combine();
BOOST_CHECK_EQUAL( collector.GetCount(), 3 );
BOOST_CHECK( !collector.HasAdditionalItems() );
// Check final state
BOOST_CHECK( !collector.HasItem( &item1 ) ); // Was removed
BOOST_CHECK( collector.HasItem( &item2 ) ); // Was transferred back
BOOST_CHECK( collector.HasItem( &item3 ) ); // Was never moved
BOOST_CHECK( collector.HasItem( &item4 ) ); // Was transferred back
}
BOOST_AUTO_TEST_SUITE_END()

79
qa/tests/common/test_hotkey_store.cpp

@ -0,0 +1,79 @@
/*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <boost/test/unit_test.hpp>
#include <hotkey_store.h>
#include <hotkeys_basic.h>
#include <tool/tool_action.h>
#include <tool/tool_event.h>
BOOST_AUTO_TEST_SUITE( HotkeyStore )
BOOST_AUTO_TEST_CASE( PersistenceAndDefaults )
{
TOOL_ACTION action1( TOOL_ACTION_ARGS().Name( "common.test1" ).FriendlyName( "Test1" )
.Scope( AS_GLOBAL ).DefaultHotkey( 'A' ) );
TOOL_ACTION action2( TOOL_ACTION_ARGS().Name( "common.test2" ).FriendlyName( "Test2" )
.Scope( AS_GLOBAL ).DefaultHotkey( 'B' ) );
HOTKEY_STORE store;
store.Init( { &action1, &action2 }, false );
auto& sections = store.GetSections();
BOOST_REQUIRE( !sections.empty() );
HOTKEY& hk = sections[0].m_HotKeys[0];
hk.m_EditKeycode = 'C';
store.SaveAllHotkeys();
BOOST_CHECK_EQUAL( action1.GetHotKey(), 'C' );
store.ResetAllHotkeysToDefault();
BOOST_CHECK_EQUAL( sections[0].m_HotKeys[0].m_EditKeycode, action1.GetDefaultHotKey() );
}
BOOST_AUTO_TEST_CASE( DuplicateRegistration )
{
TOOL_ACTION action1( TOOL_ACTION_ARGS().Name( "common.test1" ).FriendlyName( "Test1" )
.Scope( AS_GLOBAL ).DefaultHotkey( 'A' ) );
TOOL_ACTION action2( TOOL_ACTION_ARGS().Name( "common.test2" ).FriendlyName( "Test2" )
.Scope( AS_GLOBAL ).DefaultHotkey( 'B' ) );
HOTKEY_STORE store;
store.Init( { &action1, &action2 }, false );
HOTKEY* conflict = nullptr;
bool has = store.CheckKeyConflicts( &action1, action2.GetHotKey(), &conflict );
BOOST_CHECK( has );
BOOST_CHECK( conflict != nullptr );
has = store.CheckKeyConflicts( &action1, 'Z', &conflict );
BOOST_CHECK( !has );
}
BOOST_AUTO_TEST_CASE( KeycodeSerialization )
{
int code = MD_CTRL + 'M';
wxString name = KeyNameFromKeyCode( code );
int round = KeyCodeFromKeyName( name );
BOOST_CHECK_EQUAL( code, round );
}
BOOST_AUTO_TEST_SUITE_END()

65
qa/tests/common/test_notifications_manager.cpp

@ -0,0 +1,65 @@
/*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <boost/test/unit_test.hpp>
#include <ui_events.h>
#include <build_version.h>
#include <paths.h>
#include <wx/filename.h>
#include <wx/string.h>
#include <notifications_manager.h>
BOOST_AUTO_TEST_SUITE( Notifications )
BOOST_AUTO_TEST_CASE( CreateAndPersist )
{
wxFileName tmpDir( wxFileName::GetTempDir(), "" );
wxString envPath = tmpDir.GetFullPath();
wxSetEnv( wxS("KICAD_CACHE_HOME"), envPath );
wxFileName::Mkdir( tmpDir.GetFullPath(), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
NOTIFICATIONS_MANAGER mgr;
mgr.CreateOrUpdate( wxS("key"), wxS("Title"), wxS("Desc") );
mgr.Save();
wxFileName fn( PATHS::GetUserCachePath(), wxS("notifications.json") );
BOOST_CHECK( fn.FileExists() );
}
class TEST_HANDLER : public wxEvtHandler
{
public:
bool triggered = false;
void OnEvent( wxCommandEvent& ) { triggered = true; }
};
BOOST_AUTO_TEST_CASE( EventDispatch )
{
TEST_HANDLER handler;
handler.Bind( EDA_EVT_UNITS_CHANGED, &TEST_HANDLER::OnEvent, &handler );
wxCommandEvent evt( EDA_EVT_UNITS_CHANGED );
handler.ProcessEvent( evt );
BOOST_CHECK( handler.triggered );
}
BOOST_AUTO_TEST_SUITE_END()

478
qa/tests/common/test_reporting.cpp

@ -0,0 +1,478 @@
/*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <boost/test/unit_test.hpp>
#include <reporter.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/statusbr.h>
#include <wx/log.h>
#include <vector>
#include <sstream>
// Mock TEST_REPORTER to test base REPORTER functionality
class TEST_REPORTER : public REPORTER
{
public:
TEST_REPORTER() : m_hasMessage( false ), m_messageCount( 0 ) {}
REPORTER& Report( const wxString& aText, SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override
{
REPORTER::Report( aText, aSeverity ); // Call base to update severity mask
m_messages.push_back( std::make_pair( aText, aSeverity ) );
m_hasMessage = true;
m_messageCount++;
return *this;
}
bool HasMessage() const override
{
return m_hasMessage;
}
void Clear() override
{
REPORTER::Clear();
m_messages.clear();
m_hasMessage = false;
m_messageCount = 0;
}
const std::vector<std::pair<wxString, SEVERITY>>& GetMessages() const { return m_messages; }
int GetMessageCount() const { return m_messageCount; }
private:
std::vector<std::pair<wxString, SEVERITY>> m_messages;
bool m_hasMessage;
int m_messageCount;
};
// Mock wxTextCtrl for testing
class MockTextCtrl
{
public:
MockTextCtrl() {}
void AppendText( const wxString& text ) { m_content += text; }
void SetValue( const wxString& text ) { m_content = text; }
wxString GetValue() const { return m_content; }
bool IsEmpty() const { return m_content.IsEmpty(); }
void Clear() { m_content.Clear(); }
private:
wxString m_content;
};
// Mock wxStatusBar for testing
class MockStatusBar
{
public:
MockStatusBar() { m_fields.resize( 3 ); } // Default 3 fields
void SetStatusText( const wxString& text, int field = 0 )
{
if( field >= 0 && field < (int)m_fields.size() )
m_fields[field] = text;
}
wxString GetStatusText( int field = 0 ) const
{
if( field >= 0 && field < (int)m_fields.size() )
return m_fields[field];
return wxEmptyString;
}
private:
std::vector<wxString> m_fields;
};
BOOST_AUTO_TEST_SUITE( ReporterTests )
BOOST_AUTO_TEST_CASE( BaseReporter_Constructor )
{
TEST_REPORTER reporter;
BOOST_CHECK( !reporter.HasMessage() );
BOOST_CHECK( reporter.GetUnits() == EDA_UNITS::MM );
BOOST_CHECK( !reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO ) );
}
BOOST_AUTO_TEST_CASE( BaseReporter_SingleReport )
{
TEST_REPORTER reporter;
reporter.Report( wxT("Test message"), RPT_SEVERITY_INFO );
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK_EQUAL( reporter.GetMessageCount(), 1 );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO ) );
const auto& messages = reporter.GetMessages();
BOOST_CHECK_EQUAL( messages.size(), 1 );
BOOST_CHECK_EQUAL( messages[0].first, wxString("Test message") );
BOOST_CHECK_EQUAL( messages[0].second, RPT_SEVERITY_INFO );
}
BOOST_AUTO_TEST_CASE( BaseReporter_MultipleReports )
{
TEST_REPORTER reporter;
reporter.Report( wxT("Info message"), RPT_SEVERITY_INFO );
reporter.Report( wxT("Warning message"), RPT_SEVERITY_WARNING );
reporter.Report( wxT("Error message"), RPT_SEVERITY_ERROR );
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK_EQUAL( reporter.GetMessageCount(), 3 );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO ) );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_ERROR ) );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO | RPT_SEVERITY_WARNING ) );
}
BOOST_AUTO_TEST_CASE( BaseReporter_ReportTail )
{
TEST_REPORTER reporter;
reporter.ReportTail( wxT("Tail message"), RPT_SEVERITY_INFO );
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK_EQUAL( reporter.GetMessageCount(), 1 );
const auto& messages = reporter.GetMessages();
BOOST_CHECK_EQUAL( messages[0].first, wxString("Tail message") );
BOOST_CHECK_EQUAL( messages[0].second, RPT_SEVERITY_INFO );
}
BOOST_AUTO_TEST_CASE( BaseReporter_ReportHead )
{
TEST_REPORTER reporter;
reporter.ReportHead( wxT("Head message"), RPT_SEVERITY_WARNING );
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK_EQUAL( reporter.GetMessageCount(), 1 );
const auto& messages = reporter.GetMessages();
BOOST_CHECK_EQUAL( messages[0].first, wxString("Head message") );
BOOST_CHECK_EQUAL( messages[0].second, RPT_SEVERITY_WARNING );
}
BOOST_AUTO_TEST_CASE( BaseReporter_OperatorLeftShift )
{
TEST_REPORTER reporter;
reporter << wxT("Stream message");
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK_EQUAL( reporter.GetMessageCount(), 1 );
const auto& messages = reporter.GetMessages();
BOOST_CHECK_EQUAL( messages[0].first, wxString("Stream message") );
BOOST_CHECK_EQUAL( messages[0].second, RPT_SEVERITY_UNDEFINED );
}
BOOST_AUTO_TEST_CASE( BaseReporter_CharPointerReport )
{
TEST_REPORTER reporter;
reporter.Report( "C-style string", RPT_SEVERITY_ERROR );
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK_EQUAL( reporter.GetMessageCount(), 1 );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_ERROR ) );
}
BOOST_AUTO_TEST_CASE( BaseReporter_Clear )
{
TEST_REPORTER reporter;
reporter.Report( wxT("Message 1"), RPT_SEVERITY_INFO );
reporter.Report( wxT("Message 2"), RPT_SEVERITY_WARNING );
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO ) );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) );
reporter.Clear();
BOOST_CHECK( !reporter.HasMessage() );
BOOST_CHECK( !reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO ) );
BOOST_CHECK( !reporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) );
BOOST_CHECK_EQUAL( reporter.GetMessageCount(), 0 );
}
BOOST_AUTO_TEST_CASE( BaseReporter_SeverityMask )
{
TEST_REPORTER reporter;
// Test individual severities
reporter.Report( wxT("Info"), RPT_SEVERITY_INFO );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO ) );
BOOST_CHECK( !reporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) );
reporter.Report( wxT("Warning"), RPT_SEVERITY_WARNING );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO ) );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO | RPT_SEVERITY_WARNING ) );
// Test combined mask
BOOST_CHECK( !reporter.HasMessageOfSeverity( RPT_SEVERITY_ERROR ) );
BOOST_CHECK( !reporter.HasMessageOfSeverity( RPT_SEVERITY_ACTION ) );
}
BOOST_AUTO_TEST_CASE( BaseReporter_EmptyMessage )
{
TEST_REPORTER reporter;
reporter.Report( wxT(""), RPT_SEVERITY_INFO );
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK_EQUAL( reporter.GetMessageCount(), 1 );
const auto& messages = reporter.GetMessages();
BOOST_CHECK_EQUAL( messages[0].first, wxString("") );
}
BOOST_AUTO_TEST_CASE( BaseReporter_LongMessage )
{
TEST_REPORTER reporter;
wxString longMessage( 10000, 'A' );
reporter.Report( longMessage, RPT_SEVERITY_INFO );
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK_EQUAL( reporter.GetMessageCount(), 1 );
const auto& messages = reporter.GetMessages();
BOOST_CHECK_EQUAL( messages[0].first, longMessage );
}
BOOST_AUTO_TEST_CASE( WxStringReporter_BasicFunctionality )
{
WX_STRING_REPORTER reporter;
BOOST_CHECK( !reporter.HasMessage() );
reporter.Report( wxT("Test message"), RPT_SEVERITY_INFO );
BOOST_CHECK( reporter.HasMessage() );
BOOST_CHECK( !reporter.GetMessages().IsEmpty() );
BOOST_CHECK( reporter.GetMessages().Contains( wxT("Test message") ) );
}
BOOST_AUTO_TEST_CASE( WxStringReporter_MultipleMessages )
{
WX_STRING_REPORTER reporter;
reporter.Report( wxT("Message 1"), RPT_SEVERITY_INFO );
reporter.Report( wxT("Message 2"), RPT_SEVERITY_WARNING );
BOOST_CHECK( reporter.HasMessage() );
const wxString& messages = reporter.GetMessages();
BOOST_CHECK( messages.Contains( wxT("Message 1") ) );
BOOST_CHECK( messages.Contains( wxT("Message 2") ) );
}
BOOST_AUTO_TEST_CASE( WxStringReporter_Clear )
{
WX_STRING_REPORTER reporter;
reporter.Report( wxT("Test message"), RPT_SEVERITY_INFO );
BOOST_CHECK( reporter.HasMessage() );
reporter.Clear();
BOOST_CHECK( !reporter.HasMessage() );
BOOST_CHECK( reporter.GetMessages().IsEmpty() );
}
BOOST_AUTO_TEST_CASE( WxStringReporter_SeverityMask )
{
WX_STRING_REPORTER reporter;
reporter.Report( wxT("Info"), RPT_SEVERITY_INFO );
reporter.Report( wxT("Warning"), RPT_SEVERITY_WARNING );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO ) );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO | RPT_SEVERITY_WARNING ) );
BOOST_CHECK( !reporter.HasMessageOfSeverity( RPT_SEVERITY_ERROR ) );
}
BOOST_AUTO_TEST_CASE( WxStringReporter_OperatorChaining )
{
WX_STRING_REPORTER reporter;
reporter.Report( wxT("First"), RPT_SEVERITY_INFO )
.Report( wxT("Second"), RPT_SEVERITY_WARNING )
<< wxT("Third");
BOOST_CHECK( reporter.HasMessage() );
const wxString& messages = reporter.GetMessages();
BOOST_CHECK( messages.Contains( wxT("First") ) );
BOOST_CHECK( messages.Contains( wxT("Second") ) );
BOOST_CHECK( messages.Contains( wxT("Third") ) );
}
BOOST_AUTO_TEST_CASE( NullReporter_Singleton )
{
REPORTER& reporter1 = NULL_REPORTER::GetInstance();
REPORTER& reporter2 = NULL_REPORTER::GetInstance();
BOOST_CHECK_EQUAL( &reporter1, &reporter2 );
}
BOOST_AUTO_TEST_CASE( NullReporter_NoMessages )
{
REPORTER& reporter = NULL_REPORTER::GetInstance();
BOOST_CHECK( !reporter.HasMessage() );
reporter.Report( wxT("Test message"), RPT_SEVERITY_INFO );
BOOST_CHECK( !reporter.HasMessage() ); // Should still report no messages
}
BOOST_AUTO_TEST_CASE( NullReporter_SeverityMask )
{
REPORTER& reporter = NULL_REPORTER::GetInstance();
reporter.Report( wxT("Info"), RPT_SEVERITY_INFO );
reporter.Report( wxT("Warning"), RPT_SEVERITY_WARNING );
// NULL_REPORTER should track severity mask even though it doesn't store messages
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_INFO ) );
BOOST_CHECK( reporter.HasMessageOfSeverity( RPT_SEVERITY_WARNING ) );
}
BOOST_AUTO_TEST_CASE( CliReporter_Singleton )
{
REPORTER& reporter1 = CLI_REPORTER::GetInstance();
REPORTER& reporter2 = CLI_REPORTER::GetInstance();
BOOST_CHECK_EQUAL( &reporter1, &reporter2 );
}
BOOST_AUTO_TEST_CASE( CliReporter_NoMessages )
{
REPORTER& reporter = CLI_REPORTER::GetInstance();
BOOST_CHECK( !reporter.HasMessage() );
reporter.Report( wxT("Test message"), RPT_SEVERITY_INFO );
BOOST_CHECK( !reporter.HasMessage() ); // Should not store messages
}
BOOST_AUTO_TEST_CASE( StdoutReporter_Singleton )
{
REPORTER& reporter1 = STDOUT_REPORTER::GetInstance();
REPORTER& reporter2 = STDOUT_REPORTER::GetInstance();
BOOST_CHECK_EQUAL( &reporter1, &reporter2 );
}
BOOST_AUTO_TEST_CASE( StdoutReporter_NoMessages )
{
REPORTER& reporter = STDOUT_REPORTER::GetInstance();
BOOST_CHECK( !reporter.HasMessage() );
reporter.Report( wxT("Test message"), RPT_SEVERITY_INFO );
BOOST_CHECK( !reporter.HasMessage() ); // Should not store messages
}
BOOST_AUTO_TEST_CASE( WxLogReporter_Singleton )
{
REPORTER& reporter1 = WXLOG_REPORTER::GetInstance();
REPORTER& reporter2 = WXLOG_REPORTER::GetInstance();
BOOST_CHECK_EQUAL( &reporter1, &reporter2 );
}
BOOST_AUTO_TEST_CASE( WxLogReporter_NoMessages )
{
REPORTER& reporter = WXLOG_REPORTER::GetInstance();
BOOST_CHECK( !reporter.HasMessage() );
reporter.Report( wxT("Test message"), RPT_SEVERITY_INFO );
BOOST_CHECK( !reporter.HasMessage() ); // Should not store messages
}
// Note: WX_TEXT_CTRL_REPORTER and STATUSBAR_REPORTER tests would require
// actual wxWidgets objects or more sophisticated mocking
BOOST_AUTO_TEST_CASE( ReporterInterface_Polymorphism )
{
std::vector<std::unique_ptr<REPORTER>> reporters;
reporters.push_back( std::make_unique<WX_STRING_REPORTER>() );
reporters.push_back( std::make_unique<TEST_REPORTER>() );
for( auto& reporter : reporters )
{
reporter->Report( wxT("Polymorphic test"), RPT_SEVERITY_INFO );
// WX_STRING_REPORTER and TEST_REPORTER should both store messages
if( dynamic_cast<WX_STRING_REPORTER*>( reporter.get() ) ||
dynamic_cast<TEST_REPORTER*>( reporter.get() ) )
{
BOOST_CHECK( reporter->HasMessage() );
}
}
}
BOOST_AUTO_TEST_CASE( ReporterInterface_ChainedOperations )
{
WX_STRING_REPORTER reporter;
// Test method chaining
REPORTER& result = reporter.Report( wxT("First"), RPT_SEVERITY_INFO )
.ReportHead( wxT("Head"), RPT_SEVERITY_WARNING )
.ReportTail( wxT("Tail"), RPT_SEVERITY_ERROR );
BOOST_CHECK_EQUAL( &result, &reporter ); // Should return reference to self
BOOST_CHECK( reporter.HasMessage() );
const wxString& messages = reporter.GetMessages();
BOOST_CHECK( messages.Contains( wxT("First") ) );
BOOST_CHECK( messages.Contains( wxT("Head") ) );
BOOST_CHECK( messages.Contains( wxT("Tail") ) );
}
BOOST_AUTO_TEST_CASE( ReporterInterface_DefaultSeverity )
{
TEST_REPORTER reporter;
// Test default severity parameter
reporter.Report( wxT("Default severity") );
const auto& messages = reporter.GetMessages();
BOOST_CHECK_EQUAL( messages[0].second, RPT_SEVERITY_UNDEFINED );
}
BOOST_AUTO_TEST_CASE( ReporterInterface_UnitsDefault )
{
TEST_REPORTER reporter;
BOOST_CHECK( reporter.GetUnits() == EDA_UNITS::MM );
}
BOOST_AUTO_TEST_SUITE_END()
Loading…
Cancel
Save