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

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

toml_test.go · 178 lines · 6.3 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 4h ago1package syntax
2
3import (
4 "strings"
5 "testing"
6)
7
8// tomlLine returns the spans of one line of a TOML document, as "text:class"
9// strings, which is far easier to read in a failure than a slice of structs.
10func tomlLine(t *testing.T, src string, line int) []string {
11 t.Helper()
12
13 spans := Highlight(LanguageTOML, src)
14 if line >= len(spans) {
15 t.Fatalf("line %d is past the end of a %d-line document", line, len(spans))
16 }
17
18 text := []rune(strings.Split(src, "\n")[line])
19 out := make([]string, 0, len(spans[line]))
20 for _, s := range spans[line] {
21 out = append(out, string(text[s.Start:s.End])+":"+s.Class.String())
22 }
23 return out
24}
25
26// wantSpans compares the spans of a line against what they should be.
27func wantSpans(t *testing.T, src string, line int, want ...string) {
28 t.Helper()
29
30 got := tomlLine(t, src, line)
31 if len(got) != len(want) {
32 t.Fatalf("line %d of %q gave %v, want %v", line, src, got, want)
33 }
34 for i := range want {
35 if got[i] != want[i] {
36 t.Errorf("line %d span %d = %q, want %q (whole line: %v)", line, i, got[i], want[i], got)
37 }
38 }
39}
40
41func TestTOMLColoursAComment(t *testing.T) {
42 wantSpans(t, "# just a note", 0, "# just a note:comment")
43}
44
45func TestTOMLColoursATableHeader(t *testing.T) {
46 wantSpans(t, "[editor]", 0, "[:punctuation", "editor:type", "]:punctuation")
47}
48
49func TestTOMLColoursAnArrayOfTablesHeader(t *testing.T) {
50 wantSpans(t, "[[servers]]", 0,
51 "[:punctuation", "[:punctuation", "servers:type", "]:punctuation", "]:punctuation")
52}
53
54func TestTOMLTellsAKeyFromItsValue(t *testing.T) {
55 wantSpans(t, `theme = "turbo-dark"`, 0, "theme:identifier", "=:operator", `"turbo-dark":string`)
56}
57
58func TestTOMLColoursABooleanAsAConstant(t *testing.T) {
59 wantSpans(t, "autosave = true", 0, "autosave:identifier", "=:operator", "true:constant")
60 wantSpans(t, "autosave = false", 0, "autosave:identifier", "=:operator", "false:constant")
61}
62
63func TestTOMLColoursNumbers(t *testing.T) {
64 for _, value := range []string{"42", "-17", "+3", "3.14", "1_000_000", "0x1f", "1e6", "inf", "nan"} {
65 t.Run(value, func(t *testing.T) {
66 got := tomlLine(t, "n = "+value, 0)
67 last := got[len(got)-1]
68 if !strings.HasSuffix(last, ":number") {
69 t.Errorf("%q was coloured %q, want a number", value, last)
70 }
71 })
72 }
73}
74
75func TestTOMLColoursDatesAsNumbers(t *testing.T) {
76 // A date is not a string and not a name; the number class is where it
77 // reads correctly without inventing a class no theme sets.
78 wantSpans(t, "when = 1979-05-27T07:32:00Z", 0,
79 "when:identifier", "=:operator", "1979-05-27T07:32:00Z:number")
80}
81
82func TestTOMLColoursTheFourKindsOfString(t *testing.T) {
83 wantSpans(t, `a = "basic"`, 0, "a:identifier", "=:operator", `"basic":string`)
84 wantSpans(t, `a = 'literal'`, 0, "a:identifier", "=:operator", `'literal':string`)
85 wantSpans(t, `a = """one line"""`, 0, "a:identifier", "=:operator", `"""one line""":string`)
86 wantSpans(t, `a = '''one line'''`, 0, "a:identifier", "=:operator", `'''one line''':string`)
87}
88
89func TestTOMLColoursAMultiLineStringOnEveryLineItCovers(t *testing.T) {
90 src := "text = \"\"\"\nfirst\nsecond\n\"\"\"\nafter = 1\n"
91
92 wantSpans(t, src, 0, "text:identifier", "=:operator", `""":string`)
93 wantSpans(t, src, 1, "first:string")
94 wantSpans(t, src, 2, "second:string")
95 wantSpans(t, src, 3, `""":string`)
96 // The line after the string must be back to normal scanning.
97 wantSpans(t, src, 4, "after:identifier", "=:operator", "1:number")
98}
99
100func TestAHashInsideAStringIsNotAComment(t *testing.T) {
101 wantSpans(t, `colour = "#ff8700"`, 0, "colour:identifier", "=:operator", `"#ff8700":string`)
102}
103
104func TestAnEqualsInsideAStringIsNotAnOperator(t *testing.T) {
105 wantSpans(t, `a = "x = y"`, 0, "a:identifier", "=:operator", `"x = y":string`)
106}
107
108func TestAnEscapedQuoteDoesNotEndABasicString(t *testing.T) {
109 wantSpans(t, `a = "he said \"no\""`, 0, "a:identifier", "=:operator", `"he said \"no\"":string`)
110}
111
112func TestABackslashDoesNotEscapeInALiteralString(t *testing.T) {
113 // The whole point of a literal string: '\' is a backslash, and the quote
114 // after it still closes the string.
115 wantSpans(t, `path = 'C:\temp\'`, 0, "path:identifier", "=:operator", `'C:\temp\':string`)
116}
117
118func TestAnUnterminatedStringIsColouredToTheEndOfTheLine(t *testing.T) {
119 // A string being typed is unterminated most of the time it is being typed;
120 // giving up on it would make the colours flicker off at every keystroke.
121 wantSpans(t, `a = "half written`, 0, "a:identifier", "=:operator", `"half written:string`)
122}
123
124func TestTOMLColoursEveryPartOfADottedKey(t *testing.T) {
125 wantSpans(t, "a.b.c = 1", 0,
126 "a:identifier", ".:punctuation", "b:identifier", ".:punctuation", "c:identifier",
127 "=:operator", "1:number")
128}
129
130func TestTOMLColoursAnArrayValue(t *testing.T) {
131 wantSpans(t, "list = [1, 2]", 0,
132 "list:identifier", "=:operator", "[:punctuation",
133 "1:number", ",:punctuation", "2:number", "]:punctuation")
134}
135
136func TestTOMLColoursAnInlineTable(t *testing.T) {
137 wantSpans(t, `fg = { c = "red" }`, 0,
138 "fg:identifier", "=:operator", "{:punctuation",
139 "c:identifier", "=:operator", `"red":string`, "}:punctuation")
140}
141
142func TestTOMLColoursAQuotedKey(t *testing.T) {
143 // Theme files are full of these: "syntax.keyword" = { … }
144 wantSpans(t, `"syntax.keyword" = "x"`, 0,
145 `"syntax.keyword":string`, "=:operator", `"x":string`)
146}
147
148func TestTOMLGivesOneEntryPerLine(t *testing.T) {
149 src := "[a]\nb = 1\n\nc = 2\n"
150
151 if got := len(Highlight(LanguageTOML, src)); got != 5 {
152 t.Errorf("Highlight() returned %d lines for a 5-line document", got)
153 }
154}
155
156func TestTOMLSpansStayInsideTheirLine(t *testing.T) {
157 src := "# a\n[t]\nk = \"\"\"\nspill\n\"\"\"\n"
158 lines := strings.Split(src, "\n")
159
160 for i, spans := range Highlight(LanguageTOML, src) {
161 width := len([]rune(lines[i]))
162 for _, s := range spans {
163 if s.Start < 0 || s.End > width || s.End <= s.Start {
164 t.Errorf("line %d (%d runes) has span %d-%d", i, width, s.Start, s.End)
165 }
166 }
167 }
168}
169
170func TestTOMLColoursTheSettingsFileItself(t *testing.T) {
171 // The file this whole feature exists to let people edit.
172 src := "[editor]\n# which theme\ntheme = \"turbo-dark\" # ours\nautosave = false\n"
173
174 wantSpans(t, src, 0, "[:punctuation", "editor:type", "]:punctuation")
175 wantSpans(t, src, 1, "# which theme:comment")
176 wantSpans(t, src, 2, "theme:identifier", "=:operator", `"turbo-dark":string`, "# ours:comment")
177 wantSpans(t, src, 3, "autosave:identifier", "=:operator", "false:constant")
178}