Skip to content

Commit 627e00d

Browse files
committed
Unit Tests
1 parent 8d4b73a commit 627e00d

File tree

2 files changed

+285
-6
lines changed

2 files changed

+285
-6
lines changed

CSharpCodeAnalyst/Exploration/CodeGraphExplorer.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ public SearchResult FindIncomingRelationships(string id)
502502
}
503503

504504
/// <summary>
505-
/// The method fills any missing intermediate containers.
505+
/// The method finds and returns the missing code elements in the hierarchy.
506506
/// </summary>
507507
public SearchResult FindGapsInHierarchy(HashSet<string> knownIds)
508508
{
@@ -538,15 +538,16 @@ private HashSet<string> FillGapsInHierarchy(HashSet<string> knownIds)
538538
var addFromHere = false;
539539
foreach (var parent in fromRootToCurrent)
540540
{
541-
if (knownIds.Contains(parent.Id))
541+
if (addFromHere)
542542
{
543-
// Found a parent, all elements from here down to current need to be present.
544-
addFromHere = true;
543+
added.Add(parent.Id);
544+
continue;
545545
}
546546

547-
if (addFromHere)
547+
if (knownIds.Contains(parent.Id))
548548
{
549-
added.Add(parent.Id);
549+
// Found a parent, all elements from here down to current need to be present.
550+
addFromHere = true;
550551
}
551552
}
552553
}
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
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

Comments
 (0)