KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_property_holder.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.en.html
19 * or you may search the http://www.gnu.org website for the version 3 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
33
34// Code under test
35#include <property_holder.h>
36
37#include <string>
38#include <vector>
39#include <memory>
40
41namespace
42{
43
47class TestWidget : public PROPERTY_MIXIN
48{
49public:
50 TestWidget( const std::string& name ) : m_name( name )
51 {
52 SetProperty( "widget_name", name );
53 SetProperty( "default_enabled", true );
54 }
55
56 const std::string& GetName() const { return m_name; }
57
58private:
59 std::string m_name;
60};
61
65struct CustomData
66{
67 int value;
68 std::string text;
69
70 CustomData( int v, const std::string& t ) : value( v ), text( t ) {}
71
72 bool operator==( const CustomData& other ) const
73 {
74 return value == other.value && text == other.text;
75 }
76};
77
81struct PROPERTY_HOLDER_TEST_FIXTURE
82{
83 PROPERTY_HOLDER_TEST_FIXTURE()
84 {
85 // Set up a holder with various types
86 m_populatedHolder.SetProperty( "bool_prop", true );
87 m_populatedHolder.SetProperty( "int_prop", 42 );
88 m_populatedHolder.SetProperty( "double_prop", 3.14159 );
89 m_populatedHolder.SetProperty( "string_prop", std::string( "hello world" ) );
90 m_populatedHolder.SetProperty( "cstring_prop", "c-style string" );
91
92 // Add a custom object
93 m_populatedHolder.SetProperty( "custom_prop", CustomData( 100, "custom" ) );
94
95 // Add a vector
96 std::vector<int> numbers = { 1, 2, 3, 4, 5 };
97 m_populatedHolder.SetProperty( "vector_prop", numbers );
98 }
99
100 PROPERTY_HOLDER m_emptyHolder;
101 PROPERTY_HOLDER m_populatedHolder;
102};
103
104} // namespace
105
109BOOST_FIXTURE_TEST_SUITE( TEST_PROPERTY_HOLDER, PROPERTY_HOLDER_TEST_FIXTURE )
110
111
115{
116 PROPERTY_HOLDER holder;
117
118 // Test various basic types
119 holder.SetProperty( "test_bool", true );
120 holder.SetProperty( "test_int", 123 );
121 holder.SetProperty( "test_double", 2.71828 );
122 holder.SetProperty( "test_string", std::string( "test value" ) );
123
124 // Verify retrieval with correct types
125 auto boolResult = holder.GetProperty<bool>( "test_bool" );
126 BOOST_CHECK( boolResult.has_value() );
127 BOOST_CHECK_EQUAL( *boolResult, true );
128
129 auto intResult = holder.GetProperty<int>( "test_int" );
130 BOOST_CHECK( intResult.has_value() );
131 BOOST_CHECK_EQUAL( *intResult, 123 );
132
133 auto doubleResult = holder.GetProperty<double>( "test_double" );
134 BOOST_CHECK( doubleResult.has_value() );
135 BOOST_CHECK_CLOSE( *doubleResult, 2.71828, 0.0001 );
136
137 auto stringResult = holder.GetProperty<std::string>( "test_string" );
138 BOOST_CHECK( stringResult.has_value() );
139 BOOST_CHECK_EQUAL( *stringResult, "test value" );
140}
141
146{
147 PROPERTY_HOLDER holder;
148 holder.SetProperty( "int_value", 42 );
149
150 // Correct type retrieval
151 auto intResult = holder.GetProperty<int>( "int_value" );
152 BOOST_CHECK( intResult.has_value() );
153 BOOST_CHECK_EQUAL( *intResult, 42 );
154
155 // Wrong type retrieval should return nullopt
156 auto stringResult = holder.GetProperty<std::string>( "int_value" );
157 BOOST_CHECK( !stringResult.has_value() );
158
159 auto doubleResult = holder.GetProperty<double>( "int_value" );
160 BOOST_CHECK( !doubleResult.has_value() );
161
162 auto boolResult = holder.GetProperty<bool>( "int_value" );
163 BOOST_CHECK( !boolResult.has_value() );
164}
165
169BOOST_AUTO_TEST_CASE( DefaultValues )
170{
171 PROPERTY_HOLDER holder;
172 holder.SetProperty( "existing_prop", 100 );
173
174 // Existing property should return stored value
175 int existingValue = holder.GetPropertyOr( "existing_prop", 999 );
176 BOOST_CHECK_EQUAL( existingValue, 100 );
177
178 // Non-existing property should return default
179 int nonExistingValue = holder.GetPropertyOr( "missing_prop", 777 );
180 BOOST_CHECK_EQUAL( nonExistingValue, 777 );
181
182 // Wrong type should return default
183 std::string wrongTypeValue = holder.GetPropertyOr<std::string>( "existing_prop", "default" );
184 BOOST_CHECK_EQUAL( wrongTypeValue, "default" );
185
186 // Test with different types
187 bool defaultBool = holder.GetPropertyOr( "missing_bool", false );
188 BOOST_CHECK_EQUAL( defaultBool, false );
189
190 std::string defaultString = holder.GetPropertyOr<std::string>( "missing_string", "fallback" );
191 BOOST_CHECK_EQUAL( defaultString, "fallback" );
192}
193
197BOOST_AUTO_TEST_CASE( ExistenceChecking )
198{
199 // Empty holder
200 BOOST_CHECK_EQUAL( false, m_emptyHolder.HasProperty( "any_key" ) );
201
202 // Populated holder
203 BOOST_CHECK( m_populatedHolder.HasProperty( "bool_prop" ) );
204 BOOST_CHECK( m_populatedHolder.HasProperty( "int_prop" ) );
205 BOOST_CHECK( m_populatedHolder.HasProperty( "string_prop" ) );
206 BOOST_CHECK_EQUAL( false, m_populatedHolder.HasProperty( "missing_prop" ) );
207}
208
212BOOST_AUTO_TEST_CASE( TypeSpecificExistence )
213{
214 // Check correct type detection
215 BOOST_CHECK( m_populatedHolder.HasPropertyOfType<bool>( "bool_prop" ) );
216 BOOST_CHECK( m_populatedHolder.HasPropertyOfType<int>( "int_prop" ) );
217 BOOST_CHECK( m_populatedHolder.HasPropertyOfType<double>( "double_prop" ) );
218 BOOST_CHECK( m_populatedHolder.HasPropertyOfType<std::string>( "string_prop" ) );
219
220 // Check wrong type detection
221 BOOST_CHECK_EQUAL( false, m_populatedHolder.HasPropertyOfType<int>( "bool_prop" ) );
222 BOOST_CHECK_EQUAL( false, m_populatedHolder.HasPropertyOfType<bool>( "int_prop" ) );
223 BOOST_CHECK_EQUAL( false, m_populatedHolder.HasPropertyOfType<std::string>( "int_prop" ) );
224
225 // Non-existing property
226 BOOST_CHECK_EQUAL( false, m_populatedHolder.HasPropertyOfType<bool>( "missing_prop" ) );
227}
228
232BOOST_AUTO_TEST_CASE( PropertyRemoval )
233{
234 PROPERTY_HOLDER holder;
235 holder.SetProperty( "temp_prop", 42 );
236
237 // Property should exist
238 BOOST_CHECK( holder.HasProperty( "temp_prop" ) );
239 BOOST_CHECK_EQUAL( 1, holder.Size() );
240
241 // Remove existing property
242 bool removed = holder.RemoveProperty( "temp_prop" );
243 BOOST_CHECK( removed );
244 BOOST_CHECK_EQUAL( false, holder.HasProperty( "temp_prop" ) );
245 BOOST_CHECK_EQUAL( 0, holder.Size() );
246
247 // Try to remove non-existing property
248 bool notRemoved = holder.RemoveProperty( "non_existing" );
249 BOOST_CHECK_EQUAL( false, notRemoved );
250}
251
255BOOST_AUTO_TEST_CASE( ClearProperties )
256{
257 PROPERTY_HOLDER holder;
258 holder.SetProperty( "prop1", 1 );
259 holder.SetProperty( "prop2", "two" );
260 holder.SetProperty( "prop3", true );
261
262 BOOST_CHECK_EQUAL( 3, holder.Size() );
263 BOOST_CHECK_EQUAL( false, holder.Empty() );
264
265 holder.Clear();
266
267 BOOST_CHECK_EQUAL( 0, holder.Size() );
268 BOOST_CHECK( holder.Empty() );
269 BOOST_CHECK_EQUAL( false, holder.HasProperty( "prop1" ) );
270 BOOST_CHECK_EQUAL( false, holder.HasProperty( "prop2" ) );
271 BOOST_CHECK_EQUAL( false, holder.HasProperty( "prop3" ) );
272}
273
277BOOST_AUTO_TEST_CASE( SizeAndEmpty )
278{
279 // Empty holder
280 BOOST_CHECK_EQUAL( 0, m_emptyHolder.Size() );
281 BOOST_CHECK( m_emptyHolder.Empty() );
282
283 // Populated holder (from fixture: 6 properties)
284 BOOST_CHECK_EQUAL( 7, m_populatedHolder.Size() );
285 BOOST_CHECK_EQUAL( false, m_populatedHolder.Empty() );
286
287 // Add one more
288 m_populatedHolder.SetProperty( "new_prop", 999 );
289 BOOST_CHECK_EQUAL( 8, m_populatedHolder.Size() );
290
291 // Remove one
292 m_populatedHolder.RemoveProperty( "new_prop" );
293 BOOST_CHECK_EQUAL( 7, m_populatedHolder.Size() );
294}
295
299BOOST_AUTO_TEST_CASE( KeyRetrieval )
300{
301 PROPERTY_HOLDER holder;
302 holder.SetProperty( "key1", 1 );
303 holder.SetProperty( "key2", "two" );
304 holder.SetProperty( "key3", true );
305
306 auto keys = holder.GetKeys();
307 BOOST_CHECK_EQUAL( 3, keys.size() );
308
309 // Keys should contain all our added keys (order not guaranteed)
310 std::sort( keys.begin(), keys.end() );
311 std::vector<std::string> expected = { "key1", "key2", "key3" };
312 std::sort( expected.begin(), expected.end() );
313
314 BOOST_CHECK_EQUAL_COLLECTIONS( keys.begin(), keys.end(), expected.begin(), expected.end() );
315
316 // Empty holder should return empty vector
317 auto emptyKeys = m_emptyHolder.GetKeys();
318 BOOST_CHECK_EQUAL( 0, emptyKeys.size() );
319}
320
324BOOST_AUTO_TEST_CASE( TypeInformation )
325{
326 PROPERTY_HOLDER holder;
327 holder.SetProperty( "int_val", 42 );
328 holder.SetProperty( "string_val", std::string( "hello" ) );
329
330 // Existing properties should return type info
331 auto intTypeInfo = holder.GetPropertyType( "int_val" );
332 BOOST_CHECK( intTypeInfo.has_value() );
333 BOOST_CHECK( intTypeInfo->get() == typeid( int ) );
334
335 auto stringTypeInfo = holder.GetPropertyType( "string_val" );
336 BOOST_CHECK( stringTypeInfo.has_value() );
337 BOOST_CHECK( stringTypeInfo->get() == typeid( std::string ) );
338
339 // Non-existing property should return nullopt
340 auto missingTypeInfo = holder.GetPropertyType( "missing" );
341 BOOST_CHECK( !missingTypeInfo.has_value() );
342}
343
347BOOST_AUTO_TEST_CASE( ComplexObjects )
348{
349 PROPERTY_HOLDER holder;
350
351 // Store custom object
352 CustomData original( 123, "test data" );
353 holder.SetProperty( "custom", original );
354
355 // Retrieve and verify
356 auto retrieved = holder.GetProperty<CustomData>( "custom" );
357 BOOST_CHECK( retrieved.has_value() );
358 BOOST_CHECK( *retrieved == original );
359
360 // Store vector
361 std::vector<std::string> stringVec = { "one", "two", "three" };
362 holder.SetProperty( "string_vector", stringVec );
363
364 auto vecRetrieved = holder.GetProperty<std::vector<std::string>>( "string_vector" );
365 BOOST_CHECK( vecRetrieved.has_value() );
366 BOOST_CHECK_EQUAL_COLLECTIONS( vecRetrieved->begin(), vecRetrieved->end(),
367 stringVec.begin(), stringVec.end() );
368
369 // Store smart pointer
370 auto smartPtr = std::make_shared<int>( 456 );
371 holder.SetProperty( "smart_ptr", smartPtr );
372
373 auto ptrRetrieved = holder.GetProperty<std::shared_ptr<int>>( "smart_ptr" );
374 BOOST_CHECK( ptrRetrieved.has_value() );
375 BOOST_CHECK_EQUAL( **ptrRetrieved, 456 );
376 BOOST_CHECK_EQUAL( ptrRetrieved->use_count(), 3 ); // Original + stored + retrieved copy
377}
378
382BOOST_AUTO_TEST_CASE( PropertyOverwriting )
383{
384 PROPERTY_HOLDER holder;
385
386 // Set initial value
387 holder.SetProperty( "changeable", 100 );
388 BOOST_CHECK_EQUAL( holder.GetPropertyOr( "changeable", 0 ), 100 );
389 BOOST_CHECK_EQUAL( 1, holder.Size() );
390
391 // Overwrite with same type
392 holder.SetProperty( "changeable", 200 );
393 BOOST_CHECK_EQUAL( holder.GetPropertyOr( "changeable", 0 ), 200 );
394 BOOST_CHECK_EQUAL( 1, holder.Size() ); // Size shouldn't change
395
396 // Overwrite with different type
397 holder.SetProperty( "changeable", std::string( "now a string" ) );
398 BOOST_CHECK_EQUAL( holder.GetPropertyOr<std::string>( "changeable", "default" ), "now a string" );
399 BOOST_CHECK_EQUAL( 1, holder.Size() ); // Size still shouldn't change
400
401 // Original type should no longer work
402 auto intResult = holder.GetProperty<int>( "changeable" );
403 BOOST_CHECK( !intResult.has_value() );
404}
405
407
408
411BOOST_AUTO_TEST_SUITE( TEST_PROPERTY_MIXIN )
412
417{
418 TestWidget widget( "test_widget" );
419
420 // Properties set in constructor should be available
421 BOOST_CHECK_EQUAL( widget.GetPropertyOr<std::string>( "widget_name", "" ), "test_widget" );
422 BOOST_CHECK_EQUAL( widget.GetPropertyOr( "default_enabled", false ), true );
423
424 // Should be able to add new properties
425 widget.SetProperty( "runtime_prop", 42 );
426 BOOST_CHECK_EQUAL( widget.GetPropertyOr( "runtime_prop", 0 ), 42 );
427
428 // Should be able to check existence
429 BOOST_CHECK( widget.HasProperty( "widget_name" ) );
430 BOOST_CHECK( widget.HasProperty( "default_enabled" ) );
431 BOOST_CHECK( widget.HasProperty( "runtime_prop" ) );
432 BOOST_CHECK_EQUAL( false, widget.HasProperty( "missing_prop" ) );
433}
434
438BOOST_AUTO_TEST_CASE( MultipleInstances )
439{
440 TestWidget widget1( "widget1" );
441 TestWidget widget2( "widget2" );
442
443 // Each should have independent properties
444 widget1.SetProperty( "unique_to_1", 100 );
445 widget2.SetProperty( "unique_to_2", 200 );
446
447 BOOST_CHECK_EQUAL( widget1.GetPropertyOr( "unique_to_1", 0 ), 100 );
448 BOOST_CHECK_EQUAL( widget1.GetPropertyOr( "unique_to_2", 0 ), 0 ); // Should get default
449
450 BOOST_CHECK_EQUAL( widget2.GetPropertyOr( "unique_to_1", 0 ), 0 ); // Should get default
451 BOOST_CHECK_EQUAL( widget2.GetPropertyOr( "unique_to_2", 0 ), 200 );
452
453 // Names should be different
454 BOOST_CHECK_EQUAL( widget1.GetPropertyOr<std::string>( "widget_name", "" ), "widget1" );
455 BOOST_CHECK_EQUAL( widget2.GetPropertyOr<std::string>( "widget_name", "" ), "widget2" );
456}
457
461BOOST_AUTO_TEST_CASE( PropertyHolderAccess )
462{
463 TestWidget widget( "access_test" );
464
465 // Should be able to access the holder directly
466 PROPERTY_HOLDER& holder = widget.GetPropertyHolder();
467 const PROPERTY_HOLDER& constHolder = widget.GetPropertyHolder();
468
469 // Operations on holder should affect widget properties
470 holder.SetProperty( "direct_access", 999 );
471 BOOST_CHECK_EQUAL( widget.GetPropertyOr( "direct_access", 0 ), 999 );
472
473 // Should be able to use holder methods
474 BOOST_CHECK( constHolder.HasProperty( "widget_name" ) );
475 auto keys = constHolder.GetKeys();
476 BOOST_CHECK( keys.size() >= 2 ); // At least widget_name and default_enabled
477}
478
480
481
484BOOST_AUTO_TEST_SUITE( PropertyHolderEdgeCases )
485
490{
491 PROPERTY_HOLDER holder;
492
493 // Empty key should work (though not recommended)
494 holder.SetProperty( "", 42 );
495 BOOST_CHECK( holder.HasProperty( "" ) );
496 BOOST_CHECK_EQUAL( holder.GetPropertyOr( "", 0 ), 42 );
497
498 // Very long key should work
499 std::string longKey( 1000, 'x' );
500 holder.SetProperty( longKey, "long key value" );
501 BOOST_CHECK( holder.HasProperty( longKey ) );
502}
503
507BOOST_AUTO_TEST_CASE( MoveSemantics )
508{
509 PROPERTY_HOLDER holder;
510
511 // Test move construction of value
512 std::vector<int> bigVector( 1000, 42 );
513 holder.SetProperty( "big_vector", std::move( bigVector ) );
514
515 // Original vector should be moved from (implementation detail, but worth testing)
516 auto retrieved = holder.GetProperty<std::vector<int>>( "big_vector" );
517 BOOST_CHECK( retrieved.has_value() );
518 BOOST_CHECK_EQUAL( retrieved->size(), 1000 );
519 BOOST_CHECK_EQUAL( (*retrieved)[0], 42 );
520}
521
525BOOST_AUTO_TEST_CASE( NullScenarios )
526{
527 PROPERTY_HOLDER holder;
528
529 // Getting from empty holder
530 auto result = holder.GetProperty<int>( "anything" );
531 BOOST_CHECK( !result.has_value() );
532
533 // Getting with empty key
534 auto emptyResult = holder.GetProperty<int>( "" );
535 BOOST_CHECK( !emptyResult.has_value() );
536
537 // Type info for non-existing property
538 auto typeInfo = holder.GetPropertyType( "missing" );
539 BOOST_CHECK( !typeInfo.has_value() );
540
541 // Removing non-existing property
542 BOOST_CHECK_EQUAL( false, holder.RemoveProperty( "non_existing" ) );
543}
544
546
547
550BOOST_AUTO_TEST_SUITE( PropertyHolderMagicValue )
551
555BOOST_AUTO_TEST_CASE( MagicValueValidation )
556{
557 PROPERTY_HOLDER holder;
558
559 // New holder should be valid
560 BOOST_CHECK( holder.IsValid() );
561 BOOST_CHECK_EQUAL( PROPERTY_HOLDER::MAGIC_VALUE, 0x50524F5048444C52ULL );
562
563 // Should be able to use all functions when valid
564 BOOST_CHECK( holder.SetProperty( "test", 42 ) );
565 BOOST_CHECK( holder.HasProperty( "test" ) );
566 BOOST_CHECK_EQUAL( holder.GetPropertyOr( "test", 0 ), 42 );
567}
568
573{
574 // Create a PROPERTY_HOLDER
575 PROPERTY_HOLDER* original = new PROPERTY_HOLDER();
576 original->SetProperty( "test_prop", 123 );
577
578 // Cast to void* (simulating client data storage)
579 void* clientData = static_cast<void*>( original );
580
581 // Safe cast should succeed
582 PROPERTY_HOLDER* casted = PROPERTY_HOLDER::SafeCast( clientData );
583 BOOST_CHECK_NE( nullptr, casted );
584 BOOST_CHECK( casted->IsValid() );
585 BOOST_CHECK_EQUAL( casted->GetPropertyOr( "test_prop", 0 ), 123 );
586
587 // Should be the same object
588 BOOST_CHECK_EQUAL( original, casted );
589
590 // Const version should also work
591 const void* constClientData = static_cast<const void*>( original );
592 const PROPERTY_HOLDER* constCasted = PROPERTY_HOLDER::SafeCast( constClientData );
593 BOOST_CHECK_NE( nullptr, constCasted );
594 BOOST_CHECK( constCasted->IsValid() );
595
596 delete original;
597}
598
602BOOST_AUTO_TEST_CASE( SafeCastingInvalid )
603{
604 // Null pointer should return null
605 BOOST_CHECK_EQUAL( nullptr, PROPERTY_HOLDER::SafeCast( static_cast<void*>( nullptr ) ) );
606 BOOST_CHECK_EQUAL( nullptr, PROPERTY_HOLDER::SafeCast( static_cast<const void*>( nullptr ) ) );
607
608 // Random memory should return null
609 int randomInt = 12345;
610 void* randomPtr = &randomInt;
611 BOOST_CHECK_EQUAL( nullptr, PROPERTY_HOLDER::SafeCast( randomPtr ) );
612
613 // Memory with wrong magic value should return null
614 struct FakeHolder {
615 uint64_t wrong_magic = 0x1234567890ABCDEFULL;
616 int some_data = 42;
617 };
618
619 FakeHolder fake;
620 void* fakePtr = &fake;
621 BOOST_CHECK_EQUAL( nullptr, PROPERTY_HOLDER::SafeCast( fakePtr ) );
622}
623
627BOOST_AUTO_TEST_CASE( UseAfterFreeDetection )
628{
629 PROPERTY_HOLDER* holder = new PROPERTY_HOLDER();
630 holder->SetProperty( "test", 42 );
631
632 // Should be valid before deletion
633 BOOST_CHECK( holder->IsValid() );
634
635 void* ptr = static_cast<void*>( holder );
636 BOOST_CHECK_NE( nullptr, PROPERTY_HOLDER::SafeCast( ptr ) );
637
638 // Delete the holder
639 delete holder;
640
641 // Now safe cast should fail (magic value was cleared in destructor)
643}
644
648BOOST_AUTO_TEST_CASE( ClientDataHelpers )
649{
650 PROPERTY_HOLDER* holder = new PROPERTY_HOLDER();
651 BOOST_CHECK_NE( nullptr, holder );
652 BOOST_CHECK( holder->IsValid() );
653
654 // Should be able to use it
655 BOOST_CHECK( holder->SetProperty( "client_test", 999 ) );
656 BOOST_CHECK_EQUAL( holder->GetPropertyOr( "client_test", 0 ), 999 );
657
658 // Safe delete should succeed
659 BOOST_CHECK( PROPERTY_HOLDER::SafeDelete( reinterpret_cast<void*>( holder ) ) );
660
661 // Safe delete of invalid pointer should fail
662 int randomData = 42;
663 BOOST_CHECK_EQUAL( false, PROPERTY_HOLDER::SafeDelete( &randomData ) );
664 BOOST_CHECK_EQUAL( false, PROPERTY_HOLDER::SafeDelete( static_cast<void*>( nullptr ) ) );
665}
666
670BOOST_AUTO_TEST_CASE( CopyMoveConstructors )
671{
672 PROPERTY_HOLDER original;
673 original.SetProperty( "test", 42 );
674 BOOST_CHECK( original.IsValid() );
675
676 // Copy constructor
677 PROPERTY_HOLDER copied( original );
678 BOOST_CHECK( copied.IsValid() );
679 BOOST_CHECK_EQUAL( copied.GetPropertyOr( "test", 0 ), 42 );
680
681 // Move constructor
682 PROPERTY_HOLDER moved( std::move( original ) );
683 BOOST_CHECK( moved.IsValid() );
684 BOOST_CHECK_EQUAL( moved.GetPropertyOr( "test", 0 ), 42 );
685
686 // Original should still be valid (magic value preserved)
687 BOOST_CHECK( original.IsValid() );
688}
689
693BOOST_AUTO_TEST_CASE( AssignmentOperators )
694{
695 PROPERTY_HOLDER source;
696 source.SetProperty( "source_prop", 123 );
697
698 PROPERTY_HOLDER target;
699 target.SetProperty( "target_prop", 456 );
700
701 BOOST_CHECK( source.IsValid() );
702 BOOST_CHECK( target.IsValid() );
703
704 // Copy assignment
705 target = source;
706 BOOST_CHECK( target.IsValid() );
707 BOOST_CHECK_EQUAL( target.GetPropertyOr( "source_prop", 0 ), 123 );
708 BOOST_CHECK_EQUAL( false, target.HasProperty( "target_prop" ) ); // Should be overwritten
709
710 // Move assignment
711 PROPERTY_HOLDER another;
712 another.SetProperty( "another_prop", 789 );
713
714 target = std::move( another );
715 BOOST_CHECK( target.IsValid() );
716 BOOST_CHECK_EQUAL( target.GetPropertyOr( "another_prop", 0 ), 789 );
717 BOOST_CHECK( another.IsValid() ); // Magic value preserved
718}
719
723BOOST_AUTO_TEST_CASE( InvalidObjectBehavior )
724{
725 // Create a fake PROPERTY_HOLDER with wrong magic value
726 struct FakePropertyHolder {
727 uint64_t wrong_magic = 0xDEADBEEF;
728 std::unordered_map<std::string, std::any> fake_properties;
729 };
730
731 FakePropertyHolder fake;
732 PROPERTY_HOLDER* fakeHolder = reinterpret_cast<PROPERTY_HOLDER*>( &fake );
733
734 // All methods should fail gracefully
735 BOOST_CHECK_EQUAL( false, fakeHolder->IsValid() );
736 BOOST_CHECK_EQUAL( false, fakeHolder->SetProperty( "test", 42 ) );
737 BOOST_CHECK_EQUAL( false, fakeHolder->HasProperty( "anything" ) );
738 BOOST_CHECK_EQUAL( false, fakeHolder->RemoveProperty( "anything" ) );
739 BOOST_CHECK_EQUAL( false, fakeHolder->Clear() );
740 BOOST_CHECK_EQUAL( 0, fakeHolder->Size() );
741 BOOST_CHECK( fakeHolder->Empty() ); // Returns true for invalid objects
742 BOOST_CHECK_EQUAL( 0, fakeHolder->GetKeys().size() );
743 BOOST_CHECK_EQUAL( false, fakeHolder->HasPropertyOfType<int>( "anything" ) );
744
745 // GetProperty should return nullopt
746 auto result = fakeHolder->GetProperty<int>( "anything" );
747 BOOST_CHECK( !result.has_value() );
748
749 // GetPropertyOr should return default
750 BOOST_CHECK_EQUAL( fakeHolder->GetPropertyOr( "anything", 999 ), 999 );
751
752 // GetPropertyType should return nullopt
753 auto typeInfo = fakeHolder->GetPropertyType( "anything" );
754 BOOST_CHECK( !typeInfo.has_value() );
755}
756
const char * name
Definition: DXF_plotter.cpp:62
bool operator==(const wxAuiPaneInfo &aLhs, const wxAuiPaneInfo &aRhs)
bool SetProperty(const std::string &aKey, T &&aValue)
Set a property with the given key and value.
static bool SafeDelete(void *aPtr) noexcept
Safely delete a PROPERTY_HOLDER from client data.
std::optional< std::reference_wrapper< const std::type_info > > GetPropertyType(const std::string &aKey) const
Get the type information for a property.
bool Empty() const
Check if there are no properties stored.
std::vector< std::string > GetKeys() const
Get all property keys.
static PROPERTY_HOLDER * SafeCast(void *aPtr) noexcept
Safely cast a void pointer to PROPERTY_HOLDER*.
bool RemoveProperty(const std::string &aKey)
Remove a property.
static constexpr uint64_t MAGIC_VALUE
Magic value for memory validation (ASCII: "PROP" + "HLDR")
std::optional< T > GetProperty(const std::string &aKey) const
Get a property value with type checking.
T GetPropertyOr(const std::string &aKey, T &&aDefaultValue) const
Get a property value with a default fallback.
bool HasPropertyOfType(const std::string &aKey) const
Check if a property exists and has the expected type.
bool HasProperty(const std::string &aKey) const
Check if a property exists.
bool IsValid() const noexcept
Check if this instance has a valid magic value.
bool Clear()
Clear all properties.
size_t Size() const
Get the number of stored properties.
Mixin class to add property support to any class.
void SetProperty(const std::string &aKey, T &&aValue)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_CHECK_EQUAL(ret, c.m_exp_result)
BOOST_AUTO_TEST_SUITE_END()
bool copied
bool moved
VECTOR3I expected(15, 30, 45)
BOOST_AUTO_TEST_CASE(BasicSetGet)
Declare the test suite.