22import unittest
33from typing import List , Optional , Union
44
5- from pylasu .model import Node , Position , Point
6- from pylasu .model .reflection import Multiplicity
5+ from pylasu .model import Node , Position , Point , internal_field
6+ from pylasu .model .reflection import Multiplicity , PropertyDescription
77from pylasu .model .naming import ReferenceByName , Named , Scope , Symbol
88from pylasu .support import extension_method
99
@@ -13,13 +13,24 @@ class SomeNode(Node, Named):
1313 foo = 3
1414 bar : int = dataclasses .field (init = False )
1515 __private__ = 4
16- ref : Node = None
16+ containment : Node = None
17+ reference : ReferenceByName [Node ] = None
1718 multiple : List [Node ] = dataclasses .field (default_factory = list )
19+ optional : Optional [Node ] = None
1820 multiple_opt : List [Optional [Node ]] = dataclasses .field (default_factory = list )
21+ internal : Node = internal_field (default = None )
1922
2023 def __post_init__ (self ):
2124 self .bar = 5
2225
26+ @dataclasses .dataclass
27+ class ExtendedNode (SomeNode ):
28+ prop = 2
29+ cont_fwd : "ExtendedNode" = None
30+ cont_ref : ReferenceByName ["ExtendedNode" ] = None
31+ multiple2 : List [SomeNode ] = dataclasses .field (default_factory = list )
32+ internal2 : Node = internal_field (default = None )
33+
2334
2435@dataclasses .dataclass
2536class SomeSymbol (Symbol ):
@@ -39,6 +50,14 @@ class InvalidNode(Node):
3950 another_child : Node = None
4051
4152
53+ def require_feature (node , name ) -> PropertyDescription :
54+ return next (n for n in node .properties if n .name == name )
55+
56+
57+ def find_feature (node , name ) -> Optional [PropertyDescription ]:
58+ return next ((n for n in node .properties if n .name == name ), None )
59+
60+
4261class ModelTest (unittest .TestCase ):
4362
4463 def test_reference_by_name_unsolved_str (self ):
@@ -77,9 +96,29 @@ def test_node_with_position(self):
7796
7897 def test_node_properties (self ):
7998 node = SomeNode ("n" ).with_position (Position (Point (1 , 0 ), Point (2 , 1 )))
80- self .assertIsNotNone (next (n for n in node .properties if n .name == 'foo' ))
81- self .assertIsNotNone (next (n for n in node .properties if n .name == 'bar' ))
82- self .assertIsNotNone (next (n for n in node .properties if n .name == "name" ))
99+ self .assertIsNotNone (find_feature (node , 'foo' ))
100+ self .assertFalse (find_feature (node , 'foo' ).is_containment )
101+ self .assertIsNotNone (find_feature (node , 'bar' ))
102+ self .assertFalse (find_feature (node , 'bar' ).is_containment )
103+ self .assertIsNotNone (find_feature (node , 'name' ))
104+ self .assertTrue (find_feature (node , 'containment' ).is_containment )
105+ self .assertFalse (find_feature (node , 'containment' ).is_reference )
106+ self .assertFalse (find_feature (node , 'reference' ).is_containment )
107+ self .assertTrue (find_feature (node , 'reference' ).is_reference )
108+ with self .assertRaises (StopIteration ):
109+ next (n for n in node .properties if n .name == '__private__' )
110+ with self .assertRaises (StopIteration ):
111+ next (n for n in node .properties if n .name == 'non_existent' )
112+ with self .assertRaises (StopIteration ):
113+ next (n for n in node .properties if n .name == 'properties' )
114+ with self .assertRaises (StopIteration ):
115+ next (n for n in node .properties if n .name == "origin" )
116+
117+ def test_node_properties_inheritance (self ):
118+ node = ExtendedNode ("n" ).with_position (Position (Point (1 , 0 ), Point (2 , 1 )))
119+ self .assertIsNotNone (find_feature (node , 'foo' ))
120+ self .assertIsNotNone (find_feature (node , 'bar' ))
121+ self .assertIsNotNone (find_feature (node , 'name' ))
83122 with self .assertRaises (StopIteration ):
84123 next (n for n in node .properties if n .name == '__private__' )
85124 with self .assertRaises (StopIteration ):
@@ -159,20 +198,52 @@ def frob_node(_: Node):
159198 pass
160199
161200 pds = [pd for pd in sorted (SomeNode .node_properties , key = lambda x : x .name )]
162- self .assertEqual (6 , len (pds ), f"{ pds } should be 6 " )
201+ self .assertEqual (8 , len (pds ), f"{ pds } should be 7 " )
163202 self .assertEqual ("bar" , pds [0 ].name )
164- self .assertFalse (pds [0 ].provides_nodes )
165- self .assertEqual ("foo" , pds [1 ].name )
166- self .assertFalse (pds [1 ].provides_nodes )
167- self .assertEqual ("multiple" , pds [2 ].name )
168- self .assertTrue (pds [2 ].provides_nodes )
169- self .assertEqual (Multiplicity .MANY , pds [2 ].multiplicity )
170- self .assertEqual ("multiple_opt" , pds [3 ].name )
171- self .assertTrue (pds [3 ].provides_nodes )
203+ self .assertFalse (pds [0 ].is_containment )
204+ self .assertEqual ("containment" , pds [1 ].name )
205+ self .assertTrue (pds [1 ].is_containment )
206+ self .assertEqual ("foo" , pds [2 ].name )
207+ self .assertFalse (pds [2 ].is_containment )
208+ self .assertEqual ("multiple" , pds [3 ].name )
209+ self .assertTrue (pds [3 ].is_containment )
172210 self .assertEqual (Multiplicity .MANY , pds [3 ].multiplicity )
173- self .assertEqual ("name" , pds [4 ].name )
174- self .assertFalse (pds [4 ].provides_nodes )
175- self .assertEqual ("ref" , pds [5 ].name )
176- self .assertTrue (pds [5 ].provides_nodes )
211+ self .assertEqual ("multiple_opt" , pds [4 ].name )
212+ self .assertTrue (pds [4 ].is_containment )
213+ self .assertEqual (Multiplicity .MANY , pds [4 ].multiplicity )
214+ self .assertEqual ("name" , pds [5 ].name )
215+ self .assertFalse (pds [5 ].is_containment )
216+ self .assertEqual ("optional" , pds [6 ].name )
217+ self .assertTrue (pds [6 ].is_containment )
218+ self .assertEqual (Multiplicity .OPTIONAL , pds [6 ].multiplicity )
219+ self .assertEqual ("reference" , pds [7 ].name )
220+ self .assertTrue (pds [7 ].is_reference )
221+
222+ self .assertRaises (Exception , lambda : [x for x in InvalidNode .node_properties ])
223+
224+ def test_node_properties_meta_inheritance (self ):
225+ @extension_method (Node )
226+ def frob_node_2 (_ : Node ):
227+ pass
228+
229+ pds = [pd for pd in sorted (ExtendedNode .node_properties , key = lambda x : x .name )]
230+ self .assertEqual (12 , len (pds ), f"{ pds } should be 7" )
231+ self .assertEqual ("bar" , pds [0 ].name )
232+ self .assertFalse (pds [0 ].is_containment )
233+ self .assertEqual ("cont_fwd" , pds [1 ].name )
234+ self .assertTrue (pds [1 ].is_containment )
235+ self .assertEqual (ExtendedNode , pds [1 ].type )
236+ self .assertEqual ("cont_ref" , pds [2 ].name )
237+ self .assertTrue (pds [2 ].is_reference )
238+ self .assertEqual (ExtendedNode , pds [2 ].type )
239+ self .assertEqual ("containment" , pds [3 ].name )
240+ self .assertTrue (pds [3 ].is_containment )
241+ self .assertEqual ("foo" , pds [4 ].name )
242+ self .assertEqual ("multiple" , pds [5 ].name )
243+ self .assertTrue (pds [5 ].is_containment )
244+ self .assertEqual (Multiplicity .MANY , pds [5 ].multiplicity )
245+ self .assertEqual ("multiple2" , pds [6 ].name )
246+ self .assertTrue (pds [6 ].is_containment )
247+ self .assertEqual (Multiplicity .MANY , pds [6 ].multiplicity )
177248
178249 self .assertRaises (Exception , lambda : [x for x in InvalidNode .node_properties ])
0 commit comments