mirror of
https://github.com/golang/go
synced 2024-11-25 02:07:58 -07:00
position.go: test cases for token.Pos
- adjustments to position.go due to changed sort.Search semantics - various minor fixes R=rsc CC=golang-dev, r https://golang.org/cl/3079041
This commit is contained in:
parent
e38b7f4953
commit
ac966ac706
@ -94,7 +94,14 @@ func (p Pos) IsValid() bool {
|
|||||||
|
|
||||||
|
|
||||||
func searchFiles(a []*File, x int) int {
|
func searchFiles(a []*File, x int) int {
|
||||||
return sort.Search(len(a), func(i int) bool { return a[i].base <= x })
|
i := sort.Search(len(a), func(i int) bool { return a[i].base < x })
|
||||||
|
// TODO(gri) The code below is really unfortunate. With the old
|
||||||
|
// semantics of sort.Search, it was possible to simply
|
||||||
|
// return i! Need to rethink the Search API.
|
||||||
|
if i == 0 || i < len(a) && a[i].base == x {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
return i - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -150,9 +157,9 @@ func (f *File) AddLineInfo(offset int, filename string, line int) {
|
|||||||
//
|
//
|
||||||
type File struct {
|
type File struct {
|
||||||
set *FileSet
|
set *FileSet
|
||||||
base int
|
name string // file name as provided to AddFile
|
||||||
size int
|
base int // Pos value range for this file is [base...base+size]
|
||||||
name string
|
size int // file size as provided to AddFile
|
||||||
|
|
||||||
// lines and infos are protected by set.mutex
|
// lines and infos are protected by set.mutex
|
||||||
lines []int
|
lines []int
|
||||||
@ -187,7 +194,7 @@ func (f *File) LineCount() int {
|
|||||||
//
|
//
|
||||||
func (f *File) AddLine(offset int) {
|
func (f *File) AddLine(offset int) {
|
||||||
f.set.mutex.Lock()
|
f.set.mutex.Lock()
|
||||||
if i := len(f.lines); i == 0 || f.lines[i-1] < offset && offset <= f.size {
|
if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset <= f.size {
|
||||||
f.lines = append(f.lines, offset)
|
f.lines = append(f.lines, offset)
|
||||||
}
|
}
|
||||||
f.set.mutex.Unlock()
|
f.set.mutex.Unlock()
|
||||||
@ -252,12 +259,26 @@ func (f *File) Position(offset int) Position {
|
|||||||
|
|
||||||
|
|
||||||
func searchUints(a []int, x int) int {
|
func searchUints(a []int, x int) int {
|
||||||
return sort.Search(len(a), func(i int) bool { return a[i] <= x })
|
i := sort.Search(len(a), func(i int) bool { return a[i] < x })
|
||||||
|
// TODO(gri) The code below is really unfortunate. With the old
|
||||||
|
// semantics of sort.Search, it was possible to simply
|
||||||
|
// return i! Need to rethink the Search API.
|
||||||
|
if i == 0 || i < len(a) && a[i] == x {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
return i - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func searchLineInfos(a []lineInfo, x int) int {
|
func searchLineInfos(a []lineInfo, x int) int {
|
||||||
return sort.Search(len(a), func(i int) bool { return a[i].offset <= x })
|
i := sort.Search(len(a), func(i int) bool { return a[i].offset < x })
|
||||||
|
// TODO(gri) The code below is really unfortunate. With the old
|
||||||
|
// semantics of sort.Search, it was possible to simply
|
||||||
|
// return i! Need to rethink the Search API.
|
||||||
|
if i == 0 || i < len(a) && a[i].offset == x {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
return i - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -298,18 +319,18 @@ func NewFileSet() *FileSet {
|
|||||||
|
|
||||||
// AddFile adds a new file with a given filename and file size to a the
|
// AddFile adds a new file with a given filename and file size to a the
|
||||||
// file set s and returns the file. Multiple files may have the same name.
|
// file set s and returns the file. Multiple files may have the same name.
|
||||||
// File.Pos may be used to create file-specifiction position values from a
|
// File.Pos may be used to create file-specific position values from a
|
||||||
// file offset.
|
// file offset.
|
||||||
//
|
//
|
||||||
func (s *FileSet) AddFile(filename string, size int) *File {
|
func (s *FileSet) AddFile(filename string, size int) *File {
|
||||||
s.mutex.Lock()
|
s.mutex.Lock()
|
||||||
f := &File{s, s.base, size, filename, []int{0}, nil}
|
defer s.mutex.Unlock()
|
||||||
|
f := &File{s, filename, s.base, size, []int{0}, nil}
|
||||||
s.base += size + 1 // +1 because EOF also has a position
|
s.base += size + 1 // +1 because EOF also has a position
|
||||||
if s.base < 0 {
|
if s.base < 0 {
|
||||||
panic("token.Pos offset overflow (> 2G of source code in file set)")
|
panic("token.Pos offset overflow (> 2G of source code in file set)")
|
||||||
}
|
}
|
||||||
s.index[f] = len(s.files)
|
s.index[f] = len(s.files)
|
||||||
s.files = append(s.files, f)
|
s.files = append(s.files, f)
|
||||||
s.mutex.Unlock()
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
136
src/pkg/go/token/position_test.go
Normal file
136
src/pkg/go/token/position_test.go
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// Copyright 2010 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 token
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func checkPos(t *testing.T, msg string, p, q Position) {
|
||||||
|
if p.Filename != q.Filename {
|
||||||
|
t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename)
|
||||||
|
}
|
||||||
|
if p.Offset != q.Offset {
|
||||||
|
t.Errorf("%s: expected offset = %d; got %d", msg, q.Offset, p.Offset)
|
||||||
|
}
|
||||||
|
if p.Line != q.Line {
|
||||||
|
t.Errorf("%s: expected line = %d; got %d", msg, q.Line, p.Line)
|
||||||
|
}
|
||||||
|
if p.Column != q.Column {
|
||||||
|
t.Errorf("%s: expected column = %d; got %d", msg, q.Column, p.Column)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestNoPos(t *testing.T) {
|
||||||
|
if NoPos.IsValid() {
|
||||||
|
t.Errorf("NoPos should not be valid")
|
||||||
|
}
|
||||||
|
var fset *FileSet
|
||||||
|
checkPos(t, "nil NoPos", fset.Position(NoPos), Position{})
|
||||||
|
fset = NewFileSet()
|
||||||
|
checkPos(t, "fset NoPos", fset.Position(NoPos), Position{})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
filename string
|
||||||
|
size int
|
||||||
|
lines []int
|
||||||
|
}{
|
||||||
|
{"a", 0, []int{}},
|
||||||
|
{"b", 5, []int{0}},
|
||||||
|
{"c", 10, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}},
|
||||||
|
{"d", 100, []int{0, 5, 10, 20, 30, 70, 71, 72, 80, 85, 90, 99}},
|
||||||
|
{"e", 777, []int{0, 80, 100, 120, 130, 180, 267, 455, 500, 567, 620}},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func linecol(lines []int, offs int) (int, int) {
|
||||||
|
prevLineOffs := 0
|
||||||
|
for line, lineOffs := range lines {
|
||||||
|
if offs < lineOffs {
|
||||||
|
return line, offs - prevLineOffs + 1
|
||||||
|
}
|
||||||
|
prevLineOffs = lineOffs
|
||||||
|
}
|
||||||
|
return len(lines), offs - prevLineOffs + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
|
||||||
|
for offs := 0; offs < f.Size(); offs++ {
|
||||||
|
p := f.Pos(offs)
|
||||||
|
offs2 := f.Offset(p)
|
||||||
|
if offs2 != offs {
|
||||||
|
t.Errorf("%s, Offset: expected offset %d; got %d", f.Name(), offs, offs2)
|
||||||
|
}
|
||||||
|
line, col := linecol(lines, offs)
|
||||||
|
msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
|
||||||
|
checkPos(t, msg, f.Position(offs), Position{f.Name(), offs, line, col})
|
||||||
|
checkPos(t, msg, fset.Position(p), Position{f.Name(), offs, line, col})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestPositions(t *testing.T) {
|
||||||
|
fset := NewFileSet()
|
||||||
|
for _, test := range tests {
|
||||||
|
// add file and verify name and size
|
||||||
|
f := fset.AddFile(test.filename, test.size)
|
||||||
|
if f.Name() != test.filename {
|
||||||
|
t.Errorf("expected filename %q; got %q", test.filename, f.Name())
|
||||||
|
}
|
||||||
|
if f.Size() != test.size {
|
||||||
|
t.Errorf("%s: expected file size %d; got %d", f.Name(), test.size, f.Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
// add lines individually and verify all positions
|
||||||
|
for i, offset := range test.lines {
|
||||||
|
f.AddLine(offset)
|
||||||
|
if f.LineCount() != i+1 {
|
||||||
|
t.Errorf("%s, AddLine: expected line count %d; got %d", f.Name(), i+1, f.LineCount())
|
||||||
|
}
|
||||||
|
// adding the same offset again should be ignored
|
||||||
|
f.AddLine(offset)
|
||||||
|
if f.LineCount() != i+1 {
|
||||||
|
t.Errorf("%s, AddLine: expected unchanged line count %d; got %d", f.Name(), i+1, f.LineCount())
|
||||||
|
}
|
||||||
|
verifyPositions(t, fset, f, test.lines[0:i+1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// add lines at once and verify all positions
|
||||||
|
ok := f.SetLines(test.lines)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("%s: SetLines failed", f.Name())
|
||||||
|
}
|
||||||
|
if f.LineCount() != len(test.lines) {
|
||||||
|
t.Errorf("%s, SetLines: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
|
||||||
|
}
|
||||||
|
verifyPositions(t, fset, f, test.lines)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func TestLineInfo(t *testing.T) {
|
||||||
|
fset := NewFileSet()
|
||||||
|
f := fset.AddFile("foo", 500)
|
||||||
|
lines := []int{0, 42, 77, 100, 210, 220, 277, 300, 333, 401}
|
||||||
|
// add lines individually and provide alternative line information
|
||||||
|
for _, offs := range lines {
|
||||||
|
f.AddLine(offs)
|
||||||
|
f.AddLineInfo(offs, "bar", 42)
|
||||||
|
}
|
||||||
|
// verify positions for all offsets
|
||||||
|
for offs := 0; offs <= f.Size(); offs++ {
|
||||||
|
p := f.Pos(offs)
|
||||||
|
_, col := linecol(lines, offs)
|
||||||
|
msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
|
||||||
|
checkPos(t, msg, f.Position(offs), Position{"bar", offs, 42, col})
|
||||||
|
checkPos(t, msg, fset.Position(p), Position{"bar", offs, 42, col})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user