221 lines
11 KiB
Go
221 lines
11 KiB
Go
package project_test
|
|
|
|
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/testutil/projecttestutil"
|
|
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
func TestProjectLifetime(t *testing.T) {
|
|
t.Parallel()
|
|
if !bundled.Embedded {
|
|
t.Skip("bundled files are not embedded")
|
|
}
|
|
|
|
t.Run("configured project", func(t *testing.T) {
|
|
t.Parallel()
|
|
files := map[string]any{
|
|
"/home/projects/TS/p1/tsconfig.json": `{
|
|
"compilerOptions": {
|
|
"noLib": true,
|
|
"module": "nodenext",
|
|
"strict": true
|
|
},
|
|
"include": ["src"]
|
|
}`,
|
|
"/home/projects/TS/p1/src/index.ts": `import { x } from "./x";`,
|
|
"/home/projects/TS/p1/src/x.ts": `export const x = 1;`,
|
|
"/home/projects/TS/p1/config.ts": `let x = 1, y = 2;`,
|
|
"/home/projects/TS/p2/tsconfig.json": `{
|
|
"compilerOptions": {
|
|
"noLib": true,
|
|
"module": "nodenext",
|
|
"strict": true
|
|
},
|
|
"include": ["src"]
|
|
}`,
|
|
"/home/projects/TS/p2/src/index.ts": `import { x } from "./x";`,
|
|
"/home/projects/TS/p2/src/x.ts": `export const x = 1;`,
|
|
"/home/projects/TS/p2/config.ts": `let x = 1, y = 2;`,
|
|
"/home/projects/TS/p3/tsconfig.json": `{
|
|
"compilerOptions": {
|
|
"noLib": true,
|
|
"module": "nodenext",
|
|
"strict": true
|
|
},
|
|
"include": ["src"]
|
|
}`,
|
|
"/home/projects/TS/p3/src/index.ts": `import { x } from "./x";`,
|
|
"/home/projects/TS/p3/src/x.ts": `export const x = 1;`,
|
|
"/home/projects/TS/p3/config.ts": `let x = 1, y = 2;`,
|
|
}
|
|
session, utils := projecttestutil.Setup(files)
|
|
snapshot, release := session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 0)
|
|
|
|
// Open files in two projects
|
|
uri1 := lsproto.DocumentUri("file:///home/projects/TS/p1/src/index.ts")
|
|
uri2 := lsproto.DocumentUri("file:///home/projects/TS/p2/src/index.ts")
|
|
session.DidOpenFile(context.Background(), uri1, 1, files["/home/projects/TS/p1/src/index.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
session.DidOpenFile(context.Background(), uri2, 1, files["/home/projects/TS/p2/src/index.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
session.WaitForBackgroundTasks()
|
|
snapshot, release = session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 2)
|
|
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
|
|
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p2/tsconfig.json")) != nil)
|
|
assert.Equal(t, len(utils.Client().WatchFilesCalls()), 1)
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p2/tsconfig.json")) != nil)
|
|
|
|
// Close p1 file and open p3 file
|
|
session.DidCloseFile(context.Background(), uri1)
|
|
uri3 := lsproto.DocumentUri("file:///home/projects/TS/p3/src/index.ts")
|
|
session.DidOpenFile(context.Background(), uri3, 1, files["/home/projects/TS/p3/src/index.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
session.WaitForBackgroundTasks()
|
|
// Should still have two projects, but p1 replaced by p3
|
|
snapshot, release = session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 2)
|
|
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p1/tsconfig.json")) == nil)
|
|
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p2/tsconfig.json")) != nil)
|
|
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p3/tsconfig.json")) != nil)
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p1/tsconfig.json")) == nil)
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p2/tsconfig.json")) != nil)
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p3/tsconfig.json")) != nil)
|
|
assert.Equal(t, len(utils.Client().WatchFilesCalls()), 1)
|
|
assert.Equal(t, len(utils.Client().UnwatchFilesCalls()), 0)
|
|
|
|
// Close p2 and p3 files, open p1 file again
|
|
session.DidCloseFile(context.Background(), uri2)
|
|
session.DidCloseFile(context.Background(), uri3)
|
|
session.DidOpenFile(context.Background(), uri1, 1, files["/home/projects/TS/p1/src/index.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
session.WaitForBackgroundTasks()
|
|
// Should have one project (p1)
|
|
snapshot, release = session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 1)
|
|
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p2/tsconfig.json")) == nil)
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p3/tsconfig.json")) == nil)
|
|
assert.Equal(t, len(utils.Client().WatchFilesCalls()), 1)
|
|
assert.Equal(t, len(utils.Client().UnwatchFilesCalls()), 0)
|
|
})
|
|
|
|
t.Run("unrooted inferred projects", func(t *testing.T) {
|
|
t.Parallel()
|
|
files := map[string]any{
|
|
"/home/projects/TS/p1/src/index.ts": `import { x } from "./x";`,
|
|
"/home/projects/TS/p1/src/x.ts": `export const x = 1;`,
|
|
"/home/projects/TS/p1/config.ts": `let x = 1, y = 2;`,
|
|
"/home/projects/TS/p2/src/index.ts": `import { x } from "./x";`,
|
|
"/home/projects/TS/p2/src/x.ts": `export const x = 1;`,
|
|
"/home/projects/TS/p2/config.ts": `let x = 1, y = 2;`,
|
|
"/home/projects/TS/p3/src/index.ts": `import { x } from "./x";`,
|
|
"/home/projects/TS/p3/src/x.ts": `export const x = 1;`,
|
|
"/home/projects/TS/p3/config.ts": `let x = 1, y = 2;`,
|
|
}
|
|
session, _ := projecttestutil.Setup(files)
|
|
snapshot, release := session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 0)
|
|
|
|
// Open files without workspace roots (empty string) - should create single inferred project
|
|
uri1 := lsproto.DocumentUri("file:///home/projects/TS/p1/src/index.ts")
|
|
uri2 := lsproto.DocumentUri("file:///home/projects/TS/p2/src/index.ts")
|
|
session.DidOpenFile(context.Background(), uri1, 1, files["/home/projects/TS/p1/src/index.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
session.DidOpenFile(context.Background(), uri2, 1, files["/home/projects/TS/p2/src/index.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
|
|
// Should have one inferred project
|
|
snapshot, release = session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 1)
|
|
assert.Assert(t, snapshot.ProjectCollection.InferredProject() != nil)
|
|
|
|
// Close p1 file and open p3 file
|
|
session.DidCloseFile(context.Background(), uri1)
|
|
uri3 := lsproto.DocumentUri("file:///home/projects/TS/p3/src/index.ts")
|
|
session.DidOpenFile(context.Background(), uri3, 1, files["/home/projects/TS/p3/src/index.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
|
|
// Should still have one inferred project
|
|
snapshot, release = session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 1)
|
|
assert.Assert(t, snapshot.ProjectCollection.InferredProject() != nil)
|
|
|
|
// Close p2 and p3 files, open p1 file again
|
|
session.DidCloseFile(context.Background(), uri2)
|
|
session.DidCloseFile(context.Background(), uri3)
|
|
session.DidOpenFile(context.Background(), uri1, 1, files["/home/projects/TS/p1/src/index.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
|
|
// Should still have one inferred project
|
|
snapshot, release = session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 1)
|
|
assert.Assert(t, snapshot.ProjectCollection.InferredProject() != nil)
|
|
})
|
|
|
|
t.Run("file moves from inferred to configured project", func(t *testing.T) {
|
|
t.Parallel()
|
|
files := map[string]any{
|
|
"/home/projects/ts/foo.ts": `export const foo = 1;`,
|
|
"/home/projects/ts/p1/tsconfig.json": `{
|
|
"compilerOptions": {
|
|
"noLib": true,
|
|
"module": "nodenext",
|
|
"strict": true
|
|
},
|
|
"include": ["main.ts"]
|
|
}`,
|
|
"/home/projects/ts/p1/main.ts": `import { foo } from "../foo"; console.log(foo);`,
|
|
}
|
|
session, _ := projecttestutil.Setup(files)
|
|
|
|
// Open foo.ts first - should create inferred project since no tsconfig found initially
|
|
fooUri := lsproto.DocumentUri("file:///home/projects/ts/foo.ts")
|
|
session.DidOpenFile(context.Background(), fooUri, 1, files["/home/projects/ts/foo.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
|
|
// Should have one inferred project
|
|
snapshot, release := session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 1)
|
|
assert.Assert(t, snapshot.ProjectCollection.InferredProject() != nil)
|
|
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p1/tsconfig.json")) == nil)
|
|
|
|
// Now open main.ts - should trigger discovery of tsconfig.json and move foo.ts to configured project
|
|
mainUri := lsproto.DocumentUri("file:///home/projects/ts/p1/main.ts")
|
|
session.DidOpenFile(context.Background(), mainUri, 1, files["/home/projects/ts/p1/main.ts"].(string), lsproto.LanguageKindTypeScript)
|
|
|
|
// Should now have one configured project and no inferred project
|
|
snapshot, release = session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 1)
|
|
assert.Assert(t, snapshot.ProjectCollection.InferredProject() == nil)
|
|
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
|
|
|
|
// Config file should be present
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
|
|
|
|
// Close main.ts - configured project should remain because foo.ts is still open
|
|
session.DidCloseFile(context.Background(), mainUri)
|
|
snapshot, release = session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 1)
|
|
assert.Assert(t, snapshot.ProjectCollection.ConfiguredProject(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
|
|
|
|
// Close foo.ts - configured project should be retained until next file open
|
|
session.DidCloseFile(context.Background(), fooUri)
|
|
snapshot, release = session.Snapshot()
|
|
defer release()
|
|
assert.Equal(t, len(snapshot.ProjectCollection.Projects()), 1)
|
|
assert.Assert(t, snapshot.ConfigFileRegistry.GetConfig(tspath.Path("/home/projects/ts/p1/tsconfig.json")) != nil)
|
|
})
|
|
}
|