KiCad PCB EDA Suite
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 <maciej.suminski@cern.ch>
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>
25 #include <property_mgr.h>
26 
27 using namespace std;
28 
29 class A : public INSPECTABLE
30 {
31 public:
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 
46 protected:
47  int m_a = 0;
48  wxPoint m_p;
49 };
50 
51 class B : public A
52 {
53 public:
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 
60 private:
61  int m_c = 0;
62 };
63 
64 class C : public INSPECTABLE
65 {
66 public:
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 
77 enum enum_glob { TEST1 = 0, TEST2 = 1, TEST3 = 4 };
78 
79 class D : public A, public C
80 {
81 public:
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 
91  enum_class getClassEnum() const { return m_enum_class; }
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 
103 class E : public D
104 {
105 };
106 
107 static 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 
120 static 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  propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point3", &A::setPoint3, &A::getPoint3 ) );
131  propMgr.AddProperty( new PROPERTY<A, wxPoint>( "point4", &A::setPoint4, &A::getPoint4 ) );
132  }
133 } _CLASS_A_DESC;
134 
135 static struct CLASS_B_DESC
136 {
138  {
140  propMgr.InheritsAfter( TYPE_HASH( B ), TYPE_HASH( A ) );
141  propMgr.AddProperty( new PROPERTY<B, int>( "C", &B::setC, &B::getC ) );
142  }
143 } _CLASS_B_DESC;
144 
145 static struct CLASS_C_DESC
146 {
148  {
150  propMgr.AddProperty( new PROPERTY<C, bool>( "bool", &C::setBool, &C::getBool ) );
151  propMgr.AddProperty( new PROPERTY<C, int>( "new", &C::setNew, &C::getNew ) );
152  }
153 } _CLASS_C_DESC;
154 
155 static struct CLASS_D_DESC
156 {
158  {
160  .Map( D::enum_class::TESTA, "TESTA" )
161  .Map( D::enum_class::TESTB, "TESTB" )
162  .Map( D::enum_class::TESTC, "TESTC" );
163 
165  propMgr.AddProperty( new PROPERTY_ENUM<D, enum_glob>( "enumGlob", &D::setGlobEnum, &D::getGlobEnum ) );
167  propMgr.AddProperty( new PROPERTY<D, wxPoint, A>( "point_alias", &D::setPoint, &D::getPoint ) );
168 
169  propMgr.ReplaceProperty( TYPE_HASH( C ), "bool",
170  new PROPERTY<D, bool, C>( "replaced_bool", &D::setBool, &D::getBool ) );
171 
172  // lines below are needed to indicate multiple inheritance
173  propMgr.AddTypeCast( new TYPE_CAST<D, A> );
174  propMgr.AddTypeCast( new TYPE_CAST<D, C> );
175  propMgr.InheritsAfter( TYPE_HASH( D ), TYPE_HASH( A ) );
176  propMgr.InheritsAfter( TYPE_HASH( D ), TYPE_HASH( C ) );
177 
178  auto cond = new PROPERTY<D, int>( "cond", &D::setCond, &D::getCond );
179  cond->SetAvailableFunc( [=](INSPECTABLE* aItem)->bool { return *aItem->Get<int>( "A" ) > 50; } );
180  propMgr.AddProperty( cond );
181  }
182 } _CLASS_D_DESC;
183 
184 static struct CLASS_E_DESC
185 {
187  {
188  wxArrayInt values;
189  values.Add( enum_glob::TEST1 );
190  values.Add( enum_glob::TEST3 );
191  wxArrayString labels;
192  labels.Add( "T1" );
193  labels.Add( "T3" );
194  wxPGChoices newChoices( labels, values );
195 
197  auto prop = new PROPERTY_ENUM<E, enum_glob, D>( "enumGlob",
199  prop->SetChoices( newChoices );
200  propMgr.ReplaceProperty( TYPE_HASH( D ), "enumGlob", prop );
201  }
202 } _CLASS_E_DESC;
203 
205 
206 
208 {
210  ptr( nullptr ),
211  propMgr( PROPERTY_MANAGER::Instance() )
212  {
213  }
214 
215  B b;
216  D d;
217  A* ptr;
219 };
220 
221 BOOST_FIXTURE_TEST_SUITE( Properties, PropertiesFixture )
222 
224 {
225  propMgr.Rebuild();
226 }
227 
228 // Basic Set() & Get()
230 {
231  ptr = &b;
232  ptr->Set( "A", 100 );
233  ptr->Set( "point", wxPoint( 100, 200 ) );
234  BOOST_CHECK_EQUAL( *ptr->Get<int>( "A" ), 100 );
235  BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point" ), wxPoint( 100, 200 ) );
236 
237  ptr = &d;
238  ptr->Set( "enumGlob", enum_glob::TEST2 );
239  ptr->Set( "enumClass", D::enum_class::TESTC );
240  BOOST_CHECK_EQUAL( *ptr->Get<enum_glob>( "enumGlob" ), enum_glob::TEST2 );
241  BOOST_CHECK_EQUAL( *ptr->Get<D::enum_class>( "enumClass" ), D::enum_class::TESTC );
242 }
243 
244 // Virtual methods
245 BOOST_AUTO_TEST_CASE( VirtualMethods )
246 {
247  // D::setA() saves a doubled value, while B::setA() saves unmodified value
248  ptr = &b;
249  ptr->Set( "A", 23 );
250  BOOST_CHECK_EQUAL( *ptr->Get<int>( "A" ), 23 ); // unmodified == 23
251 
252  ptr = &d;
253  ptr->Set( "A", 23 );
254  BOOST_CHECK_EQUAL( *ptr->Get<int>( "A" ), 46 ); // doubled == 46
255 }
256 
257 // Non-existing properties
258 BOOST_AUTO_TEST_CASE( NotexistingProperties )
259 {
260  ptr = &d;
261  BOOST_CHECK_EQUAL( ptr->Set<int>( "does not exist", 5 ), false );
262  //BOOST_CHECK_EQUAL( ptr->Get<int>( "neither" ).has_value(), false );
263 }
264 
265 // Request data using incorrect type
266 BOOST_AUTO_TEST_CASE( IncorrectType )
267 {
268  ptr = &d;
269  BOOST_CHECK_THROW( ptr->Get<wxPoint>( "A" ), std::invalid_argument );
270 }
271 
272 // Type-casting (for types with multiple inheritance)
273 BOOST_AUTO_TEST_CASE( TypeCasting )
274 {
275  ptr = &d;
276  A* D_to_A = static_cast<A*>( propMgr.TypeCast( ptr, TYPE_HASH( D ), TYPE_HASH( A ) ) );
277  BOOST_CHECK_EQUAL( D_to_A, dynamic_cast<A*>( ptr ) );
278 
279  C* D_to_C = static_cast<C*>( propMgr.TypeCast( ptr, TYPE_HASH( D ), TYPE_HASH( C ) ) );
280  BOOST_CHECK_EQUAL( D_to_C, dynamic_cast<C*>( ptr ) );
281 }
282 
284 {
285  PROPERTY_BASE* prop = propMgr.GetProperty( TYPE_HASH( D ), "enumGlob" );
286  BOOST_CHECK( prop->HasChoices() );
287 
288  wxArrayInt values;
289  values.Add( enum_glob::TEST1 );
290  values.Add( enum_glob::TEST2 );
291  values.Add( enum_glob::TEST3 );
292  wxArrayString labels;
293  labels.Add( "TEST1" );
294  labels.Add( "TEST2" );
295  labels.Add( "TEST3" );
296 
297  const wxPGChoices& v = prop->Choices();
298  BOOST_CHECK_EQUAL( v.GetCount(), values.GetCount() );
299  BOOST_CHECK_EQUAL( v.GetCount(), labels.GetCount() );
300 
301  for (int i = 0; i < values.GetCount(); ++i )
302  {
303  BOOST_CHECK_EQUAL( v.GetValue( i ), values[i] );
304  }
305 
306  for (int i = 0; i < labels.GetCount(); ++i )
307  {
308  BOOST_CHECK_EQUAL( v.GetLabel( i ), labels[i] );
309  }
310 }
311 
313 {
314  PROPERTY_BASE* prop = propMgr.GetProperty( TYPE_HASH( D ), "enumClass" );
315  BOOST_CHECK( prop->HasChoices() );
316 
317  wxArrayInt values;
318  values.Add( D::enum_class::TESTA );
319  values.Add( D::enum_class::TESTB );
320  values.Add( D::enum_class::TESTC );
321  wxArrayString labels;
322  labels.Add( "TESTA" );
323  labels.Add( "TESTB" );
324  labels.Add( "TESTC" );
325 
326  const wxPGChoices& v = prop->Choices();
327  BOOST_CHECK_EQUAL( v.GetCount(), values.GetCount() );
328  BOOST_CHECK_EQUAL( v.GetCount(), labels.GetCount() );
329 
330  for (int i = 0; i < values.GetCount(); ++i )
331  {
332  BOOST_CHECK_EQUAL( v.GetValue( i ), values[i] );
333  }
334 
335  for (int i = 0; i < labels.GetCount(); ++i )
336  {
337  BOOST_CHECK_EQUAL( v.GetLabel( i ), labels[i] );
338  }
339 }
340 
341 // Tests conditional properties (which may depend on values or other properties)
342 BOOST_AUTO_TEST_CASE( Availability )
343 {
344  PROPERTY_BASE* propCond = propMgr.GetProperty( TYPE_HASH( D ), "cond" );
345  ptr = &d;
346 
347  // "cond" property is available only when "a" field is greater than 50
348  d.setA( 0 );
349  BOOST_CHECK( !propCond->Available( ptr ) );
350 
351  d.setA( 100 );
352  BOOST_CHECK( propCond->Available( ptr ) );
353 }
354 
355 // Using a different name for a parent property
357 {
358  ptr = &d;
359 
360  ptr->Set( "point", wxPoint( 100, 100 ) );
361  BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point" ), wxPoint( 100, 100 ) );
362  BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point_alias" ), wxPoint( 100, 100 ) );
363 
364  ptr->Set( "point_alias", wxPoint( 300, 300 ) );
365  BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point" ), wxPoint( 300, 300 ) );
366  BOOST_CHECK_EQUAL( *ptr->Get<wxPoint>( "point_alias" ), wxPoint( 300, 300 ) );
367 }
368 
369 // Property renaming
371 {
372  PROPERTY_BASE* prop;
373 
374  prop = propMgr.GetProperty( TYPE_HASH( D ), "bool" );
375  BOOST_CHECK_EQUAL( prop, nullptr );
376 
377  prop = propMgr.GetProperty( TYPE_HASH( D ), "replaced_bool" );
378  BOOST_CHECK( prop );
379 }
380 
381 // Different subset of enum values for a property
382 BOOST_AUTO_TEST_CASE( AlternativeEnum )
383 {
384  PROPERTY_BASE* prop = propMgr.GetProperty( TYPE_HASH( E ), "enumGlob" );
385  BOOST_CHECK( prop->HasChoices() );
386 
387  wxArrayInt values;
388  values.Add( enum_glob::TEST1 );
389  values.Add( enum_glob::TEST3 );
390  wxArrayString labels;
391  labels.Add( "T1" );
392  labels.Add( "T3" );
393 
394  const wxPGChoices& v = prop->Choices();
395  BOOST_CHECK_EQUAL( v.GetCount(), values.GetCount() );
396  BOOST_CHECK_EQUAL( v.GetCount(), labels.GetCount() );
397 
398  for (int i = 0; i < values.GetCount(); ++i )
399  {
400  BOOST_CHECK_EQUAL( v.GetValue( i ), values[i] );
401  }
402 
403  for (int i = 0; i < labels.GetCount(); ++i )
404  {
405  BOOST_CHECK_EQUAL( v.GetLabel( i ), labels[i] );
406  }
407 }
408 
409 BOOST_AUTO_TEST_SUITE_END()
void setCond(int a)
const wxPoint & getPoint() const
virtual int getA() const =0
void setC(int a)
virtual bool HasChoices() const
Returns true if this PROPERTY has a limited set of possible values.
Definition: property.h:215
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:64
#define TYPE_HASH(x)
Macro to generate unique identifier for a type
Definition: property.h:55
static struct ENUM_GLOB_DESC _ENUM_GLOB_DESC
static struct CLASS_E_DESC _CLASS_E_DESC
bool getBool() const
enum_glob getGlobEnum() const
int getCond() const
static ENUM_MAP< T > & Instance()
Definition: property.h:519
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:58
static struct CLASS_C_DESC _CLASS_C_DESC
enum_class getClassEnum() const
void setBool(bool a)
static struct CLASS_A_DESC _CLASS_A_DESC
int getNew() const
wxPoint m_p
enum_glob
void setPoint3(wxPoint p)
virtual int getA() const override
wxAny Get(PROPERTY_BASE *aProperty)
Definition: inspectable.h:84
enum_class
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declares an inheritance relationship between types.
void setClassEnum(enum_class val)
const wxPoint & getPoint4() const
wxPoint getPoint3()
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:33
virtual void setA(int a) override
ENUM_TO_WXANY(enum_glob)
virtual const wxPGChoices & Choices() const
Returns a limited set of possible values (e.g.
Definition: property.h:197
BOOST_AUTO_TEST_CASE(Init)
enum_class m_enum_class
PROPERTY_MANAGER & propMgr
void setGlobEnum(enum_glob val)
static struct CLASS_B_DESC _CLASS_B_DESC
wxPoint getPoint2() const
int getC() const
void AddTypeCast(TYPE_CAST_BASE *aCast)
Registers a type converter.
void AddProperty(PROPERTY_BASE *aProperty)
Registers a property.
bool Available(INSPECTABLE *aObject) const
Returns true if aObject offers this PROPERTY.
Definition: property.h:223
enum_glob m_enum_glob
void setA(int a) override
void ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew)
Replaces an existing property for a specific type.
static struct CLASS_D_DESC _CLASS_D_DESC
Provides class metadata.
Definition: property_mgr.h:61
virtual void setA(int a)=0
void setNew(int m)
int getA() const override
void setPoint4(wxPoint p)
virtual const int & getA2() const
virtual void setPoint(const wxPoint &p)
void setPoint2(wxPoint &p)