diff options
Diffstat (limited to 'gopls/internal/lsp/template/parse_test.go')
-rw-r--r-- | gopls/internal/lsp/template/parse_test.go | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/gopls/internal/lsp/template/parse_test.go b/gopls/internal/lsp/template/parse_test.go new file mode 100644 index 000000000..345f52347 --- /dev/null +++ b/gopls/internal/lsp/template/parse_test.go @@ -0,0 +1,238 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package template + +import ( + "strings" + "testing" +) + +type datum struct { + buf string + cnt int + syms []string // the symbols in the parse of buf +} + +var tmpl = []datum{{` +{{if (foo .X.Y)}}{{$A := "hi"}}{{.Z $A}}{{else}} +{{$A.X 12}} +{{foo (.X.Y) 23 ($A.Zü)}} +{{end}}`, 1, []string{"{7,3,foo,Function,false}", "{12,1,X,Method,false}", + "{14,1,Y,Method,false}", "{21,2,$A,Variable,true}", "{26,2,,String,false}", + "{35,1,Z,Method,false}", "{38,2,$A,Variable,false}", + "{53,2,$A,Variable,false}", "{56,1,X,Method,false}", "{57,2,,Number,false}", + "{64,3,foo,Function,false}", "{70,1,X,Method,false}", + "{72,1,Y,Method,false}", "{75,2,,Number,false}", "{80,2,$A,Variable,false}", + "{83,2,Zü,Method,false}", "{94,3,,Constant,false}"}}, + + {`{{define "zzz"}}{{.}}{{end}} +{{template "zzz"}}`, 2, []string{"{10,3,zzz,Namespace,true}", "{18,1,dot,Variable,false}", + "{41,3,zzz,Package,false}"}}, + + {`{{block "aaa" foo}}b{{end}}`, 2, []string{"{9,3,aaa,Namespace,true}", + "{9,3,aaa,Package,false}", "{14,3,foo,Function,false}", "{19,1,,Constant,false}"}}, + {"", 0, nil}, +} + +func TestSymbols(t *testing.T) { + for i, x := range tmpl { + got := parseBuffer([]byte(x.buf)) + if got.ParseErr != nil { + t.Errorf("error:%v", got.ParseErr) + continue + } + if len(got.named) != x.cnt { + t.Errorf("%d: got %d, expected %d", i, len(got.named), x.cnt) + } + for n, s := range got.symbols { + if s.String() != x.syms[n] { + t.Errorf("%d: got %s, expected %s", i, s.String(), x.syms[n]) + } + } + } +} + +func TestWordAt(t *testing.T) { + want := []string{"", "", "$A", "$A", "", "", "", "", "", "", + "", "", "", "if", "if", "", "$A", "$A", "", "", + "B", "", "", "end", "end", "end", "", "", ""} + p := parseBuffer([]byte("{{$A := .}}{{if $A}}B{{end}}")) + for i := 0; i < len(p.buf); i++ { + got := findWordAt(p, i) + if got != want[i] { + t.Errorf("for %d, got %q, wanted %q", i, got, want[i]) + } + } +} + +func TestNLS(t *testing.T) { + buf := `{{if (foÜx .X.Y)}}{{$A := "hi"}}{{.Z $A}}{{else}} + {{$A.X 12}} + {{foo (.X.Y) 23 ($A.Z)}} + {{end}} + ` + p := parseBuffer([]byte(buf)) + if p.ParseErr != nil { + t.Fatal(p.ParseErr) + } + // line 0 doesn't have a \n in front of it + for i := 1; i < len(p.nls)-1; i++ { + if buf[p.nls[i]] != '\n' { + t.Errorf("line %d got %c", i, buf[p.nls[i]]) + } + } + // fake line at end of file + if p.nls[len(p.nls)-1] != len(buf) { + t.Errorf("got %d expected %d", p.nls[len(p.nls)-1], len(buf)) + } +} + +func TestLineCol(t *testing.T) { + buf := `{{if (foÜx .X.Y)}}{{$A := "hi"}}{{.Z $A}}{{else}} + {{$A.X 12}} + {{foo (.X.Y) 23 ($A.Z)}} + {{end}}` + if false { + t.Error(buf) + } + for n, cx := range tmpl { + buf := cx.buf + p := parseBuffer([]byte(buf)) + if p.ParseErr != nil { + t.Fatal(p.ParseErr) + } + type loc struct { + offset int + l, c uint32 + } + saved := []loc{} + // forwards + var lastl, lastc uint32 + for offset := range buf { + l, c := p.LineCol(offset) + saved = append(saved, loc{offset, l, c}) + if l > lastl { + lastl = l + if c != 0 { + t.Errorf("line %d, got %d instead of 0", l, c) + } + } + if c > lastc { + lastc = c + } + } + lines := strings.Split(buf, "\n") + mxlen := -1 + for _, l := range lines { + if len(l) > mxlen { + mxlen = len(l) + } + } + if int(lastl) != len(lines)-1 && int(lastc) != mxlen { + // lastl is 0 if there is only 1 line(?) + t.Errorf("expected %d, %d, got %d, %d for case %d", len(lines)-1, mxlen, lastl, lastc, n) + } + // backwards + for j := len(saved) - 1; j >= 0; j-- { + s := saved[j] + xl, xc := p.LineCol(s.offset) + if xl != s.l || xc != s.c { + t.Errorf("at offset %d(%d), got (%d,%d), expected (%d,%d)", s.offset, j, xl, xc, s.l, s.c) + } + } + } +} + +func TestLineColNL(t *testing.T) { + buf := "\n\n\n\n\n" + p := parseBuffer([]byte(buf)) + if p.ParseErr != nil { + t.Fatal(p.ParseErr) + } + for i := 0; i < len(buf); i++ { + l, c := p.LineCol(i) + if c != 0 || int(l) != i+1 { + t.Errorf("got (%d,%d), expected (%d,0)", l, c, i) + } + } +} + +func TestPos(t *testing.T) { + buf := ` + {{if (foÜx .X.Y)}}{{$A := "hi"}}{{.Z $A}}{{else}} + {{$A.X 12}} + {{foo (.X.Y) 23 ($A.Z)}} + {{end}}` + p := parseBuffer([]byte(buf)) + if p.ParseErr != nil { + t.Fatal(p.ParseErr) + } + for pos, r := range buf { + if r == '\n' { + continue + } + x := p.Position(pos) + n := p.FromPosition(x) + if n != pos { + // once it's wrong, it will be wrong forever + t.Fatalf("at pos %d (rune %c) got %d {%#v]", pos, r, n, x) + } + + } +} +func TestLen(t *testing.T) { + data := []struct { + cnt int + v string + }{{1, "a"}, {1, "膈"}, {4, "😆🥸"}, {7, "3😀4567"}} + p := &Parsed{nonASCII: true} + for _, d := range data { + got := p.utf16len([]byte(d.v)) + if got != d.cnt { + t.Errorf("%v, got %d wanted %d", d, got, d.cnt) + } + } +} + +func TestUtf16(t *testing.T) { + buf := ` + {{if (foÜx .X.Y)}}😀{{$A := "hi"}}{{.Z $A}}{{else}} + {{$A.X 12}} + {{foo (.X.Y) 23 ($A.Z)}} + {{end}}` + p := parseBuffer([]byte(buf)) + if p.nonASCII == false { + t.Error("expected nonASCII to be true") + } +} + +type ttest struct { + tmpl string + tokCnt int + elidedCnt int8 +} + +func TestQuotes(t *testing.T) { + tsts := []ttest{ + {"{{- /*comment*/ -}}", 1, 0}, + {"{{/*`\ncomment\n`*/}}", 1, 0}, + //{"{{foo\nbar}}\n", 1, 0}, // this action spanning lines parses in 1.16 + {"{{\"{{foo}}{{\"}}", 1, 0}, + {"{{\n{{- when}}", 1, 1}, // corrected + {"{{{{if .}}xx{{\n{{end}}", 2, 2}, // corrected + } + for _, s := range tsts { + p := parseBuffer([]byte(s.tmpl)) + if len(p.tokens) != s.tokCnt { + t.Errorf("%q: got %d tokens, expected %d", s, len(p.tokens), s.tokCnt) + } + if p.ParseErr != nil { + t.Errorf("%q: %v", string(p.buf), p.ParseErr) + } + if len(p.elided) != int(s.elidedCnt) { + t.Errorf("%q: elided %d, expected %d", s, len(p.elided), s.elidedCnt) + } + } +} |