diff options
Diffstat (limited to 'gui/internal/model/highlight_test.go')
| -rw-r--r-- | gui/internal/model/highlight_test.go | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/gui/internal/model/highlight_test.go b/gui/internal/model/highlight_test.go new file mode 100644 index 0000000..f5c1e28 --- /dev/null +++ b/gui/internal/model/highlight_test.go @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package model + +import "testing" + +// textOf is the stretch a span covers, by character offset. +func textOf(text string, s Span) string { + return string([]rune(text)[s.From:s.To]) +} + +// find is the first span of a kind whose text matches, for the assertions +// below. +func find(t *testing.T, text string, kind SpanKind, want string) { + t.Helper() + for _, s := range Spans(text) { + if s.Kind == kind && textOf(text, s) == want { + return + } + } + t.Errorf("no %v span %q in %q", kind, want, text) +} + +// TestSpansPaintsTheParts: heads, actions, strings and comments each come +// back as their own kind. +func TestSpansPaintsTheParts(t *testing.T) { + text := "(rule \"invoices\" ; the ones from suppliers\n (when (type pdf))\n (move \"Docs\"))\n" + find(t, text, SpanHead, "rule") + find(t, text, SpanHead, "when") + find(t, text, SpanHead, "type") + find(t, text, SpanAction, "move") + find(t, text, SpanString, `"invoices"`) + find(t, text, SpanString, `"Docs"`) + find(t, text, SpanComment, "; the ones from suppliers") +} + +// TestSpansKeepsQuotingStraight: a semicolon inside a string is not a +// comment, a quote inside a comment does not start a string, and an escaped +// quote does not end one. +func TestSpansKeepsQuotingStraight(t *testing.T) { + text := `(rule "a;b" (when (name "say \"hi\"")) (move "Out"))` + "\n;; \"not a string\"\n" + find(t, text, SpanString, `"a;b"`) + find(t, text, SpanString, `"say \"hi\""`) + find(t, text, SpanComment, `;; "not a string"`) + for _, s := range Spans(text) { + if s.Kind == SpanComment && textOf(text, s) == ";b\" (when (name \"say \\\"hi\\\"\")) (move \"Out\"))" { + t.Error("a semicolon inside a string started a comment") + } + } +} + +// TestSpansOnlyHeadsAreHeads: an argument that happens to be a symbol is +// not painted as a head. +func TestSpansOnlyHeadsAreHeads(t *testing.T) { + text := "(when (type pdf doc))\n" + for _, s := range Spans(text) { + if s.Kind == SpanHead && (textOf(text, s) == "pdf" || textOf(text, s) == "doc") { + t.Errorf("argument %q painted as a head", textOf(text, s)) + } + } + find(t, text, SpanHead, "type") +} + +// TestSpansCountsCharactersNotBytes: offsets are what a text buffer counts, +// so a file with Polish letters in it still colours the right stretch. +func TestSpansCountsCharactersNotBytes(t *testing.T) { + text := "(rule \"spółka\" (move \"Księgowość\"))\n" + find(t, text, SpanString, `"spółka"`) + find(t, text, SpanString, `"Księgowość"`) + find(t, text, SpanAction, "move") +} + +// TestSpansSurvivesUnclosedForms: text being typed is not yet valid, and +// the colouring must not run off the end of it. +func TestSpansSurvivesUnclosedForms(t *testing.T) { + for _, text := range []string{`(rule "half`, "(when (name ", ";; just a comment", `"`} { + for _, s := range Spans(text) { + if s.From < 0 || s.To > len([]rune(text)) || s.From > s.To { + t.Errorf("%q: span %+v is outside the text", text, s) + } + } + } +} |
