turbo-editors/turbo-moonbitpublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-moonbit.git
git clone ssh://git@rickub.com/turbo-editors/turbo-moonbit.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

main_test.go · 157 lines · 5.0 KBGo Blame HistoryRaw
📦 Turbo MoonBit cc1f595 k33g 15h ago1package main
2
3import (
4 "flag"
5 "os"
6 "path/filepath"
7 "slices"
8 "testing"
9
10 "rickub.com/turbo-editors/turbo-core/app"
11 "rickub.com/turbo-editors/turbo-core/settings"
12
13 "rickub.com/turbo-editors/turbo-moonbit/internal/moonbitlang"
14)
15
16// withArgs runs the command line parser against a fixed argument list, and
17// restores the real one afterwards so tests do not affect each other.
18func withArgs(t *testing.T, args ...string) options {
19 t.Helper()
20
21 realArgs, realFlags := os.Args, flag.CommandLine
22 t.Cleanup(func() { os.Args, flag.CommandLine = realArgs, realFlags })
23
24 os.Args = append([]string{"turbo-moonbit"}, args...)
25 flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
26 return parseFlags()
27}
28
29func TestFilesAreWhatIsLeftAfterTheFlags(t *testing.T) {
30 opts := withArgs(t, "-no-lsp", "main.mbt", "lib/x.mbt")
31
32 if !opts.noLSP {
33 t.Error("-no-lsp was not read")
34 }
35 if want := []string{"main.mbt", "lib/x.mbt"}; !slices.Equal(opts.files, want) {
36 t.Errorf("files = %v, want %v", opts.files, want)
37 }
38}
39
40func TestTheThemeFlagDefaultsToEmptyRatherThanToAName(t *testing.T) {
41 // Empty is what lets "was -theme given?" still be answered afterwards, and
42 // that is what lets the project's settings fill it in without overriding an
43 // explicit choice.
44 if opts := withArgs(t); opts.theme != "" {
45 t.Errorf("theme = %q with no flag, want the empty string", opts.theme)
46 }
47}
48
49func TestTheThemeFlagBeatsTheProjectSettings(t *testing.T) {
50 project := settings.Default()
51 project.Theme = "cobalt"
52
53 if got := themeName(options{theme: "monochrome"}, project); got != "monochrome" {
54 t.Errorf("themeName() = %q, want the flag's %q", got, "monochrome")
55 }
56}
57
58func TestTheProjectSettingsBeatTheBuiltInDefault(t *testing.T) {
59 project := settings.Default()
60 project.Theme = "cobalt"
61
62 if got := themeName(options{}, project); got != "cobalt" {
63 t.Errorf("themeName() = %q, want the project's %q", got, "cobalt")
64 }
65}
66
67func TestTheBuiltInDefaultIsUsedWhenNobodySaysOtherwise(t *testing.T) {
68 if got := themeName(options{}, settings.Default()); got == "" {
69 t.Error("themeName() = \"\" with nothing set, want the library's default")
70 }
71}
72
73func TestTheProjectRootIsTheNearestMoonModule(t *testing.T) {
74 // app.ProjectRoot walks up looking for the profile's RootMarkers. This is
75 // what decides the directory moon-lsp is started in, and starting it
76 // anywhere else is how a server answers nothing for a whole session.
77 root := t.TempDir()
78 nested := filepath.Join(root, "cmd", "main")
79 if err := os.MkdirAll(nested, 0o755); err != nil {
80 t.Fatal(err)
81 }
82 if err := os.WriteFile(filepath.Join(root, "moon.mod"), []byte(`name = "u/m"`), 0o644); err != nil {
83 t.Fatal(err)
84 }
85
86 file := filepath.Join(nested, "main.mbt")
87 if got := app.ProjectRoot(moonbitlang.Profile(), []string{file}); got != root {
88 t.Errorf("ProjectRoot(%q) = %q, want %q", file, got, root)
89 }
90}
91
92func TestTheLegacyJSONModuleFileIsAlsoARoot(t *testing.T) {
93 root := t.TempDir()
94 if err := os.WriteFile(filepath.Join(root, "moon.mod.json"), []byte(`{"name":"u/m"}`), 0o644); err != nil {
95 t.Fatal(err)
96 }
97
98 file := filepath.Join(root, "main.mbt")
99 if got := app.ProjectRoot(moonbitlang.Profile(), []string{file}); got != root {
100 t.Errorf("ProjectRoot(%q) = %q, want %q", file, got, root)
101 }
102}
103
104func TestTheNearestModuleWinsOverTheOneAboveIt(t *testing.T) {
105 // A workspace holds several modules. The server belongs to the one the
106 // file is in, not to the outermost directory that happens to have a
107 // manifest.
108 outer := t.TempDir()
109 inner := filepath.Join(outer, "member")
110 if err := os.MkdirAll(inner, 0o755); err != nil {
111 t.Fatal(err)
112 }
113 for _, dir := range []string{outer, inner} {
114 if err := os.WriteFile(filepath.Join(dir, "moon.mod"), []byte(`name = "u/m"`), 0o644); err != nil {
115 t.Fatal(err)
116 }
117 }
118
119 file := filepath.Join(inner, "lib.mbt")
120 if got := app.ProjectRoot(moonbitlang.Profile(), []string{file}); got != inner {
121 t.Errorf("ProjectRoot(%q) = %q, want the nearer %q", file, got, inner)
122 }
123}
124
125func TestLoadingSettingsFromADirectoryWithNoneGivesTheDefaults(t *testing.T) {
126 // A directory somebody merely started the editor in has said nothing, and
127 // the editor must not write to it. The starter file turns autosave on; the
128 // default leaves it off.
129 dir := t.TempDir()
130 t.Chdir(dir)
131
132 project, loaded := loadProjectSettings(moonbitlang.Profile())
133 if project == "" {
134 t.Error("loadProjectSettings returned no project directory")
135 }
136 if loaded.Autosave {
137 t.Error("autosave is on with no settings file, want it off")
138 }
139}
140
141func TestABrokenSettingsFileDoesNotStopTheEditorOpening(t *testing.T) {
142 // A broken settings file must not stop the editor opening, because the
143 // editor is how you would fix it.
144 dir := t.TempDir()
145 p := moonbitlang.Profile()
146 if err := os.MkdirAll(filepath.Join(dir, p.ProjectDir()), 0o755); err != nil {
147 t.Fatal(err)
148 }
149 if err := os.WriteFile(settings.Path(p, dir), []byte("this is not ["), 0o644); err != nil {
150 t.Fatal(err)
151 }
152 t.Chdir(dir)
153
154 if _, loaded := loadProjectSettings(p); loaded != settings.Default() {
155 t.Errorf("loadProjectSettings() = %+v with a broken file, want the defaults", loaded)
156 }
157}