turbo-editors/turbo-moonbitpublic Fork 0
v1.0.3
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 · 198 lines · 6.4 KBGo Blame HistoryRaw
📦 Turbo MoonBit cc1f595 k33g yesterday1package main
2
3import (
📦 Turbo MoonBit ded61de k33g 6h ago4 "errors"
📦 Turbo MoonBit cc1f595 k33g yesterday5 "flag"
6 "os"
7 "path/filepath"
8 "slices"
📦 Turbo MoonBit ded61de k33g 6h ago9 "strings"
📦 Turbo MoonBit cc1f595 k33g yesterday10 "testing"
11
12 "rickub.com/turbo-editors/turbo-core/app"
📦 Turbo MoonBit ded61de k33g 6h ago13 "rickub.com/turbo-editors/turbo-core/configrepo"
📦 Turbo MoonBit cc1f595 k33g yesterday14 "rickub.com/turbo-editors/turbo-core/settings"
15
16 "rickub.com/turbo-editors/turbo-moonbit/internal/moonbitlang"
17)
18
19// withArgs runs the command line parser against a fixed argument list, and
20// restores the real one afterwards so tests do not affect each other.
21func withArgs(t *testing.T, args ...string) options {
22 t.Helper()
23
24 realArgs, realFlags := os.Args, flag.CommandLine
25 t.Cleanup(func() { os.Args, flag.CommandLine = realArgs, realFlags })
26
27 os.Args = append([]string{"turbo-moonbit"}, args...)
28 flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
29 return parseFlags()
30}
31
32func TestFilesAreWhatIsLeftAfterTheFlags(t *testing.T) {
33 opts := withArgs(t, "-no-lsp", "main.mbt", "lib/x.mbt")
34
35 if !opts.noLSP {
36 t.Error("-no-lsp was not read")
37 }
38 if want := []string{"main.mbt", "lib/x.mbt"}; !slices.Equal(opts.files, want) {
39 t.Errorf("files = %v, want %v", opts.files, want)
40 }
41}
42
43func TestTheThemeFlagDefaultsToEmptyRatherThanToAName(t *testing.T) {
44 // Empty is what lets "was -theme given?" still be answered afterwards, and
45 // that is what lets the project's settings fill it in without overriding an
46 // explicit choice.
47 if opts := withArgs(t); opts.theme != "" {
48 t.Errorf("theme = %q with no flag, want the empty string", opts.theme)
49 }
50}
51
52func TestTheThemeFlagBeatsTheProjectSettings(t *testing.T) {
53 project := settings.Default()
54 project.Theme = "cobalt"
55
56 if got := themeName(options{theme: "monochrome"}, project); got != "monochrome" {
57 t.Errorf("themeName() = %q, want the flag's %q", got, "monochrome")
58 }
59}
60
61func TestTheProjectSettingsBeatTheBuiltInDefault(t *testing.T) {
62 project := settings.Default()
63 project.Theme = "cobalt"
64
65 if got := themeName(options{}, project); got != "cobalt" {
66 t.Errorf("themeName() = %q, want the project's %q", got, "cobalt")
67 }
68}
69
70func TestTheBuiltInDefaultIsUsedWhenNobodySaysOtherwise(t *testing.T) {
71 if got := themeName(options{}, settings.Default()); got == "" {
72 t.Error("themeName() = \"\" with nothing set, want the library's default")
73 }
74}
75
76func TestTheProjectRootIsTheNearestMoonModule(t *testing.T) {
77 // app.ProjectRoot walks up looking for the profile's RootMarkers. This is
78 // what decides the directory moon-lsp is started in, and starting it
79 // anywhere else is how a server answers nothing for a whole session.
80 root := t.TempDir()
81 nested := filepath.Join(root, "cmd", "main")
82 if err := os.MkdirAll(nested, 0o755); err != nil {
83 t.Fatal(err)
84 }
85 if err := os.WriteFile(filepath.Join(root, "moon.mod"), []byte(`name = "u/m"`), 0o644); err != nil {
86 t.Fatal(err)
87 }
88
89 file := filepath.Join(nested, "main.mbt")
90 if got := app.ProjectRoot(moonbitlang.Profile(), []string{file}); got != root {
91 t.Errorf("ProjectRoot(%q) = %q, want %q", file, got, root)
92 }
93}
94
95func TestTheLegacyJSONModuleFileIsAlsoARoot(t *testing.T) {
96 root := t.TempDir()
97 if err := os.WriteFile(filepath.Join(root, "moon.mod.json"), []byte(`{"name":"u/m"}`), 0o644); err != nil {
98 t.Fatal(err)
99 }
100
101 file := filepath.Join(root, "main.mbt")
102 if got := app.ProjectRoot(moonbitlang.Profile(), []string{file}); got != root {
103 t.Errorf("ProjectRoot(%q) = %q, want %q", file, got, root)
104 }
105}
106
107func TestTheNearestModuleWinsOverTheOneAboveIt(t *testing.T) {
108 // A workspace holds several modules. The server belongs to the one the
109 // file is in, not to the outermost directory that happens to have a
110 // manifest.
111 outer := t.TempDir()
112 inner := filepath.Join(outer, "member")
113 if err := os.MkdirAll(inner, 0o755); err != nil {
114 t.Fatal(err)
115 }
116 for _, dir := range []string{outer, inner} {
117 if err := os.WriteFile(filepath.Join(dir, "moon.mod"), []byte(`name = "u/m"`), 0o644); err != nil {
118 t.Fatal(err)
119 }
120 }
121
122 file := filepath.Join(inner, "lib.mbt")
123 if got := app.ProjectRoot(moonbitlang.Profile(), []string{file}); got != inner {
124 t.Errorf("ProjectRoot(%q) = %q, want the nearer %q", file, got, inner)
125 }
126}
127
128func TestLoadingSettingsFromADirectoryWithNoneGivesTheDefaults(t *testing.T) {
129 // A directory somebody merely started the editor in has said nothing, and
130 // the editor must not write to it. The starter file turns autosave on; the
131 // default leaves it off.
132 dir := t.TempDir()
133 t.Chdir(dir)
134
135 project, loaded := loadProjectSettings(moonbitlang.Profile())
136 if project == "" {
137 t.Error("loadProjectSettings returned no project directory")
138 }
139 if loaded.Autosave {
140 t.Error("autosave is on with no settings file, want it off")
141 }
142}
143
144func TestABrokenSettingsFileDoesNotStopTheEditorOpening(t *testing.T) {
145 // A broken settings file must not stop the editor opening, because the
146 // editor is how you would fix it.
147 dir := t.TempDir()
148 p := moonbitlang.Profile()
149 if err := os.MkdirAll(filepath.Join(dir, p.ProjectDir()), 0o755); err != nil {
150 t.Fatal(err)
151 }
152 if err := os.WriteFile(settings.Path(p, dir), []byte("this is not ["), 0o644); err != nil {
153 t.Fatal(err)
154 }
155 t.Chdir(dir)
156
157 if _, loaded := loadProjectSettings(p); loaded != settings.Default() {
158 t.Errorf("loadProjectSettings() = %+v with a broken file, want the defaults", loaded)
159 }
160}
📦 Turbo MoonBit ded61de k33g 6h ago161
162func TestDescribeLoadNamesTheSourceAndEveryFile(t *testing.T) {
163 got := describeLoad(configrepo.Result{
164 Remote: "https://git.rickub.com/turbo-editors/configs.git",
165 Ref: "main",
166 Dir: "/work/.turbo-moonbit",
167 Files: []string{"settings.toml", "tools.toml"},
168 })
169
170 want := "Copied /work/.turbo-moonbit from https://git.rickub.com/turbo-editors/configs.git (main):\n settings.toml\n tools.toml\n"
171 if got != want {
172 t.Errorf("describeLoad() =\n%q\nwant\n%q", got, want)
173 }
174}
175
176func TestDescribeLoadOmitsTheRefWhenTheDefaultBranchWasUsed(t *testing.T) {
177 got := describeLoad(configrepo.Result{Remote: "r", Dir: "d"})
178
179 if strings.Contains(got, "(") {
180 t.Errorf("describeLoad() = %q, want no parenthesised ref", got)
181 }
182}
183
184func TestLoadConfigLeavesAProjectThatHasAConfigurationAlone(t *testing.T) {
185 // Checked before anything is fetched, so this needs neither git nor a
186 // network: the project's own .turbo-moonbit is a decision, not a default.
187 project := t.TempDir()
188 if err := os.MkdirAll(filepath.Join(project, ".turbo-moonbit"), 0o755); err != nil {
189 t.Fatal(err)
190 }
191 t.Chdir(project)
192
193 err := loadConfig(moonbitlang.Profile(), "https://rickub.com/turbo-editors/configs/tree/main/golang-init")
194
195 if !errors.Is(err, configrepo.ErrExists) {
196 t.Errorf("loadConfig() error = %v, want ErrExists", err)
197 }
198}