using ClaudeDo.Worker.Skills; namespace ClaudeDo.Worker.Tests.Skills; /// /// Test double for IRepoCloner: "clones" by copying a pre-built local fixture directory, /// so tests never touch the network or invoke real git. One fixture dir + pinned ref can /// be registered per source URL. /// public sealed class FakeRepoCloner : IRepoCloner { private readonly Dictionary _sources = new(); private int _cloneCount; public int CloneCount => _cloneCount; public void Register(string url, string fixtureDir, string pinnedRef) => _sources[url] = (fixtureDir, pinnedRef); public Task CloneAsync(string url, string destDir, CancellationToken ct) { _cloneCount++; if (!_sources.TryGetValue(url, out var source)) throw new InvalidOperationException($"FakeRepoCloner has no fixture registered for '{url}'."); CopyDirectory(source.FixtureDir, destDir); return Task.FromResult(new ClonedRepo(destDir, source.PinnedRef)); } private static void CopyDirectory(string sourceDir, string destDir) { Directory.CreateDirectory(destDir); foreach (var file in Directory.EnumerateFiles(sourceDir, "*", SearchOption.AllDirectories)) { var relative = Path.GetRelativePath(sourceDir, file); var destPath = Path.Combine(destDir, relative); var destParent = Path.GetDirectoryName(destPath); if (!string.IsNullOrEmpty(destParent)) Directory.CreateDirectory(destParent); File.Copy(file, destPath, overwrite: true); } } }