turbo-editors/turbo-golopublic Fork 0
49c12f54ef399972152fccd592ae27e94977f9b5
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-golo.git
git clone ssh://git@rickub.com/turbo-editors/turbo-golo.git

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

main_test.go · 200 lines · 6.5 KBGo Blame HistoryRaw
📦 Turbo Golo d710c1b k33g yesterday1package main
2
3import (
📦 Turbo Golo b2b07ec k33g 10h ago4 "errors"
📦 Turbo Golo d710c1b k33g yesterday5 "flag"
6 "os"
7 "path/filepath"
8 "slices"
📦 Turbo Golo b2b07ec k33g 10h ago9 "strings"
📦 Turbo Golo d710c1b k33g yesterday10 "testing"
11
12 "rickub.com/turbo-editors/turbo-core/app"
📦 Turbo Golo b2b07ec k33g 10h ago13 "rickub.com/turbo-editors/turbo-core/configrepo"
📦 Turbo Golo d710c1b k33g yesterday14 "rickub.com/turbo-editors/turbo-core/settings"
15
16 "rickub.com/turbo-editors/turbo-golo/internal/gololang"
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-golo"}, 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.golo", "lib/x.golo")
34
35 if !opts.noLSP {
36 t.Error("-no-lsp was not read")
37 }
38 if want := []string{"main.golo", "lib/x.golo"}; !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 TestTheProjectRootIsTheDirectoryOfTheFile(t *testing.T) {
77 // app.ProjectRoot walks up looking for the profile's RootMarkers, and Golo
78 // has none: a script is a file, and there is no manifest above it to find.
79 // So the server is started in the file's own directory, however deep.
80 root := t.TempDir()
81 nested := filepath.Join(root, "scripts", "tools")
82 if err := os.MkdirAll(nested, 0o755); err != nil {
83 t.Fatal(err)
84 }
85
86 file := filepath.Join(nested, "main.golo")
87 if got := app.ProjectRoot(gololang.Profile(), []string{file}); got != nested {
88 t.Errorf("ProjectRoot(%q) = %q, want the file's own directory %q", file, got, nested)
89 }
90}
91
92func TestNothingAboveTheFileChangesTheRoot(t *testing.T) {
93 // A .git directory and a main.golo higher up are the two things somebody
94 // might expect to count as a project. Neither is a marker here, so neither
95 // moves the root: the rule is "no walk", and this pins it.
96 root := t.TempDir()
97 nested := filepath.Join(root, "lib")
98 if err := os.MkdirAll(filepath.Join(root, ".git"), 0o755); err != nil {
99 t.Fatal(err)
100 }
101 if err := os.MkdirAll(nested, 0o755); err != nil {
102 t.Fatal(err)
103 }
104 if err := os.WriteFile(filepath.Join(root, "main.golo"), []byte("module m\n"), 0o644); err != nil {
105 t.Fatal(err)
106 }
107
108 file := filepath.Join(nested, "helpers.golo")
109 if got := app.ProjectRoot(gololang.Profile(), []string{file}); got != nested {
110 t.Errorf("ProjectRoot(%q) = %q, want %q; something above the file was taken for a marker", file, got, nested)
111 }
112}
113
114func TestWithNoFileTheRootIsTheWorkingDirectory(t *testing.T) {
115 // `turbo-golo` with no file opens an empty window, and the server has to
116 // be started somewhere. Where the editor was started is the only answer.
117 dir := t.TempDir()
118 t.Chdir(dir)
119
120 got := app.ProjectRoot(gololang.Profile(), nil)
121 want, err := os.Getwd()
122 if err != nil {
123 t.Fatal(err)
124 }
125 if got != want {
126 t.Errorf("ProjectRoot() with no file = %q, want the working directory %q", got, want)
127 }
128}
129
130func TestLoadingSettingsFromADirectoryWithNoneGivesTheDefaults(t *testing.T) {
131 // A directory somebody merely started the editor in has said nothing, and
132 // the editor must not write to it. The starter file turns autosave on; the
133 // default leaves it off.
134 dir := t.TempDir()
135 t.Chdir(dir)
136
137 project, loaded := loadProjectSettings(gololang.Profile())
138 if project == "" {
139 t.Error("loadProjectSettings returned no project directory")
140 }
141 if loaded.Autosave {
142 t.Error("autosave is on with no settings file, want it off")
143 }
144}
145
146func TestABrokenSettingsFileDoesNotStopTheEditorOpening(t *testing.T) {
147 // A broken settings file must not stop the editor opening, because the
148 // editor is how you would fix it.
149 dir := t.TempDir()
150 p := gololang.Profile()
151 if err := os.MkdirAll(filepath.Join(dir, p.ProjectDir()), 0o755); err != nil {
152 t.Fatal(err)
153 }
154 if err := os.WriteFile(settings.Path(p, dir), []byte("this is not ["), 0o644); err != nil {
155 t.Fatal(err)
156 }
157 t.Chdir(dir)
158
159 if _, loaded := loadProjectSettings(p); loaded != settings.Default() {
160 t.Errorf("loadProjectSettings() = %+v with a broken file, want the defaults", loaded)
161 }
162}
📦 Turbo Golo b2b07ec k33g 10h ago163
164func TestDescribeLoadNamesTheSourceAndEveryFile(t *testing.T) {
165 got := describeLoad(configrepo.Result{
166 Remote: "https://git.rickub.com/turbo-editors/configs.git",
167 Ref: "main",
168 Dir: "/work/.turbo-golo",
169 Files: []string{"settings.toml", "tools.toml"},
170 })
171
172 want := "Copied /work/.turbo-golo from https://git.rickub.com/turbo-editors/configs.git (main):\n settings.toml\n tools.toml\n"
173 if got != want {
174 t.Errorf("describeLoad() =\n%q\nwant\n%q", got, want)
175 }
176}
177
178func TestDescribeLoadOmitsTheRefWhenTheDefaultBranchWasUsed(t *testing.T) {
179 got := describeLoad(configrepo.Result{Remote: "r", Dir: "d"})
180
181 if strings.Contains(got, "(") {
182 t.Errorf("describeLoad() = %q, want no parenthesised ref", got)
183 }
184}
185
186func TestLoadConfigLeavesAProjectThatHasAConfigurationAlone(t *testing.T) {
187 // Checked before anything is fetched, so this needs neither git nor a
188 // network: the project's own .turbo-golo is a decision, not a default.
189 project := t.TempDir()
190 if err := os.MkdirAll(filepath.Join(project, ".turbo-golo"), 0o755); err != nil {
191 t.Fatal(err)
192 }
193 t.Chdir(project)
194
195 err := loadConfig(gololang.Profile(), "https://rickub.com/turbo-editors/configs/tree/main/golang-init")
196
197 if !errors.Is(err, configrepo.ErrExists) {
198 t.Errorf("loadConfig() error = %v, want ErrExists", err)
199 }
200}