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,14 +13,26 @@ 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
2326
27+ @dataclasses .dataclass
28+ class ExtendedNode (SomeNode ):
29+ prop = 2
30+ cont_fwd : "ExtendedNode" = None
31+ cont_ref : ReferenceByName ["ExtendedNode" ] = None
32+ multiple2 : List [SomeNode ] = dataclasses .field (default_factory = list )
33+ internal2 : Node = internal_field (default = None )
34+
35+
2436@dataclasses .dataclass
2537class SomeSymbol (Symbol ):
2638 index : int = dataclasses .field (default = None )
@@ -39,6 +51,14 @@ class InvalidNode(Node):
3951 another_child : Node = None
4052
4153
54+ def require_feature (node , name ) -> PropertyDescription :
55+ return next (n for n in node .properties if n .name == name )
56+
57+
58+ def find_feature (node , name ) -> Optional [PropertyDescription ]:
59+ return next ((n for n in node .properties if n .name == name ), None )
60+
61+
4262class ModelTest (unittest .TestCase ):
4363
4464 def test_reference_by_name_unsolved_str (self ):
@@ -77,9 +97,29 @@ def test_node_with_position(self):
7797
7898 def test_node_properties (self ):
7999 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" ))
100+ self .assertIsNotNone (find_feature (node , 'foo' ))
101+ self .assertFalse (find_feature (node , 'foo' ).is_containment )
102+ self .assertIsNotNone (find_feature (node , 'bar' ))
103+ self .assertFalse (find_feature (node , 'bar' ).is_containment )
104+ self .assertIsNotNone (find_feature (node , 'name' ))
105+ self .assertTrue (find_feature (node , 'containment' ).is_containment )
106+ self .assertFalse (find_feature (node , 'containment' ).is_reference )
107+ self .assertFalse (find_feature (node , 'reference' ).is_containment )
108+ self .assertTrue (find_feature (node , 'reference' ).is_reference )
109+ with self .assertRaises (StopIteration ):
110+ next (n for n in node .properties if n .name == '__private__' )
111+ with self .assertRaises (StopIteration ):
112+ next (n for n in node .properties if n .name == 'non_existent' )
113+ with self .assertRaises (StopIteration ):
114+ next (n for n in node .properties if n .name == 'properties' )
115+ with self .assertRaises (StopIteration ):
116+ next (n for n in node .properties if n .name == "origin" )
117+
118+ def test_node_properties_inheritance (self ):
119+ node = ExtendedNode ("n" ).with_position (Position (Point (1 , 0 ), Point (2 , 1 )))
120+ self .assertIsNotNone (find_feature (node , 'foo' ))
121+ self .assertIsNotNone (find_feature (node , 'bar' ))
122+ self .assertIsNotNone (find_feature (node , 'name' ))
83123 with self .assertRaises (StopIteration ):
84124 next (n for n in node .properties if n .name == '__private__' )
85125 with self .assertRaises (StopIteration ):
@@ -159,20 +199,52 @@ def frob_node(_: Node):
159199 pass
160200
161201 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 " )
202+ self .assertEqual (8 , len (pds ), f"{ pds } should be 7 " )
163203 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 )
204+ self .assertFalse (pds [0 ].is_containment )
205+ self .assertEqual ("containment" , pds [1 ].name )
206+ self .assertTrue (pds [1 ].is_containment )
207+ self .assertEqual ("foo" , pds [2 ].name )
208+ self .assertFalse (pds [2 ].is_containment )
209+ self .assertEqual ("multiple" , pds [3 ].name )
210+ self .assertTrue (pds [3 ].is_containment )
172211 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 )
212+ self .assertEqual ("multiple_opt" , pds [4 ].name )
213+ self .assertTrue (pds [4 ].is_containment )
214+ self .assertEqual (Multiplicity .MANY , pds [4 ].multiplicity )
215+ self .assertEqual ("name" , pds [5 ].name )
216+ self .assertFalse (pds [5 ].is_containment )
217+ self .assertEqual ("optional" , pds [6 ].name )
218+ self .assertTrue (pds [6 ].is_containment )
219+ self .assertEqual (Multiplicity .OPTIONAL , pds [6 ].multiplicity )
220+ self .assertEqual ("reference" , pds [7 ].name )
221+ self .assertTrue (pds [7 ].is_reference )
222+
223+ self .assertRaises (Exception , lambda : [x for x in InvalidNode .node_properties ])
224+
225+ def test_node_properties_meta_inheritance (self ):
226+ @extension_method (Node )
227+ def frob_node_2 (_ : Node ):
228+ pass
229+
230+ pds = [pd for pd in sorted (ExtendedNode .node_properties , key = lambda x : x .name )]
231+ self .assertEqual (12 , len (pds ), f"{ pds } should be 7" )
232+ self .assertEqual ("bar" , pds [0 ].name )
233+ self .assertFalse (pds [0 ].is_containment )
234+ self .assertEqual ("cont_fwd" , pds [1 ].name )
235+ self .assertTrue (pds [1 ].is_containment )
236+ self .assertEqual (ExtendedNode , pds [1 ].type )
237+ self .assertEqual ("cont_ref" , pds [2 ].name )
238+ self .assertTrue (pds [2 ].is_reference )
239+ self .assertEqual (ExtendedNode , pds [2 ].type )
240+ self .assertEqual ("containment" , pds [3 ].name )
241+ self .assertTrue (pds [3 ].is_containment )
242+ self .assertEqual ("foo" , pds [4 ].name )
243+ self .assertEqual ("multiple" , pds [5 ].name )
244+ self .assertTrue (pds [5 ].is_containment )
245+ self .assertEqual (Multiplicity .MANY , pds [5 ].multiplicity )
246+ self .assertEqual ("multiple2" , pds [6 ].name )
247+ self .assertTrue (pds [6 ].is_containment )
248+ self .assertEqual (Multiplicity .MANY , pds [6 ].multiplicity )
177249
178250 self .assertRaises (Exception , lambda : [x for x in InvalidNode .node_properties ])
0 commit comments