kittenipc/kitcom/internal/tsgo/project/refcounting_test.go
2025-10-15 10:12:44 +03:00

136 lines
6.0 KiB
Go

package project
import (
"context"
"testing"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/bundled"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/lsp/lsproto"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/vfs/vfstest"
"gotest.tools/v3/assert"
)
func TestRefCountingCaches(t *testing.T) {
t.Parallel()
if !bundled.Embedded {
t.Skip("bundled files are not embedded")
}
setup := func(files map[string]any) *Session {
fs := bundled.WrapFS(vfstest.FromMap(files, false /*useCaseSensitiveFileNames*/))
session := NewSession(&SessionInit{
Options: &SessionOptions{
CurrentDirectory: "/",
DefaultLibraryPath: bundled.LibPath(),
TypingsLocation: "/home/src/Library/Caches/typescript",
PositionEncoding: lsproto.PositionEncodingKindUTF8,
WatchEnabled: false,
LoggingEnabled: false,
},
FS: fs,
})
return session
}
t.Run("parseCache", func(t *testing.T) {
t.Parallel()
files := map[string]any{
"/user/username/projects/myproject/src/main.ts": "const x = 1;",
"/user/username/projects/myproject/src/utils.ts": "export function util() {}",
}
t.Run("reuse unchanged file", func(t *testing.T) {
t.Parallel()
session := setup(files)
session.DidOpenFile(context.Background(), "file:///user/username/projects/myproject/src/main.ts", 1, files["/user/username/projects/myproject/src/main.ts"].(string), lsproto.LanguageKindTypeScript)
session.DidOpenFile(context.Background(), "file:///user/username/projects/myproject/src/utils.ts", 1, files["/user/username/projects/myproject/src/utils.ts"].(string), lsproto.LanguageKindTypeScript)
snapshot, release := session.Snapshot()
program := snapshot.ProjectCollection.InferredProject().Program
main := program.GetSourceFile("/user/username/projects/myproject/src/main.ts")
utils := program.GetSourceFile("/user/username/projects/myproject/src/utils.ts")
mainEntry, _ := session.parseCache.entries.Load(newParseCacheKey(main.ParseOptions(), main.ScriptKind))
utilsEntry, _ := session.parseCache.entries.Load(newParseCacheKey(utils.ParseOptions(), utils.ScriptKind))
assert.Equal(t, mainEntry.refCount, 1)
assert.Equal(t, utilsEntry.refCount, 1)
session.DidChangeFile(context.Background(), "file:///user/username/projects/myproject/src/main.ts", 2, []lsproto.TextDocumentContentChangePartialOrWholeDocument{
{
Partial: &lsproto.TextDocumentContentChangePartial{
Range: lsproto.Range{
Start: lsproto.Position{Line: 0, Character: 0},
End: lsproto.Position{Line: 0, Character: 12},
},
Text: "const x = 2;",
},
},
})
ls, err := session.GetLanguageService(context.Background(), "file:///user/username/projects/myproject/src/main.ts")
assert.NilError(t, err)
assert.Assert(t, ls.GetProgram().GetSourceFile("/user/username/projects/myproject/src/main.ts") != main)
assert.Equal(t, ls.GetProgram().GetSourceFile("/user/username/projects/myproject/src/utils.ts"), utils)
assert.Equal(t, mainEntry.refCount, 2)
assert.Equal(t, utilsEntry.refCount, 2)
release()
assert.Equal(t, mainEntry.refCount, 1)
assert.Equal(t, utilsEntry.refCount, 1)
})
t.Run("release file on close", func(t *testing.T) {
t.Parallel()
session := setup(files)
session.DidOpenFile(context.Background(), "file:///user/username/projects/myproject/src/main.ts", 1, files["/user/username/projects/myproject/src/main.ts"].(string), lsproto.LanguageKindTypeScript)
session.DidOpenFile(context.Background(), "file:///user/username/projects/myproject/src/utils.ts", 1, files["/user/username/projects/myproject/src/utils.ts"].(string), lsproto.LanguageKindTypeScript)
snapshot, release := session.Snapshot()
program := snapshot.ProjectCollection.InferredProject().Program
main := program.GetSourceFile("/user/username/projects/myproject/src/main.ts")
utils := program.GetSourceFile("/user/username/projects/myproject/src/utils.ts")
release()
mainEntry, _ := session.parseCache.entries.Load(newParseCacheKey(main.ParseOptions(), main.ScriptKind))
utilsEntry, _ := session.parseCache.entries.Load(newParseCacheKey(utils.ParseOptions(), utils.ScriptKind))
assert.Equal(t, mainEntry.refCount, 1)
assert.Equal(t, utilsEntry.refCount, 1)
session.DidCloseFile(context.Background(), "file:///user/username/projects/myproject/src/main.ts")
_, err := session.GetLanguageService(context.Background(), "file:///user/username/projects/myproject/src/utils.ts")
assert.NilError(t, err)
assert.Equal(t, utilsEntry.refCount, 1)
assert.Equal(t, mainEntry.refCount, 0)
mainEntry, ok := session.parseCache.entries.Load(newParseCacheKey(main.ParseOptions(), main.ScriptKind))
assert.Equal(t, ok, false)
})
})
t.Run("extendedConfigCache", func(t *testing.T) {
files := map[string]any{
"/user/username/projects/myproject/tsconfig.json": `{
"extends": "./tsconfig.base.json"
}`,
"/user/username/projects/myproject/tsconfig.base.json": `{
"compilerOptions": {}
}`,
"/user/username/projects/myproject/src/main.ts": "const x = 1;",
}
t.Run("release extended configs with project close", func(t *testing.T) {
t.Parallel()
session := setup(files)
session.DidOpenFile(context.Background(), "file:///user/username/projects/myproject/src/main.ts", 1, files["/user/username/projects/myproject/src/main.ts"].(string), lsproto.LanguageKindTypeScript)
snapshot, release := session.Snapshot()
config := snapshot.ConfigFileRegistry.GetConfig("/user/username/projects/myproject/tsconfig.json")
assert.Equal(t, config.ExtendedSourceFiles()[0], "/user/username/projects/myproject/tsconfig.base.json")
extendedConfigEntry, _ := session.extendedConfigCache.entries.Load("/user/username/projects/myproject/tsconfig.base.json")
assert.Equal(t, extendedConfigEntry.refCount, 1)
release()
session.DidCloseFile(context.Background(), "file:///user/username/projects/myproject/src/main.ts")
session.DidOpenFile(context.Background(), "untitled:Untitled-1", 1, "", lsproto.LanguageKindTypeScript)
assert.Equal(t, extendedConfigEntry.refCount, 0)
})
})
}