Forge
csharpc0b81713
1using AgentNotes.Core;
2
3namespace AgentNotesMcp.Tests;
4
5public sealed class LocalSettingsLoaderTests
6{
7 [Fact]
8 public void Bootstrap_MissingConfig_ReturnsExitCode2()
9 {
10 using var clear = TestEnvVarScope.Clear(AgentNotesBootstrap.ConfigEnvVar);
11 var code = AgentNotesBootstrap.TryLoadSettings([], out var settings, out var error);
12 Assert.Equal(AgentNotesBootstrap.ExitMissingConfig, code);
13 Assert.Null(settings);
14 Assert.Contains("--config", error, StringComparison.OrdinalIgnoreCase);
15 }
16
17 [Fact]
18 public void Loader_ResolvesPrimaryFromNamedRoot()
19 {
20 using var root = TempKnowledgeRoot.Create();
21 var tomlPath = AgentNotesTestToml.WriteFromEmbeddedTemplate(root.Path);
22 var settings = LocalSettingsLoader.Load(tomlPath);
23 Assert.Equal(root.Path, settings.PrimaryKnowledgeRoot);
24 Assert.Equal("door-to-singularity", settings.Workspace.DefaultScope);
25 Assert.Equal("work/local/workspace-scope-map-v1.md", settings.Workspace.ScopeMapRelative);
26 }
27
28 [Fact]
29 public void Loader_WithoutWorkspaceSection_UsesEmbeddedNeutralExample()
30 {
31 using var root = TempKnowledgeRoot.Create();
32 var toml = $"""
33 version = 1
34
35 [knowledge]
36 primary = "test"
37
38 [knowledge.roots]
39 test = "{root.Path.Replace('\\', '/')}"
40 """;
41 var path = Path.Combine(Path.GetTempPath(), "AgentNotesMcpTests", $"cfg-{Guid.NewGuid():N}.toml");
42 Directory.CreateDirectory(Path.GetDirectoryName(path)!);
43 File.WriteAllText(path, toml);
44 var settings = LocalSettingsLoader.Load(path);
45 Assert.Equal("example", settings.Workspace.DefaultScope);
46 Assert.Equal("example/workspace-scope-map-v1.md", settings.Workspace.ScopeMapRelative);
47 }
48
49 [Fact]
50 public void Loader_RejectsInvalidWorkspaceScopeMapPath()
51 {
52 using var root = TempKnowledgeRoot.Create();
53 var toml = $"""
54 version = 1
55
56 [knowledge]
57 primary = "test"
58
59 [knowledge.roots]
60 test = "{root.Path.Replace('\\', '/')}"
61
62 [workspace]
63 scope_map = "../evil-map.md"
64 """;
65 var path = Path.Combine(Path.GetTempPath(), "AgentNotesMcpTests", $"cfg-{Guid.NewGuid():N}.toml");
66 Directory.CreateDirectory(Path.GetDirectoryName(path)!);
67 File.WriteAllText(path, toml);
68 var ex = Assert.Throws<InvalidOperationException>(() => LocalSettingsLoader.Load(path));
69 Assert.Contains("relative under knowledge/", ex.Message, StringComparison.OrdinalIgnoreCase);
70 }
71
72 [Fact]
73 public void GetNotesPath_UsesPrimaryRootFromRuntime()
74 {
75 using var root = TempKnowledgeRoot.Create();
76 using var runtime = AgentNotesTestToml.Install(AgentNotesTestToml.WriteFromEmbeddedTemplate(root.Path));
77 var storage = new NotesStorage();
78 var notesPath = storage.GetNotesPath(Path.Combine(root.Path, "any-workspace"));
79 Assert.Equal(Path.Combine(root.Path, "agent-notes.md"), notesPath);
80 }
81
82 [Fact]
83 public void ResolveKnowledgeRoot_UsesRuntimeWithoutToolArgument()
84 {
85 using var root = TempKnowledgeRoot.Create();
86 using var runtime = AgentNotesTestToml.Install(AgentNotesTestToml.WriteFromEmbeddedTemplate(root.Path));
87 var resolved = NotesStorage.ResolveKnowledgeRoot(null);
88 Assert.Equal(root.Path, resolved);
89 }
90
91 private sealed class TestEnvVarScope : IDisposable
92 {
93 private readonly string _name;
94 private readonly string? _previous;
95
96 private TestEnvVarScope(string name, string? previous)
97 {
98 _name = name;
99 _previous = previous;
100 }
101
102 internal static TestEnvVarScope Clear(string name)
103 {
104 var previous = Environment.GetEnvironmentVariable(name);
105 Environment.SetEnvironmentVariable(name, null);
106 return new TestEnvVarScope(name, previous);
107 }
108
109 public void Dispose() => Environment.SetEnvironmentVariable(_name, _previous);
110 }
111
112 internal sealed class TempKnowledgeRoot : IDisposable
113 {
114 internal string Path { get; }
115
116 private TempKnowledgeRoot(string path) => Path = path;
117
118 internal static TempKnowledgeRoot Create()
119 {
120 var path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "AgentNotesMcpTests", "kb", Guid.NewGuid().ToString("N"));
121 Directory.CreateDirectory(System.IO.Path.Combine(path, "knowledge", "work", "local"));
122 NotesStorageTests.SeedTestScopeAliasDefaultsForRoot(path);
123 return new TempKnowledgeRoot(path);
124 }
125
126 public void Dispose()
127 {
128 try
129 {
130 if (Directory.Exists(Path))
131 Directory.Delete(Path, recursive: true);
132 }
133 catch (Exception ex)
134 {
135 throw new InvalidOperationException($"Failed to cleanup: {Path}", ex);
136 }
137 }
138 }
139}
140
View only · write via MCP/CIDE