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 along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
22#include <wx/gdicmn.h> // wxPoint
23
24#include <inspectable.h>
26
27using namespace std;
28
29class A : public INSPECTABLE
30{
31public:
32 virtual void setA( int a ) = 0;
33 virtual int getA() const = 0;
34 virtual const int& getA2() const { return m_a; }
35
36 virtual void setPoint( const wxPoint& p ) { m_p = p; }
37 void setPoint2( wxPoint& p ) { m_p = p; }
38 void setPoint3( wxPoint p ) { m_p = p; }
39 void setPoint4( wxPoint p ) { m_p = p; }
40
41 const wxPoint& getPoint() const { return m_p; }
42 wxPoint getPoint2() const { return m_p; }
43 wxPoint getPoint3() { return m_p; }
44 const wxPoint& getPoint4() const { return m_p; }
45
46protected:
47 int m_a = 0;
48 wxPoint m_p;
49};
50
51class B : public A
52{
53public:
54 void setA( int a ) override { m_a = a; }
55 int getA() const override { return m_a; }
56
57 void setC( int a ) { m_c = a; }
58 int getC() const { return m_c; }
59
60private:
61 int m_c = 0;
62};
63
64class C
65{
66public:
67 bool getBool() const { return m_bool; }
68 void setBool( bool a ) { m_bool = a; }
69
70 int getNew() const { return m_m; }
71 void setNew( int m ) { m_m = m; }
72
73 int m_m = 0;
74 bool m_bool = false;
75};
76
77enum enum_glob { TEST1 = 0, TEST2 = 1, TEST3 = 4 };
78
79class D : public A, public C
80{
81public:
82 enum enum_class { TESTA = 0, TESTB = 1, TESTC = 4 };
83
84 // note 2x factor
85 virtual void setA( int a ) override { m_aa = 2 * a; }
86 virtual int getA() const override { return m_aa; }
87
88 enum_glob getGlobEnum() const { return m_enum_glob; }
89 void setGlobEnum( enum_glob val ) { m_enum_glob = val; }
90
92 void setClassEnum( enum_class val ) { m_enum_class = val; }
93
94 void setCond( int a ) { m_cond = a; }
95 int getCond() const { return m_cond; }
96
99 int m_aa = 0;
100 int m_cond = 0;
101};
102
103class E : public D
104{
105};
106
107static struct ENUM_GLOB_DESC
108{
110 {
112 .Map( enum_glob::TEST1, "TEST1" )
113 .Map( enum_glob::TEST2, "TEST2" )
114 .Map( enum_glob::TEST3, "TEST3" );
115 }
117
119
120static struct CLASS_A_DESC
121{
123 {
125 propMgr.AddProperty( new PROPERTY<A, int>( "A", &A::setA, &A::getA ) );
126 propMgr.AddProperty( new PROPERTY<A, int>( "A2", &A::setA, &A::getA2 ) );
127 propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point", &A::setPoint, &A::getPoint ) );
128 propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point2", &A::setPoint, &A::getPoint2 ) );
129
130 // TODO non-const getters are not supported
131 //propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point3", &A::setPoint3, &A::getPoint3 ) );
132 propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point4", &A::setPoint4, &A::getPoint4 ) );
133 }
135
136static struct CLASS_B_DESC
137{
139 {
141 propMgr.InheritsAfter( TYPE_HASH( B ), TYPE_HASH( A ) );
142 propMgr.AddProperty( new PROPERTY<B, int>( "C", &B::setC, &B::getC ) );
143 }
145
146static struct CLASS_C_DESC
147{
149 {
151 propMgr.AddProperty( new PROPERTY<C, bool>( "bool", &C::setBool, &C::getBool ) );
152 propMgr.AddProperty( new PROPERTY<C, int>( "new", &C::setNew, &C::getNew ) );
153 }
155
156static struct CLASS_D_DESC
157{
159 {
161 .Map( D::enum_class::TESTA, "TESTA" )
162 .Map( D::enum_class::TESTB, "TESTB" )
163 .Map( D::enum_class::TESTC, "TESTC" );
164
168 propMgr.AddProperty( new PROPERTY<D, wxPoint, A>( "point_alias", &D::setPoint, &D::getPoint ) );
169
170 propMgr.ReplaceProperty( TYPE_HASH( C ), "bool",
171 new PROPERTY<D, bool, C>( "replaced_bool", &D::setBool, &D::getBool ) );
172
173 // lines below are needed to indicate multiple inheritance
174 propMgr.AddTypeCast( new TYPE_CAST<D, A> );
175 propMgr.AddTypeCast( new TYPE_CAST<D, C> );
176 propMgr.InheritsAfter( TYPE_HASH( D ), TYPE_HASH( A ) );
177 propMgr.InheritsAfter( TYPE_HASH( D ), TYPE_HASH( C ) );
178
179 auto cond = new PROPERTY<D, int>( "cond", &D::setCond, &D::getCond );
180 cond->SetAvailableFunc( [=](INSPECTABLE* aItem)->bool {
181 return *aItem->Get<enum_glob>( "enumGlob" ) == enum_glob::TEST1;
182 } );
183 propMgr.AddProperty( cond );
184 }
186
187static struct CLASS_E_DESC
188{
190 {
191 wxArrayInt values;
192 values.Add( enum_glob::TEST1 );
193 values.Add( enum_glob::TEST3 );
194 wxArrayString labels;
195 labels.Add( "T1" );
196 labels.Add( "T3" );
197 wxPGChoices newChoices( labels, values );
198
200 auto prop = new PROPERTY_ENUM<E, enum_glob, D>( "enumGlob",
202 prop->SetChoices( newChoices );
203 propMgr.ReplaceProperty( TYPE_HASH( D ), "enumGlob", prop );
204 }
206
208
209
211{
213 ptr( nullptr ),
214 propMgr( PROPERTY_MANAGER::Instance() )
215 {
216 }
217
222};
223
224BOOST_FIXTURE_TEST_SUITE( Properties, PropertiesFixture )
225
227{
228 propMgr.Rebuild();
229}
230
231// Basic Set() & Get()
233{
234 ptr = &b;
235 ptr->Set( "A", 100 );
236 ptr->Set( "point", wxPoint( 100, 200 ) );
237 BOOST_CHECK_EQUAL( *ptr->Get<int>( "A" ), 100 );
238 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point" ), wxPoint( 100, 200 ) );
239
240 ptr = &d;
241 ptr->Set( "enumGlob", enum_glob::TEST2 );
242 ptr->Set( "enumClass", D::enum_class::TESTC );
243 BOOST_CHECK_EQUAL( *ptr->Get<enum_glob>( "enumGlob" ), enum_glob::TEST2 );
244 BOOST_CHECK_EQUAL( *ptr->Get<D::enum_class>( "enumClass" ), D::enum_class::TESTC );
245}
246
247// Virtual methods
248BOOST_AUTO_TEST_CASE( VirtualMethods )
249{
250 // D::setA() saves a doubled value, while B::setA() saves unmodified value
251 ptr = &b;
252 ptr->Set( "A", 23 );
253 BOOST_CHECK_EQUAL( *ptr->Get<int>( "A" ), 23 ); // unmodified == 23
254
255 ptr = &d;
256 ptr->Set( "A", 23 );
257 BOOST_CHECK_EQUAL( *ptr->Get<int>( "A" ), 46 ); // doubled == 46
258}
259
260// Non-existing properties
261BOOST_AUTO_TEST_CASE( NotexistingProperties )
262{
263 ptr = &d;
264 BOOST_CHECK_EQUAL( ptr->Set<int>( "does not exist", 5 ), false );
265 BOOST_CHECK_EQUAL( static_cast<bool>( ptr->Get<int>( "neither" ) ), false );
266}
267
268// Request data using incorrect type
269BOOST_AUTO_TEST_CASE( IncorrectType )
270{
271 ptr = &d;
272 BOOST_CHECK_THROW( ptr->Get<wxPoint>( "A" ), std::invalid_argument );
273}
274
275// Type-casting (for types with multiple inheritance)
277{
278 ptr = &d;
279 A* D_to_A = static_cast<A*>( propMgr.TypeCast( ptr, TYPE_HASH( D ), TYPE_HASH( A ) ) );
280 BOOST_CHECK_EQUAL( D_to_A, dynamic_cast<A*>( ptr ) );
281
282 C* D_to_C = static_cast<C*>( propMgr.TypeCast( ptr, TYPE_HASH( D ), TYPE_HASH( C ) ) );
283 BOOST_CHECK_EQUAL( D_to_C, dynamic_cast<C*>( ptr ) );
284}
285
287{
288 PROPERTY_BASE* prop = propMgr.GetProperty( TYPE_HASH( D ), "enumGlob" );
289 BOOST_CHECK( prop->HasChoices() );
290
291 wxArrayInt values;
292 values.Add( enum_glob::TEST1 );
293 values.Add( enum_glob::TEST2 );
294 values.Add( enum_glob::TEST3 );
295 wxArrayString labels;
296 labels.Add( "TEST1" );
297 labels.Add( "TEST2" );
298 labels.Add( "TEST3" );
299
300 const wxPGChoices& v = prop->Choices();
301 BOOST_CHECK_EQUAL( v.GetCount(), values.GetCount() );
302 BOOST_CHECK_EQUAL( v.GetCount(), labels.GetCount() );
303
304 for (unsigned int i = 0; i < values.GetCount(); ++i )
305 {
306 BOOST_CHECK_EQUAL( v.GetValue( i ), values[i] );
307 }
308
309 for (unsigned int i = 0; i < labels.GetCount(); ++i )
310 {
311 BOOST_CHECK_EQUAL( v.GetLabel( i ), labels[i] );
312 }
313
314 D item ;
315 wxString str;
316
317 item.setGlobEnum( static_cast<enum_glob>( -1 ) );
318 wxAny any = item.Get( prop );
319 BOOST_CHECK_EQUAL( any.GetAs<wxString>( &str ), false );
320
322 any = item.Get( prop );
323 BOOST_CHECK_EQUAL( any.GetAs<wxString>( &str ), true );
324}
325
327{
328 PROPERTY_BASE* prop = propMgr.GetProperty( TYPE_HASH( D ), "enumClass" );
329 BOOST_CHECK( prop->HasChoices() );
330
331 wxArrayInt values;
332 values.Add( D::enum_class::TESTA );
333 values.Add( D::enum_class::TESTB );
334 values.Add( D::enum_class::TESTC );
335 wxArrayString labels;
336 labels.Add( "TESTA" );
337 labels.Add( "TESTB" );
338 labels.Add( "TESTC" );
339
340 const wxPGChoices& v = prop->Choices();
341 BOOST_CHECK_EQUAL( v.GetCount(), values.GetCount() );
342 BOOST_CHECK_EQUAL( v.GetCount(), labels.GetCount() );
343
344 for (unsigned int i = 0; i < values.GetCount(); ++i )
345 {
346 BOOST_CHECK_EQUAL( v.GetValue( i ), values[i] );
347 }
348
349 for (unsigned int i = 0; i < labels.GetCount(); ++i )
350 {
351 BOOST_CHECK_EQUAL( v.GetLabel( i ), labels[i] );
352 }
353}
354
355// Tests conditional properties (which may depend on values or other properties)
356BOOST_AUTO_TEST_CASE( Availability )
357{
358 PROPERTY_BASE* propCond = propMgr.GetProperty( TYPE_HASH( D ), "cond" );
359 ptr = &d;
360
361 // "cond" property is available only when "a" field is greater than 50 //TODO fix desc
362 d.setGlobEnum( enum_glob::TEST3 );
363 BOOST_CHECK( !propCond->Available( ptr ) );
364
365 d.setGlobEnum( enum_glob::TEST1 );
366 BOOST_CHECK( propCond->Available( ptr ) );
367}
368
369// Using a different name for a parent property
371{
372 ptr = &d;
373
374 ptr->Set( "point", wxPoint( 100, 100 ) );
375 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point" ), wxPoint( 100, 100 ) );
376 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point_alias" ), wxPoint( 100, 100 ) );
377
378 ptr->Set( "point_alias", wxPoint( 300, 300 ) );
379 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point" ), wxPoint( 300, 300 ) );
380 BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point_alias" ), wxPoint( 300, 300 ) );
381}
382
383// Property renaming
385{
386 PROPERTY_BASE* prop;
387
388 prop = propMgr.GetProperty( TYPE_HASH( D ), "bool" );
389 BOOST_CHECK_EQUAL( prop, nullptr );
390
391 prop = propMgr.GetProperty( TYPE_HASH( D ), "replaced_bool" );
392 BOOST_CHECK( prop );
393}
394
395// Different subset of enum values for a property
396BOOST_AUTO_TEST_CASE( AlternativeEnum )
397{
398 PROPERTY_BASE* prop = propMgr.GetProperty( TYPE_HASH( E ), "enumGlob" );
399 BOOST_CHECK( prop->HasChoices() );
400
401 wxArrayInt values;
402 values.Add( enum_glob::TEST1 );
403 values.Add( enum_glob::TEST3 );
404 wxArrayString labels;
405 labels.Add( "T1" );
406 labels.Add( "T3" );
407
408 const wxPGChoices& v = prop->Choices();
409 BOOST_CHECK_EQUAL( v.GetCount(), values.GetCount() );
410 BOOST_CHECK_EQUAL( v.GetCount(), labels.GetCount() );
411
412 for (unsigned int i = 0; i < values.GetCount(); ++i )
413 {
414 BOOST_CHECK_EQUAL( v.GetValue( i ), values[i] );
415 }
416
417 for (unsigned int i = 0; i < labels.GetCount(); ++i )
418 {
419 BOOST_CHECK_EQUAL( v.GetLabel( i ), labels[i] );
420 }
421}
422
int m_a
void setPoint2(wxPoint &p)
wxPoint m_p
virtual const int & getA2() const
virtual void setPoint(const wxPoint &p)
wxPoint getPoint3()
const wxPoint & getPoint4() const
virtual int getA() const =0
void setPoint3(wxPoint p)
virtual void setA(int a)=0
void setPoint4(wxPoint p)
wxPoint getPoint2() const
const wxPoint & getPoint() const
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)
enum_class
@ TESTC
@ TESTA
@ TESTB
int m_cond
int m_aa
void setClassEnum(enum_class val)
static ENUM_MAP< T > & Instance()
Definition: property.h:663
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:36
wxAny Get(PROPERTY_BASE *aProperty) const
Definition: inspectable.h:99
virtual bool HasChoices() const
Return true if this PROPERTY has a limited set of possible values.
Definition: property.h:241
bool Available(INSPECTABLE *aObject) const
Return true if aObject offers this PROPERTY.
Definition: property.h:249
virtual const wxPGChoices & Choices() const
Return a limited set of possible values (e.g.
Definition: property.h:223
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:85
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:87
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.
STL namespace.
#define TYPE_HASH(x)
Definition: property.h:71
#define ENUM_TO_WXANY(type)
Macro to define read-only fields (no setter method available)
Definition: property.h:765
PROPERTY_MANAGER & propMgr
BOOST_AUTO_TEST_SUITE_END()
static struct ENUM_GLOB_DESC _ENUM_GLOB_DESC
static struct CLASS_A_DESC _CLASS_A_DESC
static struct CLASS_D_DESC _CLASS_D_DESC
enum_glob
@ TEST3
@ TEST1
@ TEST2
BOOST_AUTO_TEST_CASE(Init)
static struct CLASS_C_DESC _CLASS_C_DESC
static struct CLASS_E_DESC _CLASS_E_DESC
static struct CLASS_B_DESC _CLASS_B_DESC