// Copyright 2020 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package fake import ( "context" "io/ioutil" "os" "sort" "testing" "time" "golang.org/x/tools/internal/lsp/protocol" ) const data = ` -- go.mod -- go 1.12 -- nested/README.md -- Hello World! ` func newWorkdir(t *testing.T) (*Workdir, <-chan []FileEvent, func()) { t.Helper() tmpdir, err := ioutil.TempDir("", "goplstest-workdir-") if err != nil { t.Fatal(err) } wd := NewWorkdir(tmpdir) if err := wd.writeInitialFiles(data); err != nil { t.Fatal(err) } cleanup := func() { if err := os.RemoveAll(tmpdir); err != nil { t.Error(err) } } fileEvents := make(chan []FileEvent) watch := func(_ context.Context, events []FileEvent) { fileEvents <- events } wd.AddWatcher(watch) return wd, fileEvents, cleanup } func TestWorkdir_ReadFile(t *testing.T) { wd, _, cleanup := newWorkdir(t) defer cleanup() got, err := wd.ReadFile("nested/README.md") if err != nil { t.Fatal(err) } want := "Hello World!\n" if got != want { t.Errorf("reading workdir file, got %q, want %q", got, want) } } func TestWorkdir_WriteFile(t *testing.T) { wd, events, cleanup := newWorkdir(t) defer cleanup() ctx := context.Background() tests := []struct { path string wantType protocol.FileChangeType }{ {"data.txt", protocol.Created}, {"nested/README.md", protocol.Changed}, } for _, test := range tests { if err := wd.WriteFile(ctx, test.path, "42"); err != nil { t.Fatal(err) } es := <-events if got := len(es); got != 1 { t.Fatalf("len(events) = %d, want 1", got) } if es[0].Path != test.path { t.Errorf("event.Path = %q, want %q", es[0].Path, test.path) } if es[0].ProtocolEvent.Type != test.wantType { t.Errorf("event type = %v, want %v", es[0].ProtocolEvent.Type, test.wantType) } got, err := wd.ReadFile(test.path) if err != nil { t.Fatal(err) } want := "42" if got != want { t.Errorf("ws.ReadFile(%q) = %q, want %q", test.path, got, want) } } } func TestWorkdir_ListFiles(t *testing.T) { wd, _, cleanup := newWorkdir(t) defer cleanup() checkFiles := func(dir string, want []string) { files, err := wd.ListFiles(dir) if err != nil { t.Fatal(err) } sort.Strings(want) var got []string for p := range files { got = append(got, p) } sort.Strings(got) if len(got) != len(want) { t.Fatalf("ListFiles(): len = %d, want %d; got=%v; want=%v", len(got), len(want), got, want) } for i, f := range got { if f != want[i] { t.Errorf("ListFiles()[%d] = %s, want %s", i, f, want[i]) } } } checkFiles(".", []string{"go.mod", "nested/README.md"}) checkFiles("nested", []string{"nested/README.md"}) } func TestWorkdir_CheckForFileChanges(t *testing.T) { t.Skip("broken on darwin-amd64-10_12") wd, events, cleanup := newWorkdir(t) defer cleanup() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() checkChange := func(path string, typ protocol.FileChangeType) { if err := wd.CheckForFileChanges(ctx); err != nil { t.Fatal(err) } var gotEvt FileEvent select { case <-ctx.Done(): t.Fatal(ctx.Err()) case ev := <-events: gotEvt = ev[0] } // Only check relative path and Type if gotEvt.Path != path || gotEvt.ProtocolEvent.Type != typ { t.Errorf("file events: got %v, want {Path: %s, Type: %v}", gotEvt, path, typ) } } // Sleep some positive amount of time to ensure a distinct mtime. time.Sleep(100 * time.Millisecond) if err := WriteFileData("go.mod", []byte("module foo.test\n"), wd.RelativeTo); err != nil { t.Fatal(err) } checkChange("go.mod", protocol.Changed) if err := WriteFileData("newFile", []byte("something"), wd.RelativeTo); err != nil { t.Fatal(err) } checkChange("newFile", protocol.Created) fp := wd.AbsPath("newFile") if err := os.Remove(fp); err != nil { t.Fatal(err) } checkChange("newFile", protocol.Deleted) } func TestSplitModuleVersionPath(t *testing.T) { tests := []struct { path string wantModule, wantVersion, wantSuffix string }{ {"foo.com@v1.2.3/bar", "foo.com", "v1.2.3", "bar"}, {"foo.com/module@v1.2.3/bar", "foo.com/module", "v1.2.3", "bar"}, {"foo.com@v1.2.3", "foo.com", "v1.2.3", ""}, {"std@v1.14.0", "std", "v1.14.0", ""}, {"another/module/path", "another/module/path", "", ""}, } for _, test := range tests { module, version, suffix := splitModuleVersionPath(test.path) if module != test.wantModule || version != test.wantVersion || suffix != test.wantSuffix { t.Errorf("splitModuleVersionPath(%q) =\n\t(%q, %q, %q)\nwant\n\t(%q, %q, %q)", test.path, module, version, suffix, test.wantModule, test.wantVersion, test.wantSuffix) } } }