Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Elastic.Codex/Elastic.Codex.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
<StartupHookSupport Condition="'$(Configuration)' == 'Debug'">true</StartupHookSupport>
</PropertyGroup>

<ItemGroup>
<InternalsVisibleTo Include="Navigation.Tests"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include="RazorSlices"/>
</ItemGroup>
Expand Down
5 changes: 3 additions & 2 deletions src/Elastic.Codex/Sourcing/CodexCloneService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information

using System.IO.Abstractions;
using System.Security;
using Elastic.Documentation.Configuration.Codex;
using Elastic.Documentation.Configuration.Toc;
using Elastic.Documentation.Diagnostics;
Expand Down Expand Up @@ -268,9 +269,9 @@ await context.WriteFileSystem.File.WriteAllTextAsync(
return found;
}
}
catch (UnauthorizedAccessException)
catch (Exception ex) when (ex is UnauthorizedAccessException or SecurityException)
{
// Skip directories we can't access
// Skip directories we can't access (including ScopedFileSystem-blocked hidden dirs)
}

return null;
Expand Down
89 changes: 89 additions & 0 deletions tests/Navigation.Tests/Codex/FindDocsetFileTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.IO.Abstractions.TestingHelpers;
using AwesomeAssertions;
using Elastic.Codex.Sourcing;
using Elastic.Documentation.Configuration;
using Nullean.ScopedFileSystem;

namespace Elastic.Documentation.Navigation.Tests.Codex;

public class FindDocsetFileTests
{
private static readonly string RepoRoot = Path.Join(Paths.WorkingDirectoryRoot.FullName, "repo");

private static ScopedFileSystem CreateScopedFs(MockFileSystem mockFs) =>
FileSystemFactory.ScopeCurrentWorkingDirectory(mockFs);

[Fact]
public void StandardPath_Found()
{
var mockFs = new MockFileSystem(new Dictionary<string, MockFileData>
{
{ Path.Join(RepoRoot, "docs/docset.yml"), new MockFileData("project: test") }
});

var result = CodexCloneService.FindDocsetFile(mockFs, mockFs.DirectoryInfo.New(RepoRoot));

result.Should().NotBeNull();
result.Name.Should().Be("docset.yml");
}

[Fact]
public void NonStandardPath_FoundViaRecursion()
{
var mockFs = new MockFileSystem(new Dictionary<string, MockFileData>
{
{ Path.Join(RepoRoot, "docs-codex/docset.yml"), new MockFileData("project: test") }
});

var result = CodexCloneService.FindDocsetFile(mockFs, mockFs.DirectoryInfo.New(RepoRoot));

result.Should().NotBeNull();
result.Name.Should().Be("docset.yml");
}

[Fact]
public void HiddenDirectory_SkippedByScopedFileSystem()
{
var mockFs = new MockFileSystem(new Dictionary<string, MockFileData>
{
{ Path.Join(RepoRoot, ".github/workflows/ci.yml"), new MockFileData("name: CI") },
{ Path.Join(RepoRoot, "docs-codex/docset.yml"), new MockFileData("project: test") }
});
var scopedFs = CreateScopedFs(mockFs);

var result = CodexCloneService.FindDocsetFile(scopedFs, scopedFs.DirectoryInfo.New(RepoRoot));

result.Should().NotBeNull();
result.Name.Should().Be("docset.yml");
}

[Fact]
public void NoDocset_ReturnsNull()
{
var mockFs = new MockFileSystem(new Dictionary<string, MockFileData>
{
{ Path.Join(RepoRoot, "src/main.py"), new MockFileData("print('hello')") }
});

var result = CodexCloneService.FindDocsetFile(mockFs, mockFs.DirectoryInfo.New(RepoRoot));

result.Should().BeNull();
}

[Fact]
public void NodeModules_Skipped()
{
var mockFs = new MockFileSystem(new Dictionary<string, MockFileData>
{
{ Path.Join(RepoRoot, "node_modules/some-pkg/docset.yml"), new MockFileData("project: fake") }
});

var result = CodexCloneService.FindDocsetFile(mockFs, mockFs.DirectoryInfo.New(RepoRoot));

result.Should().BeNull();
}
}
Loading