1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
11 "golang.org/x/tools/internal/span"
14 // The funny character below is 4 bytes long in UTF-8; two UTF-16 code points
15 var funnyString = []byte("š23\nš45")
17 var toUTF16Tests = []struct {
20 line int // 1-indexed count
21 col int // 1-indexed byte position in line
22 offset int // 0-indexed byte offset into input
23 resUTF16col int // 1-indexed UTF-16 col number
24 pre string // everything before the cursor on the line
25 post string // everything from the cursor onwards
26 err string // expected error string in call to ToUTF16Column
30 scenario: "cursor missing content",
32 err: "ToUTF16Column: point is missing position",
35 scenario: "cursor missing position",
39 err: "ToUTF16Column: point is missing position",
42 scenario: "cursor missing offset",
47 err: "ToUTF16Column: point is missing offset",
50 scenario: "zero length input; cursor at first col, first line",
58 scenario: "cursor before funny character; first line",
68 scenario: "cursor after funny character; first line",
71 col: 5, // 4 + 1 (1-indexed)
73 resUTF16col: 3, // 2 + 1 (1-indexed)
78 scenario: "cursor after last character on first line",
81 col: 7, // 4 + 1 + 1 + 1 (1-indexed)
82 offset: 6, // 4 + 1 + 1
83 resUTF16col: 5, // 2 + 1 + 1 + 1 (1-indexed)
88 scenario: "cursor before funny character; second line",
92 offset: 7, // length of first line
98 scenario: "cursor after funny character; second line",
101 col: 5, // 4 + 1 (1-indexed)
102 offset: 11, // 7 (length of first line) + 4
103 resUTF16col: 3, // 2 + 1 (1-indexed)
108 scenario: "cursor after last character on second line",
111 col: 7, // 4 + 1 + 1 + 1 (1-indexed)
112 offset: 13, // 7 (length of first line) + 4 + 1 + 1
113 resUTF16col: 5, // 2 + 1 + 1 + 1 (1-indexed)
118 scenario: "cursor beyond end of file",
121 col: 8, // 4 + 1 + 1 + 1 + 1 (1-indexed)
122 offset: 14, // 4 + 1 + 1 + 1
123 err: "ToUTF16Column: offsets 7-14 outside file contents (13)",
127 var fromUTF16Tests = []struct {
130 line int // 1-indexed line number (isn't actually used)
131 offset int // 0-indexed byte offset to beginning of line
132 utf16col int // 1-indexed UTF-16 col number
133 resCol int // 1-indexed byte position in line
134 resOffset int // 0-indexed byte offset into input
135 pre string // everything before the cursor on the line
136 post string // everything from the cursor onwards
137 err string // expected error string in call to ToUTF16Column
140 scenario: "zero length input; cursor at first col, first line",
151 scenario: "missing offset",
155 err: "FromUTF16Column: point is missing offset",
158 scenario: "cursor before funny character",
168 scenario: "cursor after funny character",
178 scenario: "cursor after last character on line",
188 scenario: "cursor beyond last character on line",
199 scenario: "cursor before funny character; second line",
202 offset: 7, // length of first line
210 scenario: "cursor after funny character; second line",
213 offset: 7, // length of first line
214 utf16col: 3, // 2 + 1 (1-indexed)
215 resCol: 5, // 4 + 1 (1-indexed)
216 resOffset: 11, // 7 (length of first line) + 4
221 scenario: "cursor after last character on second line",
224 offset: 7, // length of first line
225 utf16col: 5, // 2 + 1 + 1 + 1 (1-indexed)
226 resCol: 7, // 4 + 1 + 1 + 1 (1-indexed)
227 resOffset: 13, // 7 (length of first line) + 4 + 1 + 1
232 scenario: "cursor beyond end of file",
236 utf16col: 6, // 2 + 1 + 1 + 1 + 1(1-indexed)
237 resCol: 8, // 4 + 1 + 1 + 1 + 1 (1-indexed)
238 resOffset: 14, // 7 (length of first line) + 4 + 1 + 1 + 1
239 err: "FromUTF16Column: chr goes beyond the content",
242 scenario: "offset beyond end of file",
247 err: "FromUTF16Column: offset (14) greater than length of content (13)",
251 func TestToUTF16(t *testing.T) {
252 for _, e := range toUTF16Tests {
253 t.Run(e.scenario, func(t *testing.T) {
254 if e.issue != nil && !*e.issue {
255 t.Skip("expected to fail")
257 p := span.NewPoint(e.line, e.col, e.offset)
258 got, err := span.ToUTF16Column(p, e.input)
260 if err.Error() != e.err {
261 t.Fatalf("expected error %v; got %v", e.err, err)
266 t.Fatalf("unexpected success; wanted %v", e.err)
268 if got != e.resUTF16col {
269 t.Fatalf("expected result %v; got %v", e.resUTF16col, got)
271 pre, post := getPrePost(e.input, p.Offset())
272 if string(pre) != e.pre {
273 t.Fatalf("expected #%d pre %q; got %q", p.Offset(), e.pre, pre)
275 if string(post) != e.post {
276 t.Fatalf("expected #%d, post %q; got %q", p.Offset(), e.post, post)
282 func TestFromUTF16(t *testing.T) {
283 for _, e := range fromUTF16Tests {
284 t.Run(e.scenario, func(t *testing.T) {
285 p := span.NewPoint(e.line, 1, e.offset)
286 p, err := span.FromUTF16Column(p, e.utf16col, []byte(e.input))
288 if err.Error() != e.err {
289 t.Fatalf("expected error %v; got %v", e.err, err)
294 t.Fatalf("unexpected success; wanted %v", e.err)
296 if p.Column() != e.resCol {
297 t.Fatalf("expected resulting col %v; got %v", e.resCol, p.Column())
299 if p.Offset() != e.resOffset {
300 t.Fatalf("expected resulting offset %v; got %v", e.resOffset, p.Offset())
302 pre, post := getPrePost(e.input, p.Offset())
303 if string(pre) != e.pre {
304 t.Fatalf("expected #%d pre %q; got %q", p.Offset(), e.pre, pre)
306 if string(post) != e.post {
307 t.Fatalf("expected #%d post %q; got %q", p.Offset(), e.post, post)
313 func getPrePost(content []byte, offset int) (string, string) {
314 pre, post := string(content)[:offset], string(content)[offset:]
315 if i := strings.LastIndex(pre, "\n"); i >= 0 {
318 if i := strings.IndexRune(post, '\n'); i >= 0 {