tests(git-provider): Add basic registration tests

- make ModuleCore internals visible to ModuleTests
This commit is contained in:
Scott 2026-08-10 15:50:24 +10:00
commit 09236e826a
7 changed files with 135 additions and 38 deletions

View file

@ -6,12 +6,18 @@ public class GitManager
private static readonly Lazy<GitManager> GitManagerInstance = new(() => new GitManager());
public static GitManager Instance => GitManagerInstance.Value;
/// <summary>
/// Always returns a new clean instance of GitManager
/// </summary>
internal static GitManager InternalFreshInstance => new();
/// <summary>
/// Simply <see cref="Path.DirectorySeparatorChar"/>.ToString()
/// </summary>
private static readonly string DirectorySeparator = Path.DirectorySeparatorChar.ToString();
private readonly InternalDirectory _repositories;
private readonly Lock _readWriteLock = new();
private GitManager()
{
@ -20,6 +26,7 @@ public class GitManager
_repositories = new InternalDirectory()
{
Name = DirectorySeparator,
InternalPath = DirectorySeparator
};
}
@ -29,18 +36,35 @@ public class GitManager
/// </summary>
/// <param name="absoluteRepositoryLocation"></param>
/// <param name="registrationName"></param>
/// <returns></returns>
public void RegisterRepo(string absoluteRepositoryLocation, string registrationName)
/// <returns>The normalised string the repository was registered against</returns>
public string RegisterRepo(string absoluteRepositoryLocation, string registrationName)
{
// Regardless of if we get a name or not, the fully qualified version for us
// starts with a
var directorySegmentsFromName = NameToSegments(
string.IsNullOrWhiteSpace(registrationName)
// Depending on the caller, it might be possible that they've scripted automatic repo registration. Because I
// don't really want to account to all the subtle ways that can be parallised, I just naively lock on every
// registration attempt. This method should be quick regardless, and I could use ConcurrentDictionary except
// that means every instance of InternalDirectory would need it and yeah nah fuck that I can just lock at the
// top level
lock (_readWriteLock)
{
var normalisedName = NormaliseNamePath(string.IsNullOrWhiteSpace(registrationName)
? new DirectoryInfo(absoluteRepositoryLocation).Name
: registrationName
);
: registrationName);
_repositories.Add(absoluteRepositoryLocation, directorySegmentsFromName);
// Regardless of if we get a name or not, the fully qualified version for us
// starts with a /
var directorySegmentsFromName = NameToSegments(normalisedName);
var added = _repositories.Add(absoluteRepositoryLocation, directorySegmentsFromName);
// Not sure about this, the Add should throw any exceptions on duplicate/failures but for now I'll leave this
// here
if (added == null)
{
throw new Exception("Failed to register location");
}
return normalisedName;
}
}
/// <summary>
@ -50,7 +74,7 @@ public class GitManager
/// <returns></returns>
private Queue<string> NameToSegments(string name)
{
var segments = NormaliseNamePath(name).Split(DirectorySeparator);
var segments = name.Split(DirectorySeparator);
return segments.Length == 1
? new Queue<string>([DirectorySeparator, name])
@ -84,48 +108,55 @@ public class GitManager
public Dictionary<string, InternalDirectory> Children { get; set; } = [];
internal string InternalPath { get; set; }
/// <summary>
/// If not null, this is the absolute location of a registered git repository
/// </summary>
public string? FullRepositoryPath { get; set; }
internal void Add(string absoluteRepositoryLocation, Queue<string> directorySegmentsFromName)
/// <summary>
///
/// </summary>
/// <param name="absoluteRepositoryLocation"></param>
/// <param name="directorySegmentsFromName"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
internal InternalDirectory? Add(string absoluteRepositoryLocation, Queue<string> directorySegmentsFromName)
{
var topStack = directorySegmentsFromName.Dequeue();
if (topStack == Name)
{
// We're at the end of the directory segments so we can safely say we're at the end of the tree so
// we add it to the relevant dictionary
if (directorySegmentsFromName.Count == 0)
{
FullRepositoryPath = absoluteRepositoryLocation;
//Children.Add(topStack, directory);
}
else
{
var nextSegment = directorySegmentsFromName.Peek();
// Attempt to get the next level of the directory. If we don't have a key entry, create one
if (!Children.TryGetValue(nextSegment, out var nextChild))
{
nextChild = new InternalDirectory()
{
Name = nextSegment,
};
Children.Add(nextSegment, nextChild);
}
// add the next
nextChild.Add(absoluteRepositoryLocation, directorySegmentsFromName);
}
}
else
if (topStack != Name)
{
// logically it shouldn't be possible to have a value on top of the stack that _doesn't_ exist, but
// just incase we throw as this should only happen if an Add is attempted on the root and the queue was
// not correctly rooted to /
throw new Exception($"Directory segment does not seem to exist: {topStack}");
}
// We're at the end of the directory segments so we can safely say we're at the end of the tree so
// we add it to the relevant dictionary
if (directorySegmentsFromName.Count == 0)
{
FullRepositoryPath = absoluteRepositoryLocation;
return this;
}
var nextSegment = directorySegmentsFromName.Peek();
// Attempt to get the next level of the directory. If we don't have a key entry, create one
if (!Children.TryGetValue(nextSegment, out var nextChild))
{
nextChild = new InternalDirectory()
{
Name = nextSegment,
InternalPath = Path.Combine(InternalPath, nextSegment)
};
Children.Add(nextSegment, nextChild);
}
// add the next
return nextChild.Add(absoluteRepositoryLocation, directorySegmentsFromName);
}
}
}

View file

@ -7,4 +7,10 @@
<LangVersion>latestmajor</LangVersion>
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>ModuleTests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
</Project>