- Add options.json parser with mdDoc support - Add nixpkgs indexer using nix-build - Implement all MCP tool handlers: - search_options: Full-text search with filters - get_option: Option details with children - get_file: Fetch file contents - index_revision: Build and index options - list_revisions: Show indexed versions - delete_revision: Remove indexed data - Add parser tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
155 lines
3.5 KiB
Go
155 lines
3.5 KiB
Go
package nixos
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseOptions(t *testing.T) {
|
|
// Sample options.json content
|
|
input := `{
|
|
"services.nginx.enable": {
|
|
"declarations": ["/nix/store/xxx-source/nixos/modules/services/web-servers/nginx/default.nix"],
|
|
"default": false,
|
|
"description": "Whether to enable Nginx Web Server.",
|
|
"readOnly": false,
|
|
"type": "boolean"
|
|
},
|
|
"services.nginx.package": {
|
|
"declarations": ["/nix/store/xxx-source/nixos/modules/services/web-servers/nginx/default.nix"],
|
|
"default": {},
|
|
"description": {"_type": "mdDoc", "text": "The nginx package to use."},
|
|
"readOnly": false,
|
|
"type": "package"
|
|
},
|
|
"services.caddy.enable": {
|
|
"declarations": ["/nix/store/xxx-source/nixos/modules/services/web-servers/caddy/default.nix"],
|
|
"default": false,
|
|
"description": "Enable Caddy web server",
|
|
"readOnly": false,
|
|
"type": "boolean"
|
|
}
|
|
}`
|
|
|
|
options, err := ParseOptions(strings.NewReader(input))
|
|
if err != nil {
|
|
t.Fatalf("ParseOptions failed: %v", err)
|
|
}
|
|
|
|
if len(options) != 3 {
|
|
t.Errorf("Expected 3 options, got %d", len(options))
|
|
}
|
|
|
|
// Check nginx.enable
|
|
opt := options["services.nginx.enable"]
|
|
if opt == nil {
|
|
t.Fatal("Expected services.nginx.enable option")
|
|
}
|
|
if opt.Type != "boolean" {
|
|
t.Errorf("Type = %q, want boolean", opt.Type)
|
|
}
|
|
if opt.Description != "Whether to enable Nginx Web Server." {
|
|
t.Errorf("Description = %q", opt.Description)
|
|
}
|
|
if opt.Default != "false" {
|
|
t.Errorf("Default = %q, want false", opt.Default)
|
|
}
|
|
if len(opt.Declarations) != 1 {
|
|
t.Errorf("Expected 1 declaration, got %d", len(opt.Declarations))
|
|
}
|
|
// Check declaration path normalization
|
|
if !strings.HasPrefix(opt.Declarations[0], "nixos/") {
|
|
t.Errorf("Declaration path not normalized: %q", opt.Declarations[0])
|
|
}
|
|
|
|
// Check nginx.package (mdDoc description)
|
|
opt = options["services.nginx.package"]
|
|
if opt == nil {
|
|
t.Fatal("Expected services.nginx.package option")
|
|
}
|
|
if opt.Description != "The nginx package to use." {
|
|
t.Errorf("Description = %q (mdDoc not extracted)", opt.Description)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeDeclarationPath(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
expect string
|
|
}{
|
|
{
|
|
"/nix/store/xxx-source/nixos/modules/services/web-servers/nginx/default.nix",
|
|
"nixos/modules/services/web-servers/nginx/default.nix",
|
|
},
|
|
{
|
|
"/nix/store/xxx/pkgs/top-level/all-packages.nix",
|
|
"pkgs/top-level/all-packages.nix",
|
|
},
|
|
{
|
|
"/nix/store/abc123/lib/types.nix",
|
|
"lib/types.nix",
|
|
},
|
|
{
|
|
"relative/path.nix",
|
|
"relative/path.nix",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.input, func(t *testing.T) {
|
|
got := normalizeDeclarationPath(tt.input)
|
|
if got != tt.expect {
|
|
t.Errorf("normalizeDeclarationPath(%q) = %q, want %q", tt.input, got, tt.expect)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExtractDescription(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input interface{}
|
|
expect string
|
|
}{
|
|
{
|
|
"string",
|
|
"Simple description",
|
|
"Simple description",
|
|
},
|
|
{
|
|
"mdDoc",
|
|
map[string]interface{}{
|
|
"_type": "mdDoc",
|
|
"text": "Markdown description",
|
|
},
|
|
"Markdown description",
|
|
},
|
|
{
|
|
"description key",
|
|
map[string]interface{}{
|
|
"description": "Nested description",
|
|
},
|
|
"Nested description",
|
|
},
|
|
{
|
|
"nil",
|
|
nil,
|
|
"",
|
|
},
|
|
{
|
|
"empty map",
|
|
map[string]interface{}{},
|
|
"",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := extractDescription(tt.input)
|
|
if got != tt.expect {
|
|
t.Errorf("extractDescription = %q, want %q", got, tt.expect)
|
|
}
|
|
})
|
|
}
|
|
}
|