mirror of
https://github.com/lukaszraczylo/filepuff-mcp.git
synced 2026-06-05 22:23:50 +00:00
5ad975ee7a
* v2.0: token-optimization overhaul Additive (backward-compatible flags): - file_read: skeleton mode, strip (imports/license/block_comments), compact_line_numbers, 8-char etag with prefix-match compat - ast_query: format=verbose|compact|location, pagination cursor - file_search: cluster mode, pagination cursor - lsp_query (references): compact output Breaking (v2): - Preambles removed; opt-in verbose=true restores - edit_apply: response=count|diff|none, default count - ping tool removed - symbol_at/find_definition/find_references merged into lsp_query - Tool descriptions trimmed -83%, help moved to filepuff://help/<tool> - Batch file_read dedups by etag Protocol: - ResourceLink returned for file_read >64 KiB (force_inline override) - OnAfterInitialize hook reads capabilities.experimental.filepuff for session defaults (default_format, default_max_results, default_cluster, compact_refs, line_numbers, resource_link_threshold) * fix: drop --max-total-count from ripgrep args The flag does not exist in stable ripgrep (confirmed up to 15.1.0 -- "unrecognized flag --max-total-count, similar flags that are available: --max-count"). Every file_search call failed on hosts with stock rg. --max-count is per-file, not a drop-in replacement, so rely on the in-process truncation in parseOutput that was already the documented safety net.
187 lines
6.4 KiB
Go
187 lines
6.4 KiB
Go
package server
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
// TestParseSessionPrefsEmpty verifies zero-value result for nil/empty input.
|
|
func TestParseSessionPrefsEmpty(t *testing.T) {
|
|
p := ParseSessionPrefs(nil)
|
|
if p.ASTQueryFormat != "" {
|
|
t.Errorf("ASTQueryFormat: want \"\", got %q", p.ASTQueryFormat)
|
|
}
|
|
if p.DefaultMaxResults != 0 {
|
|
t.Errorf("DefaultMaxResults: want 0, got %d", p.DefaultMaxResults)
|
|
}
|
|
if p.DefaultCluster != nil {
|
|
t.Errorf("DefaultCluster: want nil, got %v", *p.DefaultCluster)
|
|
}
|
|
if p.CompactRefs != nil {
|
|
t.Errorf("CompactRefs: want nil, got %v", *p.CompactRefs)
|
|
}
|
|
if p.LineNumbers != "" {
|
|
t.Errorf("LineNumbers: want \"\", got %q", p.LineNumbers)
|
|
}
|
|
if p.ResourceLinkThreshold != 0 {
|
|
t.Errorf("ResourceLinkThreshold: want 0, got %d", p.ResourceLinkThreshold)
|
|
}
|
|
|
|
// Also test with an empty (non-nil) map.
|
|
p2 := ParseSessionPrefs(map[string]any{})
|
|
if p2.ASTQueryFormat != "" || p2.DefaultMaxResults != 0 {
|
|
t.Error("empty map should produce zero-value prefs")
|
|
}
|
|
}
|
|
|
|
// TestParseSessionPrefsAllFields verifies full round-trip with all supported keys.
|
|
func TestParseSessionPrefsAllFields(t *testing.T) {
|
|
raw := map[string]any{
|
|
"terse": true, // no-op; should not produce an error
|
|
"default_format": "compact",
|
|
"default_max_results": float64(50), // JSON numbers decode as float64
|
|
"default_cluster": true,
|
|
"compact_refs": true,
|
|
"line_numbers": "none",
|
|
"resource_link_threshold": float64(32768),
|
|
}
|
|
p := ParseSessionPrefs(raw)
|
|
|
|
if p.ASTQueryFormat != "compact" {
|
|
t.Errorf("ASTQueryFormat: want \"compact\", got %q", p.ASTQueryFormat)
|
|
}
|
|
if p.DefaultMaxResults != 50 {
|
|
t.Errorf("DefaultMaxResults: want 50, got %d", p.DefaultMaxResults)
|
|
}
|
|
if p.DefaultCluster == nil || !*p.DefaultCluster {
|
|
t.Errorf("DefaultCluster: want true, got %v", p.DefaultCluster)
|
|
}
|
|
if p.CompactRefs == nil || !*p.CompactRefs {
|
|
t.Errorf("CompactRefs: want true, got %v", p.CompactRefs)
|
|
}
|
|
if p.LineNumbers != "none" {
|
|
t.Errorf("LineNumbers: want \"none\", got %q", p.LineNumbers)
|
|
}
|
|
if p.ResourceLinkThreshold != 32768 {
|
|
t.Errorf("ResourceLinkThreshold: want 32768, got %d", p.ResourceLinkThreshold)
|
|
}
|
|
}
|
|
|
|
// TestParseSessionPrefsLineNumbersVariants tests all valid line_numbers values.
|
|
func TestParseSessionPrefsLineNumbersVariants(t *testing.T) {
|
|
for _, want := range []string{"none", "compact", "full"} {
|
|
p := ParseSessionPrefs(map[string]any{"line_numbers": want})
|
|
if p.LineNumbers != want {
|
|
t.Errorf("line_numbers=%q: got %q", want, p.LineNumbers)
|
|
}
|
|
}
|
|
// Invalid value → ignored (empty string).
|
|
p := ParseSessionPrefs(map[string]any{"line_numbers": "bogus"})
|
|
if p.LineNumbers != "" {
|
|
t.Errorf("invalid line_numbers should be ignored, got %q", p.LineNumbers)
|
|
}
|
|
}
|
|
|
|
// TestParseSessionPrefsFormatVariants tests all valid default_format values.
|
|
func TestParseSessionPrefsFormatVariants(t *testing.T) {
|
|
for _, want := range []string{"verbose", "compact", "location"} {
|
|
p := ParseSessionPrefs(map[string]any{"default_format": want})
|
|
if p.ASTQueryFormat != want {
|
|
t.Errorf("default_format=%q: got %q", want, p.ASTQueryFormat)
|
|
}
|
|
}
|
|
// Invalid value → ignored.
|
|
p := ParseSessionPrefs(map[string]any{"default_format": "yaml"})
|
|
if p.ASTQueryFormat != "" {
|
|
t.Errorf("invalid format should be ignored, got %q", p.ASTQueryFormat)
|
|
}
|
|
}
|
|
|
|
// TestParseSessionPrefsTypeMismatch verifies that wrong types are silently ignored.
|
|
func TestParseSessionPrefsTypeMismatch(t *testing.T) {
|
|
raw := map[string]any{
|
|
"default_format": 123, // wrong type (int instead of string)
|
|
"default_max_results": "fifty", // wrong type
|
|
"default_cluster": "yes", // wrong type (string instead of bool)
|
|
"compact_refs": 42, // wrong type
|
|
"line_numbers": true, // wrong type
|
|
"resource_link_threshold": "big", // wrong type
|
|
}
|
|
p := ParseSessionPrefs(raw)
|
|
if p.ASTQueryFormat != "" {
|
|
t.Errorf("type mismatch for format should produce empty, got %q", p.ASTQueryFormat)
|
|
}
|
|
if p.DefaultMaxResults != 0 {
|
|
t.Errorf("type mismatch for max_results should produce 0, got %d", p.DefaultMaxResults)
|
|
}
|
|
if p.DefaultCluster != nil {
|
|
t.Errorf("type mismatch for cluster should produce nil")
|
|
}
|
|
if p.CompactRefs != nil {
|
|
t.Errorf("type mismatch for compact_refs should produce nil")
|
|
}
|
|
if p.LineNumbers != "" {
|
|
t.Errorf("type mismatch for line_numbers should produce empty, got %q", p.LineNumbers)
|
|
}
|
|
if p.ResourceLinkThreshold != 0 {
|
|
t.Errorf("type mismatch for threshold should produce 0, got %d", p.ResourceLinkThreshold)
|
|
}
|
|
}
|
|
|
|
// TestParseSessionPrefsNegativeValues verifies negative numbers are rejected.
|
|
func TestParseSessionPrefsNegativeValues(t *testing.T) {
|
|
p := ParseSessionPrefs(map[string]any{
|
|
"default_max_results": float64(-5),
|
|
"resource_link_threshold": float64(-1),
|
|
})
|
|
if p.DefaultMaxResults != 0 {
|
|
t.Errorf("negative max_results should be rejected, got %d", p.DefaultMaxResults)
|
|
}
|
|
if p.ResourceLinkThreshold != 0 {
|
|
t.Errorf("negative threshold should be rejected, got %d", p.ResourceLinkThreshold)
|
|
}
|
|
}
|
|
|
|
// TestParseSessionPrefsIntCoercion verifies int and int64 inputs also work.
|
|
func TestParseSessionPrefsIntCoercion(t *testing.T) {
|
|
p := ParseSessionPrefs(map[string]any{
|
|
"default_max_results": int(25),
|
|
"resource_link_threshold": int64(16384),
|
|
})
|
|
if p.DefaultMaxResults != 25 {
|
|
t.Errorf("int max_results: want 25, got %d", p.DefaultMaxResults)
|
|
}
|
|
if p.ResourceLinkThreshold != 16384 {
|
|
t.Errorf("int64 threshold: want 16384, got %d", p.ResourceLinkThreshold)
|
|
}
|
|
}
|
|
|
|
// TestParseSessionPrefsClusterFalse ensures default_cluster=false stores a non-nil false.
|
|
func TestParseSessionPrefsClusterFalse(t *testing.T) {
|
|
p := ParseSessionPrefs(map[string]any{"default_cluster": false})
|
|
if p.DefaultCluster == nil {
|
|
t.Error("default_cluster=false should store non-nil pointer")
|
|
}
|
|
if *p.DefaultCluster != false {
|
|
t.Error("default_cluster=false: want false pointer")
|
|
}
|
|
}
|
|
|
|
// TestSessionPrefsAtomicStore verifies sessionPrefsPtr is readable after Store.
|
|
func TestSessionPrefsAtomicStore(t *testing.T) {
|
|
var sp sessionPrefsPtr
|
|
if sp.Load() != nil {
|
|
t.Error("uninitialised Load() should return nil")
|
|
}
|
|
|
|
prefs := ParseSessionPrefs(map[string]any{"default_format": "compact"})
|
|
sp.Store(&prefs)
|
|
|
|
loaded := sp.Load()
|
|
if loaded == nil {
|
|
t.Fatal("Load() returned nil after Store")
|
|
}
|
|
if loaded.ASTQueryFormat != "compact" {
|
|
t.Errorf("loaded format: want compact, got %q", loaded.ASTQueryFormat)
|
|
}
|
|
}
|