KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_property.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 (C) 2020 CERN
5 * @author Maciej Suminski <[email protected]>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
22#include <wx/gdicmn.h> // wxPoint
23
24#include <inspectable_impl.h>
26
27using namespace std;
28
29namespace
30{
31class A : public INSPECTABLE
32{
33public:
34 virtual void setA( int a ) = 0;
35 virtual int getA() const = 0;
36 virtual const int& getA2() const { return m_a; }
37
38 virtual void setPoint( const wxPoint& p ) { m_p = p; }
39 void setPoint2( wxPoint& p ) { m_p = p; }
40 void setPoint3( wxPoint p ) { m_p = p; }
41 void setPoint4( wxPoint p ) { m_p = p; }
42
43 const wxPoint& getPoint() const { return m_p; }
44 wxPoint getPoint2() const { return m_p; }
45 wxPoint getPoint3() { return m_p; }
46 const wxPoint& getPoint4() const { return m_p; }
47
48protected:
49 int m_a = 0;
50 wxPoint m_p;
51};
52} // namespace
53
54class B : public A
55{
56public:
57 void setA( int a ) override { m_a = a; }
58 int getA() const override { return m_a; }
59
60 void setC( int a ) { m_c = a; }
61 int getC() const { return m_c; }
62
63private:
64 int m_c = 0;
65};
66
67class C
68{
69public:
70 bool getBool() const { return m_bool; }
71 void setBool( bool a ) { m_bool = a; }
72
73 int getNew() const { return m_m; }
74 void setNew( int m ) { m_m = m; }
75
76 int m_m = 0;
77 bool m_bool = false;
78};
79
80enum enum_glob { TEST1 = 0, TEST2 = 1, TEST3 = 4 };
81
82class D : public A, public C
83{
84public:
85 enum enum_class { TESTA = 0, TESTB = 1, TESTC = 4 };
86
87 // note 2x factor
88 virtual void setA( int a ) override { m_aa = 2 * a; }
89 virtual int getA() const override { return m_aa; }
90
91 enum_glob getGlobEnum() const { return m_enum_glob; }
92 void setGlobEnum( enum_glob val ) { m_enum_glob = val; }
93
95 void setClassEnum( enum_class val ) { m_enum_class = val; }
96
97 void setCond( int a ) { m_cond = a; }
98 int getCond() const { return m_cond; }
99
102 int m_aa = 0;
103 int m_cond = 0;
104};
105
106class E : public D
107{
108};
109
110static struct ENUM_GLOB_DESC
111{
113 {
115 .Map( enum_glob::TEST1, "TEST1" )
116 .Map( enum_glob::TEST2, "TEST2" )
117 .Map( enum_glob::TEST3, "TEST3" );
118 }
120
122
123static struct CLASS_A_DESC
124{
126 {
128 propMgr.AddProperty( new PROPERTY<A, int>( "A", &A::setA, &A::getA ) );
129 propMgr.AddProperty( new PROPERTY<A, int>( "A2", &A::setA, &A::getA2 ) );
130 propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point", &A::setPoint, &A::getPoint ) );
131 propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point2", &A::setPoint, &A::getPoint2 ) );
132
133 // TODO non-const getters are not supported
134 //propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point3", &A::setPoint3, &A::getPoint3 ) );
135 propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point4", &A::setPoint4, &A::getPoint4 ) );
136 }
138
139static struct CLASS_B_DESC
140{
142 {
144 propMgr.InheritsAfter( TYPE_HASH( B ), TYPE_HASH( A ) );
145 propMgr.AddProperty( new PROPERTY<B, int>( "C", &B::setC, &B::getC ) );
146 }
148
149static struct CLASS_C_DESC
150{
152 {
154 propMgr.AddProperty( new PROPERTY<C, bool>( "bool", &C::setBool, &C::getBool ) );
155 propMgr.AddProperty( new PROPERTY<C, int>( "new", &C::setNew, &C::getNew ) );
156 }
158
159static struct CLASS_D_DESC
160{
162 {
164 .Map( D::enum_class::TESTA, "TESTA" )
165 .Map( D::enum_class::TESTB, "TESTB" )
166 .Map( D::enum_class::TESTC, "TESTC" );
167
169 propMgr.AddProperty( new PROPERTY_ENUM<D, enum_glob>( "enumGlob", &D::setGlobEnum, &D::getGlobEnum ) );
170 propMgr.AddProperty( new PROPERTY_ENUM<D, D::enum_class>( "enumClass", &D::setClassEnum, &D::getClassEnum ) );
171 propMgr.AddProperty( new PROPERTY<D, wxPoint, A>( "point_alias", &D::setPoint, &D::getPoint ) );
172
173 propMgr.ReplaceProperty( TYPE_HASH( C ), "bool",
174 new PROPERTY<D, bool, C>( "replaced_bool", &D::setBool, &D::getBool ) );
175
176 // lines below are needed to indicate multiple inheritance
177 propMgr.AddTypeCast( new TYPE_CAST<D, A> );
178 propMgr.AddTypeCast( new TYPE_CAST<D, C> );
179 propMgr.InheritsAfter( TYPE_HASH( D ), TYPE_HASH( A ) );
180 propMgr.InheritsAfter( TYPE_HASH( D ), TYPE_HASH( C ) );
181
182 propMgr.AddProperty( new PROPERTY<D, int>( "cond",
183 &D::setCond, &D::getCond ) )
184 .SetAvailableFunc( [=]( INSPECTABLE* aItem )->bool
185 {
186 return *aItem->Get<enum_glob>( "enumGlob" ) == enum_glob::TEST1;
187 } );
188 }
190
191static struct CLASS_E_DESC
192{
194 {
195 wxArrayInt values;
196 values.Add( enum_glob::TEST1 );
197 values.Add( enum_glob::TEST3 );
198 wxArrayString labels;
199 labels.Add( "T1" );
200 labels.Add( "T3" );
201 wxPGChoices newChoices( labels, values );
202
204 auto prop = new PROPERTY_ENUM<E, enum_glob, D>( "enumGlob",
206 prop->SetChoices( newChoices );
207 propMgr.ReplaceProperty( TYPE_HASH( D ), "enumGlob", prop );
208 }
210
211ENUM_TO_WXANY( D::enum_class );
212
213
215{
217 ptr( nullptr ),
218 propMgr( PROPERTY_MANAGER::Instance() )
219 {
220 }
221
224 A* ptr;
226};
227
228BOOST_FIXTURE_TEST_SUITE( Properties, PropertiesFixture )
229
230// Basic Set() & Get()
232{
233 ptr = &b;
234 ptr->Set( "A", 100 );
235 ptr->Set( "point", wxPoint( 100, 200 ) );
236 BOOST_CHECK_EQUAL( *ptr->Get<int>( "A" ), 100 );
237 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point" ), wxPoint( 100, 200 ) );
238
239 ptr = &d;
240 ptr->Set( "enumGlob", enum_glob::TEST2 );
241 ptr->Set( "enumClass", D::enum_class::TESTC );
242 BOOST_CHECK_EQUAL( *ptr->Get<enum_glob>( "enumGlob" ), enum_glob::TEST2 );
243 BOOST_CHECK_EQUAL( *ptr->Get<D::enum_class>( "enumClass" ), D::enum_class::TESTC );
244}
245
246// Virtual methods
247BOOST_AUTO_TEST_CASE( VirtualMethods )
248{
249 // D::setA() saves a doubled value, while B::setA() saves unmodified value
250 ptr = &b;
251 ptr->Set( "A", 23 );
252 BOOST_CHECK_EQUAL( *ptr->Get<int>( "A" ), 23 ); // unmodified == 23
253
254 ptr = &d;
255 ptr->Set( "A", 23 );
256 BOOST_CHECK_EQUAL( *ptr->Get<int>( "A" ), 46 ); // doubled == 46
257}
258
259// Non-existing properties
260BOOST_AUTO_TEST_CASE( NotexistingProperties )
261{
262 ptr = &d;
263 BOOST_CHECK_EQUAL( ptr->Set<int>( "does not exist", 5 ), false );
264 BOOST_CHECK_EQUAL( static_cast<bool>( ptr->Get<int>( "neither" ) ), false );
265}
266
267// Request data using incorrect type
268BOOST_AUTO_TEST_CASE( IncorrectType )
269{
270 ptr = &d;
271 BOOST_CHECK_THROW( ptr->Get<wxPoint>( "A" ), std::invalid_argument );
272}
273
274// Type-casting (for types with multiple inheritance)
276{
277 ptr = &d;
278 A* D_to_A = static_cast<A*>( propMgr.TypeCast( ptr, TYPE_HASH( D ), TYPE_HASH( A ) ) );
279 BOOST_CHECK_EQUAL( D_to_A, dynamic_cast<A*>( ptr ) );
280
281 C* D_to_C = static_cast<C*>( propMgr.TypeCast( ptr, TYPE_HASH( D ), TYPE_HASH( C ) ) );
282 BOOST_CHECK_EQUAL( D_to_C, dynamic_cast<C*>( ptr ) );
283}
284
286{
287 PROPERTY_BASE* prop = propMgr.GetProperty( TYPE_HASH( D ), "enumGlob" );
288 BOOST_CHECK( prop->HasChoices() );
289
290 wxArrayInt values;
291 values.Add( enum_glob::TEST1 );
292 values.Add( enum_glob::TEST2 );
293 values.Add( enum_glob::TEST3 );
294 wxArrayString labels;
295 labels.Add( "TEST1" );
296 labels.Add( "TEST2" );
297 labels.Add( "TEST3" );
298
299 const wxPGChoices& v = prop->Choices();
300 BOOST_CHECK_EQUAL( v.GetCount(), values.GetCount() );
301 BOOST_CHECK_EQUAL( v.GetCount(), labels.GetCount() );
302
303 for (unsigned int i = 0; i < values.GetCount(); ++i )
304 {
305 BOOST_CHECK_EQUAL( v.GetValue( i ), values[i] );
306 }
307
308 for (unsigned int i = 0; i < labels.GetCount(); ++i )
309 {
310 BOOST_CHECK_EQUAL( v.GetLabel( i ), labels[i] );
311 }
312
313 D item ;
314 wxString str;
315
316 item.setGlobEnum( static_cast<enum_glob>( -1 ) );
317 wxAny any = item.Get( prop );
318 BOOST_CHECK_EQUAL( any.GetAs<wxString>( &str ), false );
319
321 any = item.Get( prop );
322 BOOST_CHECK_EQUAL( any.GetAs<wxString>( &str ), true );
323}
324
326{
327 PROPERTY_BASE* prop = propMgr.GetProperty( TYPE_HASH( D ), "enumClass" );
328 BOOST_CHECK( prop->HasChoices() );
329
330 wxArrayInt values;
331 values.Add( D::enum_class::TESTA );
332 values.Add( D::enum_class::TESTB );
333 values.Add( D::enum_class::TESTC );
334 wxArrayString labels;
335 labels.Add( "TESTA" );
336 labels.Add( "TESTB" );
337 labels.Add( "TESTC" );
338
339 const wxPGChoices& v = prop->Choices();
340 BOOST_CHECK_EQUAL( v.GetCount(), values.GetCount() );
341 BOOST_CHECK_EQUAL( v.GetCount(), labels.GetCount() );
342
343 for (unsigned int i = 0; i < values.GetCount(); ++i )
344 {
345 BOOST_CHECK_EQUAL( v.GetValue( i ), values[i] );
346 }
347
348 for (unsigned int i = 0; i < labels.GetCount(); ++i )
349 {
350 BOOST_CHECK_EQUAL( v.GetLabel( i ), labels[i] );
351 }
352}
353
354// Tests conditional properties (which may depend on values or other properties)
355BOOST_AUTO_TEST_CASE( Availability )
356{
357 PROPERTY_BASE* propCond = propMgr.GetProperty( TYPE_HASH( D ), "cond" );
358 ptr = &d;
359
360 // "cond" property is available only when "a" field is greater than 50 //TODO fix desc
361 d.setGlobEnum( enum_glob::TEST3 );
362 BOOST_CHECK( !propCond->Available( ptr ) );
363
364 d.setGlobEnum( enum_glob::TEST1 );
365 BOOST_CHECK( propCond->Available( ptr ) );
366}
367
368// Using a different name for a parent property
370{
371 ptr = &d;
372
373 ptr->Set( "point", wxPoint( 100, 100 ) );
374 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point" ), wxPoint( 100, 100 ) );
375 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point_alias" ), wxPoint( 100, 100 ) );
376
377 ptr->Set( "point_alias", wxPoint( 300, 300 ) );
378 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point" ), wxPoint( 300, 300 ) );
379 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point_alias" ), wxPoint( 300, 300 ) );
380}
381
382// Property renaming
384{
385 PROPERTY_BASE* prop;
386
387 prop = propMgr.GetProperty( TYPE_HASH( D ), "bool" );
388 BOOST_CHECK_EQUAL( prop, nullptr );
389
390 prop = propMgr.GetProperty( TYPE_HASH( D ), "replaced_bool" );
391 BOOST_CHECK( prop );
392}
393
394// Different subset of enum values for a property
395BOOST_AUTO_TEST_CASE( AlternativeEnum )
396{
397 PROPERTY_BASE* prop = propMgr.GetProperty( TYPE_HASH( E ), "enumGlob" );
398 BOOST_CHECK( prop->HasChoices() );
399
400 wxArrayInt values;
401 values.Add( enum_glob::TEST1 );
402 values.Add( enum_glob::TEST3 );
403 wxArrayString labels;
404 labels.Add( "T1" );
405 labels.Add( "T3" );
406
407 const wxPGChoices& v = prop->Choices();
408 BOOST_CHECK_EQUAL( v.GetCount(), values.GetCount() );
409 BOOST_CHECK_EQUAL( v.GetCount(), labels.GetCount() );
410
411 for (unsigned int i = 0; i < values.GetCount(); ++i )
412 {
413 BOOST_CHECK_EQUAL( v.GetValue( i ), values[i] );
414 }
415
416 for (unsigned int i = 0; i < labels.GetCount(); ++i )
417 {
418 BOOST_CHECK_EQUAL( v.GetLabel( i ), labels[i] );
419 }
420}
421
422// Duplicate registration should not crash or leak
423BOOST_AUTO_TEST_CASE( DuplicateProperty )
424{
425 PROPERTY_BASE* original = propMgr.GetProperty( TYPE_HASH( B ), "C" );
426 BOOST_REQUIRE( original );
427
428 int origValue = 42;
429 b.setC( origValue );
430
431 // Attempt to register a duplicate property with the same name and owner
432 PROPERTY_BASE& returned = propMgr.AddProperty( new PROPERTY<B, int>( "C", &B::setC, &B::getC ) );
433
434 // AddProperty should return the existing property, not the new one
435 BOOST_CHECK_EQUAL( &returned, original );
436
437 // The original property should still function correctly
438 BOOST_CHECK_EQUAL( *b.Get<int>( "C" ), origValue );
439
440 // Rebuild should succeed without crashing on dangling pointers
441 propMgr.Rebuild();
442
443 PROPERTY_BASE* afterRebuild = propMgr.GetProperty( TYPE_HASH( B ), "C" );
444 BOOST_CHECK_EQUAL( afterRebuild, original );
445}
446
int m_c
int getA() const override
void setC(int a)
void setA(int a) override
int getC() const
bool m_bool
int m_m
bool getBool() const
void setBool(bool a)
void setNew(int m)
int getNew() const
virtual int getA() const override
int getCond() const
enum_class m_enum_class
enum_glob m_enum_glob
enum_glob getGlobEnum() const
void setCond(int a)
enum_class getClassEnum() const
virtual void setA(int a) override
void setGlobEnum(enum_glob val)
int m_cond
int m_aa
void setClassEnum(enum_class val)
static ENUM_MAP< T > & Instance()
Definition property.h:792
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:39
wxAny Get(PROPERTY_BASE *aProperty) const
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:275
virtual bool HasChoices() const
Return true if this PROPERTY has a limited set of possible values.
Definition property.h:259
bool Available(INSPECTABLE *aObject) const
Return true if aObject offers this PROPERTY.
Definition property.h:267
virtual const wxPGChoices & Choices() const
Return a limited set of possible values (e.g.
Definition property.h:239
Provide class metadata.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
PROPERTY_BASE & ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
void AddTypeCast(TYPE_CAST_BASE *aCast)
Register a type converter.
A type-safe container of any type.
Definition ki_any.h:92
STL namespace.
#define TYPE_HASH(x)
Macro to generate unique identifier for a type.
Definition property.h:74
#define ENUM_TO_WXANY(type)
Definition property.h:899
#define D(x)
Definition ptree.cpp:37
PROPERTY_MANAGER & propMgr
static VECTOR2D getPoint(const float *aPointCoordinates)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
static struct CLASS_A_DESC _CLASS_A_DESC
static struct CLASS_D_DESC _CLASS_D_DESC
static struct ENUM_GLOB_DESC s_ENUM_GLOB_DESC
enum_glob
@ TEST3
@ TEST1
@ TEST2
static struct CLASS_C_DESC _CLASS_C_DESC
static struct CLASS_E_DESC _CLASS_E_DESC
BOOST_AUTO_TEST_CASE(SetGet)
static struct CLASS_B_DESC _CLASS_B_DESC
BOOST_CHECK_EQUAL(result, "25.4")