diff --git a/src/EStimLibrary/Core/Haptics/HapticSession.cs b/src/EStimLibrary/Core/Haptics/HapticSession.cs
index 8bf0163..965de54 100644
--- a/src/EStimLibrary/Core/Haptics/HapticSession.cs
+++ b/src/EStimLibrary/Core/Haptics/HapticSession.cs
@@ -44,7 +44,7 @@ public class HapticSession
///
/// The global contact IDs that are currently wired to one or more leads.
///
- public SortedSet WiredContacts => this._leadManager._WiredContacts;
+ public SortedSet WiredContacts => this._leadManager.WiredContacts;
///
/// The global contact IDs that are currently not wired to any leads.
///
@@ -60,7 +60,7 @@ public class HapticSession
///
/// The global output IDs that are currently wired to one or more leads.
///
- public SortedSet WiredOutputs => this._leadManager._WiredOutputs;
+ public SortedSet WiredOutputs => this._leadManager.WiredOutputs;
///
/// The global output IDs that are currently not wired to any leads.
///
diff --git a/src/EStimLibrary/Core/HardwareInterfaces/LeadManager.cs b/src/EStimLibrary/Core/HardwareInterfaces/LeadManager.cs
index e9c8158..3f22c0b 100644
--- a/src/EStimLibrary/Core/HardwareInterfaces/LeadManager.cs
+++ b/src/EStimLibrary/Core/HardwareInterfaces/LeadManager.cs
@@ -18,24 +18,30 @@ public class LeadManager : ResourceManager
/// The global contact IDs that are currently wired to one or more leads.
/// Only valid IDs are added.
///
- internal SortedSet _WiredContacts { get; private set; }
+ public SortedSet WiredContacts => new(this._ContactLeadIdMap.Keys);
///
/// The global output IDs that are currently wired to one or more leads.
/// Only valid IDs are added.
///
- internal SortedSet _WiredOutputs { get; private set; }
-
+ public SortedSet WiredOutputs => new(this._OutputLeadIdMap.Keys);
+ ///
+ /// A map of global contact IDs to the set of global lead IDs they are
+ /// involved in.
+ ///
protected Dictionary> _ContactLeadIdMap;
+ ///
+ /// A map of global output IDs to the set of global lead IDs they are
+ /// involved in.
+ ///
protected Dictionary> _OutputLeadIdMap;
//TODO? public Dictionary ContactOutputMap { get; protected set; }
+ ///
+ /// Initialize an empty lead manager with no values initially stored.
+ ///
public LeadManager()
{
- // Initialize wired ID sets.
- this._WiredContacts = new();
- this._WiredOutputs = new();
-
// Initialize empty dictionaries and a zero total count of contacts.
this._ContactLeadIdMap = new();
this._OutputLeadIdMap = new();
@@ -52,9 +58,8 @@ public LeadManager()
/// False if invalid or not wired.
public bool IsWiredContact(int contactId)
{
- // Inherent ID validation bc only valid IDs will be added to
- // WiredContacts.
- return this._WiredContacts.Contains(contactId);
+ // Inherent ID validation bc only valid IDs will be in WiredContacts.
+ return this.WiredContacts.Contains(contactId);
}
///
@@ -66,7 +71,8 @@ public bool IsWiredContact(int contactId)
/// False if invalid or not wired.
public bool IsWiredOutput(int outputId)
{
- return this._WiredOutputs.Contains(outputId);
+ // Inherent ID validation bc only valid IDs will be in WiredOutputs.
+ return this.WiredOutputs.Contains(outputId);
}
///
@@ -81,23 +87,25 @@ public bool IsWiredOutput(int outputId)
/// True if the lead could be added, False if not.
public bool TryAddLead(Lead lead, out int leadId)
{
- // Get the next available lead ID and try adding the lead to the
- // resource pool.
- if (!this.TryGetNextAvailableId(out leadId) ||
- !this.TryAddResource(leadId, lead))
+ // First lets check if the lead already has been given an Id
+ // If the lead has already been added return true and the lead's Id
+ if (this.Resources.ContainsValue(lead))
{
- // Return early if failed.
+ // This is guaranteed to be the same as in the Resources since
+ // Leads are compared based on values and Id is a value.
+ leadId = lead.Id;
+ return true;
+ }
+ if (!(this.TryGetNextAvailableId(out leadId) &&
+ this.TryAddResource(leadId, lead)))
+ {
+ // We return early if this fails
return false;
}
-
- // Actually set the lead's ID.
+ // Update the lead Id
lead._Id = leadId;
-
- // Update extra internal structs. For all contacts and outputs:
- // a) Mark as wired.
- this._WiredContacts.UnionWith(lead.ContactSet);
- this._WiredOutputs.UnionWith(lead.OutputSet);
- // b) Add the lead ID to their list of leads.
+ // Update extra internal structs. For all contacts and outputs, add the
+ // lead ID to their list of leads.
// TODO: why need to make a copy to avoid collection mod? no mod tho...
// AND only an issue during debug
foreach (var contactId in lead.ContactSet.ToList())
@@ -203,10 +211,11 @@ public bool TryRemoveLead(int leadId, out Lead removedLead)
// Remove the lead ID from the contact's lead set.
var leadSet = this._ContactLeadIdMap[contactId];
leadSet.Remove(leadId);
- // Remove the contact from the "wired" set if no leads left on it.
+ // If the contact is no longer connected to any leads, remove the
+ // contact entry entirely.
if (leadSet.Count == 0)
{
- this._WiredContacts.Remove(contactId);
+ this._ContactLeadIdMap.Remove(contactId);
}
}
foreach (var outputId in removedLead.OutputSet)
@@ -214,10 +223,11 @@ public bool TryRemoveLead(int leadId, out Lead removedLead)
// Remove the lead ID from the output's lead set.
var leadSet = this._OutputLeadIdMap[outputId];
leadSet.Remove(leadId);
- // Remove the output from the "wired" set if no leads left on it.
+ // If the output is no longer connected to any leads, remove the
+ // output entry entirely.
if (leadSet.Count == 0)
{
- this._WiredOutputs.Remove(outputId);
+ this._OutputLeadIdMap.Remove(outputId);
}
}
@@ -239,12 +249,13 @@ public bool TryRemoveLead(int leadId, out Lead removedLead)
/// not.
public bool TryRemoveLead(Lead lead, out int leadId, out Lead removedLead)
{
- // Try to get the ID of the Lead (Leads are records: Equals by value).
- // TODO: actually test if this int? and FirstOrDefault strategy works.
- // Was having some troubles with it in another class where HasValue
- // returned true but only because the default value (stored upon lookup
- // failure) was technically a valid value by that check --> TEST TEST!!!
- int? id = this.Resources.FirstOrDefault(kv => kv.Value.Equals(lead)).Key;
+ // Check if this Id is in the resources pool.
+ int? id = null;
+ if (this.Resources.ContainsKey(lead.Id))
+ {
+ // Set the Id of the lead to be removed.
+ id = lead.Id;
+ }
if (id.HasValue)
{
// Store the ID of the lead to be removed.
@@ -268,6 +279,7 @@ public bool TryRemoveLead(Lead lead, out int leadId, out Lead removedLead)
// so I/O calls can be handled by another class
public static void SaveMapToCSV(string outfile)
{
+
}
public static LeadManager LoadMapFromCSV(string infile)
diff --git a/tests/EStimLibrary.UnitTests/Core/HardwareInterfaces/LeadManagerTests.cs b/tests/EStimLibrary.UnitTests/Core/HardwareInterfaces/LeadManagerTests.cs
new file mode 100644
index 0000000..7b7c311
--- /dev/null
+++ b/tests/EStimLibrary.UnitTests/Core/HardwareInterfaces/LeadManagerTests.cs
@@ -0,0 +1,489 @@
+using EStimLibrary.Core;
+using EStimLibrary.Core.HardwareInterfaces;
+
+
+namespace EStimLibrary.UnitTests.Core.HardwareInterfaces;
+
+
+///
+/// Tests for the LeadManager class.
+///
+public class LeadManagerTests
+{
+ ///
+ /// Test the empty constructor. There is nothing to test since all fields
+ /// that get initialized are protected or internal with no public get
+ /// methods so they cannot be checked.
+ ///
+ [Fact]
+ public void EmptyConstuctor_ShouldInitEmpty()
+ {
+ var leadManager = new LeadManager();
+ // No assertions are needed since we are only ensuring the object
+ // initializes without error.
+ }
+
+ ///
+ /// Test the behavior of the TryAddLead method when adding a lead to an
+ /// empty LeadManager. Verifies that the method returns the correct ID and
+ /// updates the wiring state of the contacts and outputs.
+ /// The LeadManager instance to test the
+ /// TryAddLead method on.
+ /// The Lead object to add to the LeadManager.
+ /// The expected ID that should be assigned to the
+ /// lead after it is added.
+ ///
+ [Theory]
+ [MemberData(nameof(TryAddLeadEmptyData))]
+ public void TryAddLead_ShouldReturnCorrectIdWhenLeadMangerIsEmpty(
+ LeadManager leadManager, Lead lead,
+ int expectedId)
+ {
+
+ var results = leadManager.TryAddLead(lead, out var id);
+ // Assert that the operation is successful and returns the expected ID
+ Assert.True(results);
+ Assert.Equal(expectedId, id);
+ // Assert all contacts in the lead are correctly wired in the lead mgr
+ foreach (var contact in lead.ContactSet)
+ {
+ Assert.True(leadManager.IsWiredContact(contact));
+ }
+ // Assert all outputs in the lead are correctly wired in the lead mgr
+ foreach (var output in lead.OutputSet)
+ {
+ Assert.True(leadManager.IsWiredOutput(output));
+ }
+ }
+
+ ///
+ /// Test parameter data for TryAddLead, following the form:
+ /// leadManager (Instance to be used),
+ /// lead (to be added),
+ /// expectedId
+ /// Assuming all global IDs and leads are valid in the session.
+ ///
+ public static IEnumerable