Something went wrong. Try again.
A Thrift language server, formatter, and linter.
lsp linter helix vim vscode thrift
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185package resolver
import ( "testing"
"github.com/karitham/thrift-ls/resolver/resolvertest")
// dungeonFiles gives two dungeon kitchens the same relative layout: the// same include path exists under several include paths, so search order// decides which file wins. The far kitchen (laios) comes first in the// include paths.var dungeonFiles = []string{ "/dungeon/senshi/kitchen/recipes/hotpot.thrift", "/dungeon/senshi/kitchen/dishes.thrift", "/dungeon/senshi/pantry/hotpot.thrift", "/dungeon/laios/kitchen/recipes/hotpot.thrift", "/dungeon/laios/kitchen/dishes.thrift", "/dungeon/laios/pantry/hotpot.thrift",}
func dungeonIncludePaths() []string { return []string{ "/dungeon/laios/kitchen", "/dungeon/laios/pantry", "/dungeon/senshi/pantry", "/dungeon/senshi/kitchen", }}
func TestCandidatesNearestIncludePathWins(t *testing.T) { r := New(dungeonIncludePaths(), WithFS(resolvertest.Seed(dungeonFiles...)))
got := r.Candidates(t.Context(), "/dungeon/senshi/kitchen/recipes/stew.thrift", "recipes/hotpot.thrift") want := []string{ "/dungeon/senshi/kitchen/recipes/hotpot.thrift", "/dungeon/laios/kitchen/recipes/hotpot.thrift", }
if len(got) != len(want) { t.Fatalf("Candidates = %v, want %v", got, want) }
for i := range want { if got[i] != want[i] { t.Fatalf("Candidates = %v, want %v", got, want) } }}
func TestCandidatesOrderedNearestFirst(t *testing.T) { r := New(dungeonIncludePaths(), WithFS(resolvertest.Seed(dungeonFiles...)))
got := r.Candidates(t.Context(), "/dungeon/senshi/kitchen/recipes/stew.thrift", "dishes.thrift") want := []string{ "/dungeon/senshi/kitchen/dishes.thrift", "/dungeon/laios/kitchen/dishes.thrift", }
if len(got) != len(want) { t.Fatalf("Candidates = %v, want %v", got, want) }
for i := range want { if got[i] != want[i] { t.Fatalf("Candidates = %v, want %v", got, want) } }}
func TestCandidatesTiesKeepConfigOrder(t *testing.T) { // From a sibling floor, every root ties on shared prefix, so the // include path order decides. r := New(dungeonIncludePaths(), WithFS(resolvertest.Seed(dungeonFiles...)))
got := r.Candidates(t.Context(), "/dungeon/floor4/main.thrift", "hotpot.thrift") want := []string{ "/dungeon/laios/pantry/hotpot.thrift", "/dungeon/senshi/pantry/hotpot.thrift", }
if len(got) != len(want) { t.Fatalf("Candidates = %v, want %v", got, want) }
for i := range want { if got[i] != want[i] { t.Fatalf("Candidates = %v, want %v", got, want) } }}
func TestResolveUsesNearestCandidate(t *testing.T) { r := New(dungeonIncludePaths(), WithFS(resolvertest.Seed(dungeonFiles...)))
got := r.Resolve(t.Context(), "/dungeon/senshi/kitchen/recipes/stew.thrift", "dishes.thrift") if want := "/dungeon/senshi/kitchen/dishes.thrift"; got != want { t.Errorf("Resolve = %q, want %q", got, want) }}
func TestResolveFallsBackToFileDir(t *testing.T) { r := New(dungeonIncludePaths(), WithFS(resolvertest.Seed(dungeonFiles...)))
cur := "/dungeon/senshi/kitchen/recipes/stew.thrift" got := r.Resolve(t.Context(), cur, "missing.thrift") if want := "/dungeon/senshi/kitchen/recipes/missing.thrift"; got != want { t.Errorf("Resolve = %q, want %q", got, want) }}
func TestSortByProximityKeepsInputOrder(t *testing.T) { paths := []string{"/dungeon/floor1", "/dungeon", "/dungeon/floor1/monsters"}
got := sortByProximity(paths, "/dungeon/floor1/monsters") want := []string{"/dungeon/floor1/monsters", "/dungeon/floor1", "/dungeon"}
for i := range want { if got[i] != want[i] { t.Fatalf("sortByProximity = %v, want %v", got, want) } }
if paths[0] != "/dungeon/floor1" { t.Errorf("input mutated: %v", paths) }}
// Locks the ranking semantics: shared prefix, not filepath.Rel containment// depth. The senshi root shares more components with the file's directory// and wins, though the config lists laios first.func TestCandidatesParentRootOutranksFarRoot(t *testing.T) { r := New([]string{ "/dungeon/laios/recipes", // farther "/dungeon/senshi/recipes", }, WithFS(resolvertest.Seed( "/dungeon/laios/recipes/stew.thrift", "/dungeon/senshi/recipes/stew.thrift", )))
got := r.Resolve(t.Context(), "/dungeon/senshi/recipes/chapter2/stew.thrift", "stew.thrift") if want := "/dungeon/senshi/recipes/stew.thrift"; got != want { t.Errorf("Resolve = %q, want %q", got, want) }}
// The two heuristics disagree here: shared prefix ranks the senshi root// first (3 shared components vs 2), filepath.Rel depth ranks the laios// root first. Shared prefix wins.func TestCandidatesSharedPrefixNotRelDepth(t *testing.T) { r := New([]string{ "/dungeon/laios", // shallower by filepath.Rel "/dungeon/senshi/kitchen2/monsters/beasts", }, WithFS(resolvertest.Seed( "/dungeon/laios/stew.thrift", "/dungeon/senshi/kitchen2/monsters/beasts/stew.thrift", )))
got := r.Resolve(t.Context(), "/dungeon/senshi/kitchen/stew.thrift", "stew.thrift") if want := "/dungeon/senshi/kitchen2/monsters/beasts/stew.thrift"; got != want { t.Errorf("Resolve = %q, want %q", got, want) }}
// POSIX compares case-sensitively: case-differing prefixes are different// directories. Windows components fold case and split backslashes,// regardless of the build platform.func TestSharedDirPrefixCaseSensitivity(t *testing.T) { // POSIX components compare case-sensitively: only the leading "/" // component of the two paths is shared. posixA := sharedComponents("/srv/Data/room", false) posixB := sharedComponents("/SRV/Data/pantry", false)
if n := sharedPrefixLen(posixA, posixB, false); n != 1 { t.Errorf("posix shared prefix = %d, want 1", n) }
as := sharedComponents(`C:\Repo\room`, true) bs := sharedComponents(`c:\repo\pantry`, true)
if n := sharedPrefixLen(as, bs, true); n != 2 { // drive and repo match t.Errorf("windows shared prefix = %d, want 2", n) }}