1+ using CodeParserTests . Helper ;
2+ using Contracts . Graph ;
3+ using CSharpCodeAnalyst . Exploration ;
4+
5+ namespace CodeParserTests . UnitTests . Exploration ;
6+
7+ [ TestFixture ]
8+ public class CodeGraphExplorerTests
9+ {
10+
11+ [ SetUp ]
12+ public void SetUp ( )
13+ {
14+ _graph = new TestCodeGraph ( ) ;
15+ _explorer = new CodeGraphExplorer ( ) ;
16+ _explorer . LoadCodeGraph ( _graph ) ;
17+ }
18+
19+ private TestCodeGraph _graph = null ! ;
20+ private CodeGraphExplorer _explorer = null ! ;
21+
22+ private Relationship Rel ( CodeElement source , CodeElement target , RelationshipType type , RelationshipAttribute attributes = RelationshipAttribute . None )
23+ {
24+ var r = new Relationship ( source . Id , target . Id , type , attributes ) ;
25+ source . Relationships . Add ( r ) ;
26+ return r ;
27+ }
28+
29+ [ Test ]
30+ public void GetElements_ReturnsExisting_IgnoresMissing ( )
31+ {
32+ var a = _graph . CreateClass ( "A" ) ;
33+ var b = _graph . CreateMethod ( "B" , a ) ;
34+ var list = _explorer . GetElements ( new List < string > { "A" , "B" , "C" } ) ;
35+ CollectionAssert . AreEquivalent ( new [ ] { a , b } , list ) ;
36+ }
37+
38+ [ Test ]
39+ public void FindParents_ReturnsDistinctParents ( )
40+ {
41+ var cls = _graph . CreateClass ( "Cls" ) ;
42+ var m1 = _graph . CreateMethod ( "M1" , cls ) ;
43+ var m2 = _graph . CreateMethod ( "M2" , cls ) ;
44+ var result = _explorer . FindParents ( new List < string > { m1 . Id , m2 . Id } ) ;
45+ CollectionAssert . AreEquivalent ( new [ ] { cls } , result . Elements ) ;
46+ Assert . That ( result . Relationships , Is . Empty ) ;
47+ }
48+
49+ [ Test ]
50+ public void FindMissingTypesForLonelyTypeMembers_AddsContainers ( )
51+ {
52+ var asm = _graph . CreateAssembly ( "Asm" ) ;
53+ var ns = _graph . CreateNamespace ( "Ns" , asm ) ;
54+ var cls = _graph . CreateClass ( "Cls" , ns ) ;
55+ var m = _graph . CreateMethod ( "M" , cls ) ;
56+ var known = new HashSet < string > { m . Id } ; // only method known
57+ var result = _explorer . FindMissingTypesForLonelyTypeMembers ( known ) ;
58+ Assert . That ( result . Elements . Any ( e => e . Id == cls . Id ) ) ;
59+ }
60+
61+ [ Test ]
62+ public void FindGapsInHierarchy_FillsIntermediateContainers ( )
63+ {
64+ var asm = _graph . CreateAssembly ( "Asm" ) ;
65+ var ns = _graph . CreateNamespace ( "Ns" , asm ) ;
66+ var cls = _graph . CreateClass ( "Cls" , ns ) ;
67+ var m = _graph . CreateMethod ( "M" , cls ) ;
68+ var known = new HashSet < string > { asm . Id , m . Id } ; // gap: Ns, Cls missing
69+ var result = _explorer . FindGapsInHierarchy ( known ) ;
70+ Assert . That ( result . Elements . Select ( e => e . Id ) . ToHashSet ( ) . SetEquals ( new [ ] { ns . Id , cls . Id } ) ) ;
71+ }
72+
73+ [ Test ]
74+ public void FindOutgoingCalls_DirectCalls ( )
75+ {
76+ var cls = _graph . CreateClass ( "Cls" ) ;
77+ var m1 = _graph . CreateMethod ( "M1" , cls ) ;
78+ var m2 = _graph . CreateMethod ( "M2" , cls ) ;
79+ Rel ( m1 , m2 , RelationshipType . Calls ) ;
80+ var result = _explorer . FindOutgoingCalls ( m1 . Id ) ;
81+ CollectionAssert . AreEquivalent ( new [ ] { m2 } , result . Elements ) ;
82+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 1 ) ) ;
83+ }
84+
85+ [ Test ]
86+ public void FindIncomingCalls_DirectCallers ( )
87+ {
88+ var cls = _graph . CreateClass ( "Cls" ) ;
89+ var target = _graph . CreateMethod ( "Target" , cls ) ;
90+ var caller = _graph . CreateMethod ( "Caller" , cls ) ;
91+ Rel ( caller , target , RelationshipType . Calls ) ;
92+ var result = _explorer . FindIncomingCalls ( target . Id ) ;
93+ CollectionAssert . AreEquivalent ( new [ ] { caller } , result . Elements ) ;
94+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 1 ) ) ;
95+ }
96+
97+ [ Test ]
98+ public void FindIncomingCallsRecursive_TracesChain ( )
99+ {
100+ var cls = _graph . CreateClass ( "Cls" ) ;
101+ var m1 = _graph . CreateMethod ( "M1" , cls ) ;
102+ var m2 = _graph . CreateMethod ( "M2" , cls ) ;
103+ var m3 = _graph . CreateMethod ( "M3" , cls ) ;
104+ Rel ( m2 , m1 , RelationshipType . Calls ) ;
105+ Rel ( m3 , m2 , RelationshipType . Calls ) ;
106+ var result = _explorer . FindIncomingCallsRecursive ( m1 . Id ) ;
107+ CollectionAssert . AreEquivalent ( new [ ] { m2 , m3 } , result . Elements ) ;
108+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 2 ) ) ;
109+ }
110+
111+ [ Test ]
112+ public void FindOutgoingRelationships_ReturnsAllTargets ( )
113+ {
114+ var cls = _graph . CreateClass ( "Cls" ) ;
115+ var m1 = _graph . CreateMethod ( "M1" , cls ) ;
116+ var m2 = _graph . CreateMethod ( "M2" , cls ) ;
117+ Rel ( m1 , m2 , RelationshipType . Calls ) ;
118+ Rel ( m1 , m2 , RelationshipType . Uses ) ;
119+ var result = _explorer . FindOutgoingRelationships ( m1 . Id ) ;
120+ CollectionAssert . AreEquivalent ( new [ ] { m2 , m2 } , result . Elements ) ; // duplicates allowed
121+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 2 ) ) ;
122+ }
123+
124+ [ Test ]
125+ public void FindIncomingRelationships_ReturnsAllSources ( )
126+ {
127+ var cls = _graph . CreateClass ( "Cls" ) ;
128+ var m1 = _graph . CreateMethod ( "M1" , cls ) ;
129+ var m2 = _graph . CreateMethod ( "M2" , cls ) ;
130+ Rel ( m2 , m1 , RelationshipType . Calls ) ;
131+ Rel ( m2 , m1 , RelationshipType . Uses ) ;
132+ var result = _explorer . FindIncomingRelationships ( m1 . Id ) ;
133+ CollectionAssert . AreEquivalent ( new [ ] { m2 , m2 } , result . Elements ) ;
134+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 2 ) ) ;
135+ }
136+
137+ [ Test ]
138+ public void FindAllRelationships_FiltersByIdSet ( )
139+ {
140+ var cls = _graph . CreateClass ( "Cls" ) ;
141+ var a = _graph . CreateMethod ( "A" , cls ) ;
142+ var b = _graph . CreateMethod ( "B" , cls ) ;
143+ var c = _graph . CreateMethod ( "C" , cls ) ;
144+ var r1 = Rel ( a , b , RelationshipType . Calls ) ;
145+ Rel ( b , c , RelationshipType . Calls ) ;
146+ var set = new HashSet < string > { a . Id , b . Id } ; // only r1 qualifies
147+ var rels = _explorer . FindAllRelationships ( set ) . ToList ( ) ;
148+ CollectionAssert . AreEquivalent ( new [ ] { r1 } , rels ) ;
149+ }
150+
151+ [ Test ]
152+ public void FindOutgoingRelationshipsDeep_IncludesChildrenSources ( )
153+ {
154+ var cls = _graph . CreateClass ( "Cls" ) ;
155+ var m1 = _graph . CreateMethod ( "M1" , cls ) ;
156+ var m2 = _graph . CreateMethod ( "M2" , cls ) ;
157+ Rel ( m1 , m2 , RelationshipType . Calls ) ;
158+ var result = _explorer . FindOutgoingRelationshipsDeep ( cls . Id ) ;
159+ // Elements should include class + its two methods
160+ Assert . That ( result . Elements . Any ( e => e . Id == cls . Id ) ) ;
161+ Assert . That ( result . Elements . Any ( e => e . Id == m1 . Id ) ) ;
162+ Assert . That ( result . Elements . Any ( e => e . Id == m2 . Id ) ) ;
163+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 1 ) ) ;
164+ }
165+
166+ [ Test ]
167+ public void FindIncomingRelationshipsDeep_IncludesChildrenTargets ( )
168+ {
169+ var cls = _graph . CreateClass ( "Cls" ) ;
170+ var m1 = _graph . CreateMethod ( "M1" , cls ) ;
171+ var m2 = _graph . CreateMethod ( "M2" , cls ) ;
172+ Rel ( m2 , m1 , RelationshipType . Calls ) ;
173+ var result = _explorer . FindIncomingRelationshipsDeep ( cls . Id ) ;
174+ // Should include both methods and relationship
175+ Assert . That ( result . Elements . Any ( e => e . Id == m1 . Id ) ) ;
176+ Assert . That ( result . Elements . Any ( e => e . Id == m2 . Id ) ) ;
177+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 1 ) ) ;
178+ }
179+
180+ [ Test ]
181+ public void FindFullInheritanceTree_ReturnsBaseAndDerived ( )
182+ {
183+ var baseCls = _graph . CreateClass ( "Base" ) ;
184+ var derived1 = _graph . CreateClass ( "D1" ) ;
185+ var derived2 = _graph . CreateClass ( "D2" ) ;
186+ Rel ( derived1 , baseCls , RelationshipType . Inherits ) ;
187+ Rel ( derived2 , baseCls , RelationshipType . Inherits ) ;
188+ var result = _explorer . FindFullInheritanceTree ( baseCls . Id ) ;
189+ CollectionAssert . AreEquivalent ( new [ ] { baseCls , derived1 , derived2 } , result . Elements ) ;
190+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 2 ) ) ;
191+ }
192+
193+ [ Test ]
194+ public void FindSpecializations_ReturnsImplementorsAndOverrides ( )
195+ {
196+ var iface = _graph . CreateInterface ( "I" ) ;
197+ var impl = _graph . CreateClass ( "Impl" ) ;
198+ Rel ( impl , iface , RelationshipType . Implements ) ;
199+ var result = _explorer . FindSpecializations ( iface . Id ) ;
200+ CollectionAssert . AreEquivalent ( new [ ] { impl } , result . Elements ) ;
201+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 1 ) ) ;
202+ }
203+
204+ [ Test ]
205+ public void FindAbstractions_ReturnsInterfacesAndBases ( )
206+ {
207+ var iface = _graph . CreateInterface ( "I" ) ;
208+ var impl = _graph . CreateClass ( "Impl" ) ;
209+ Rel ( impl , iface , RelationshipType . Implements ) ;
210+ var result = _explorer . FindAbstractions ( impl . Id ) ;
211+ CollectionAssert . AreEquivalent ( new [ ] { iface } , result . Elements ) ;
212+ Assert . That ( result . Relationships . Count ( ) , Is . EqualTo ( 1 ) ) ;
213+ }
214+
215+ [ Test ]
216+ public void FollowIncomingCallsHeuristically_RestrictsSideHierarchy ( )
217+ {
218+ var baseCls = _graph . CreateClass ( "Base" ) ;
219+ var s1 = _graph . CreateClass ( "S1" ) ;
220+ var s2 = _graph . CreateClass ( "S2" ) ;
221+ Rel ( s1 , baseCls , RelationshipType . Inherits ) ;
222+ Rel ( s2 , baseCls , RelationshipType . Inherits ) ;
223+
224+ var mStart = _graph . CreateMethod ( "S1_M" , s1 ) ;
225+ var callerAllowed = _graph . CreateMethod ( "S1_Caller" , s1 ) ;
226+ var callerBase = _graph . CreateMethod ( "Base_Caller" , baseCls ) ;
227+ var callerForbidden = _graph . CreateMethod ( "S2_Caller" , s2 ) ;
228+
229+ Rel ( callerAllowed , mStart , RelationshipType . Calls , RelationshipAttribute . IsInstanceCall ) ;
230+ Rel ( callerBase , mStart , RelationshipType . Calls ) ;
231+ Rel ( callerForbidden , mStart , RelationshipType . Calls ) ;
232+
233+ var result = _explorer . FollowIncomingCallsHeuristically ( mStart . Id ) ;
234+ var ids = result . Elements . Select ( e => e . Id ) . ToHashSet ( ) ;
235+ Assert . That ( ids . Contains ( callerAllowed . Id ) , Is . True ) ;
236+ Assert . That ( ids . Contains ( callerBase . Id ) , Is . True ) ;
237+ Assert . That ( ids . Contains ( callerForbidden . Id ) , Is . False , "Side hierarchy call should be excluded" ) ;
238+ }
239+
240+ [ Test ]
241+ public void FollowIncomingCallsHeuristically_HandlesEvents ( )
242+ {
243+ var cls = _graph . CreateClass ( "Cls" ) ;
244+ var evt = _graph . CreateEvent ( "Evt" , cls ) ;
245+ var handler = _graph . CreateMethod ( "Handler" , cls ) ;
246+ Rel ( handler , evt , RelationshipType . Handles ) ;
247+ var raiser = _graph . CreateMethod ( "Raiser" , cls ) ;
248+ Rel ( raiser , evt , RelationshipType . Invokes ) ;
249+ var result = _explorer . FollowIncomingCallsHeuristically ( handler . Id ) ;
250+ var ids = result . Elements . Select ( e => e . Id ) . ToHashSet ( ) ;
251+ Assert . That ( ids . Contains ( evt . Id ) , Is . True ) ;
252+ Assert . That ( ids . Contains ( raiser . Id ) , Is . True ) ;
253+ }
254+
255+ [ Test ]
256+ public void FindOutgoingRelationships_EmptyForUnknownId ( )
257+ {
258+ var result = _explorer . FindOutgoingRelationships ( "Unknown" ) ;
259+ Assert . That ( result . Elements , Is . Empty ) ;
260+ Assert . That ( result . Relationships , Is . Empty ) ;
261+ }
262+
263+ [ Test ]
264+ public void FindIncomingCalls_ReturnsEmptyForUnknownId ( )
265+ {
266+ var result = _explorer . FindIncomingCalls ( "Unknown" ) ;
267+ Assert . That ( result . Elements , Is . Empty ) ;
268+ Assert . That ( result . Relationships , Is . Empty ) ;
269+ }
270+
271+ [ Test ]
272+ public void FindFullInheritanceTree_ReturnsEmptyForUnknownId ( )
273+ {
274+ var result = _explorer . FindFullInheritanceTree ( "Unknown" ) ;
275+ Assert . That ( result . Elements , Is . Empty ) ;
276+ Assert . That ( result . Relationships , Is . Empty ) ;
277+ }
278+ }
0 commit comments