Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Commit 010d49a

Browse files
authored
positioner: simplify, fix and add more tests (#342)
* positioner: simplify fix and add more tests Signed-off-by: Denys Smirnov <[email protected]>
1 parent 1322001 commit 010d49a

File tree

3 files changed

+88
-33
lines changed

3 files changed

+88
-33
lines changed

uast/transformer/positioner/positions.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,21 +76,20 @@ type positionIndex struct {
7676
}
7777

7878
func newPositionIndex(data []byte) *positionIndex {
79-
idx := &positionIndex{}
80-
idx.size = len(data)
79+
idx := &positionIndex{
80+
size: len(data),
81+
}
8182
idx.addLineOffset(0)
8283
for offset, b := range data {
8384
if b == '\n' {
8485
idx.addLineOffset(offset + 1)
8586
}
8687
}
87-
8888
return idx
8989
}
9090

9191
func (idx *positionIndex) addLineOffset(offset int) {
9292
idx.offsetByLine = append(idx.offsetByLine, offset)
93-
9493
}
9594

9695
// LineCol returns a one-based line and col given a zero-based byte offset.
@@ -146,7 +145,7 @@ func (idx *positionIndex) Offset(line, col int) (int, error) {
146145
maxCol = 1
147146
}
148147

149-
if col < minCol || (maxCol > 0 && col - 1 > maxCol) {
148+
if col < minCol || (maxCol > 0 && col-1 > maxCol) {
150149
return 0, fmt.Errorf("column out of bounds: %d [%d, %d]", col, minCol, maxCol)
151150
}
152151

uast/transformer/positioner/positions_test.go

Lines changed: 83 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,42 @@ import (
88
"gopkg.in/bblfsh/sdk.v2/uast/nodes"
99
)
1010

11-
func TestFillLineColFromOffset(t *testing.T) {
11+
func offset(v int) nodes.Object {
12+
return uast.Position{Offset: uint32(v)}.ToObject()
13+
}
14+
15+
func lineCol(line, col int) nodes.Object {
16+
return uast.Position{Line: uint32(line), Col: uint32(col)}.ToObject()
17+
}
18+
19+
func fullPos(off, line, col int) nodes.Object {
20+
return uast.Position{Offset: uint32(off), Line: uint32(line), Col: uint32(col)}.ToObject()
21+
}
22+
23+
func TestFillLineColNested(t *testing.T) {
1224
require := require.New(t)
1325

1426
data := "hello\n\nworld"
1527

1628
input := nodes.Object{
17-
uast.KeyStart: uast.Position{Offset: 0}.ToObject(),
18-
uast.KeyEnd: uast.Position{Offset: 4}.ToObject(),
19-
"a": nodes.Array{nodes.Object{
20-
uast.KeyStart: uast.Position{Offset: 7}.ToObject(),
21-
uast.KeyEnd: uast.Position{Offset: 12}.ToObject(),
29+
"a": nodes.Object{
30+
uast.KeyStart: offset(0),
31+
uast.KeyEnd: offset(4),
32+
},
33+
"b": nodes.Array{nodes.Object{
34+
uast.KeyStart: offset(7),
35+
uast.KeyEnd: offset(12),
2236
}},
2337
}
2438

2539
expected := nodes.Object{
26-
uast.KeyStart: uast.Position{Offset: 0, Line: 1, Col: 1}.ToObject(),
27-
uast.KeyEnd: uast.Position{Offset: 4, Line: 1, Col: 5}.ToObject(),
28-
"a": nodes.Array{nodes.Object{
29-
uast.KeyStart: uast.Position{Offset: 7, Line: 3, Col: 1}.ToObject(),
30-
uast.KeyEnd: uast.Position{Offset: 12, Line: 3, Col: 6}.ToObject(),
40+
"a": nodes.Object{
41+
uast.KeyStart: fullPos(0, 1, 1),
42+
uast.KeyEnd: fullPos(4, 1, 5),
43+
},
44+
"b": nodes.Array{nodes.Object{
45+
uast.KeyStart: fullPos(7, 3, 1),
46+
uast.KeyEnd: fullPos(12, 3, 6),
3147
}},
3248
}
3349

@@ -37,25 +53,30 @@ func TestFillLineColFromOffset(t *testing.T) {
3753
require.Equal(expected, out)
3854
}
3955

40-
func TestFillOffsetFromLineCol(t *testing.T) {
56+
func TestFillOffsetNested(t *testing.T) {
4157
require := require.New(t)
4258

4359
data := "hello\n\nworld"
60+
4461
input := nodes.Object{
45-
uast.KeyStart: uast.Position{Line: 1, Col: 1}.ToObject(),
46-
uast.KeyEnd: uast.Position{Line: 1, Col: 5}.ToObject(),
47-
"a": nodes.Array{nodes.Object{
48-
uast.KeyStart: uast.Position{Line: 3, Col: 1}.ToObject(),
49-
uast.KeyEnd: uast.Position{Line: 3, Col: 5}.ToObject(),
62+
"a": nodes.Object{
63+
uast.KeyStart: lineCol(1, 1),
64+
uast.KeyEnd: lineCol(1, 5),
65+
},
66+
"b": nodes.Array{nodes.Object{
67+
uast.KeyStart: lineCol(3, 1),
68+
uast.KeyEnd: lineCol(3, 6),
5069
}},
5170
}
5271

5372
expected := nodes.Object{
54-
uast.KeyStart: uast.Position{Offset: 0, Line: 1, Col: 1}.ToObject(),
55-
uast.KeyEnd: uast.Position{Offset: 4, Line: 1, Col: 5}.ToObject(),
56-
"a": nodes.Array{nodes.Object{
57-
uast.KeyStart: uast.Position{Offset: 7, Line: 3, Col: 1}.ToObject(),
58-
uast.KeyEnd: uast.Position{Offset: 11, Line: 3, Col: 5}.ToObject(),
73+
"a": nodes.Object{
74+
uast.KeyStart: fullPos(0, 1, 1),
75+
uast.KeyEnd: fullPos(4, 1, 5),
76+
},
77+
"b": nodes.Array{nodes.Object{
78+
uast.KeyStart: fullPos(7, 3, 1),
79+
uast.KeyEnd: fullPos(12, 3, 6),
5980
}},
6081
}
6182

@@ -65,23 +86,58 @@ func TestFillOffsetFromLineCol(t *testing.T) {
6586
require.Equal(expected, out)
6687
}
6788

68-
func TestEmptyFile(t *testing.T) {
89+
func TestFillOffsetEmptyFile(t *testing.T) {
6990
require := require.New(t)
7091

7192
data := ""
7293

7394
input := nodes.Object{
74-
uast.KeyStart: uast.Position{Line: 1, Col: 1}.ToObject(),
75-
uast.KeyEnd: uast.Position{Line: 1, Col: 1}.ToObject(),
95+
uast.KeyStart: lineCol(1, 1),
96+
uast.KeyEnd: lineCol(1, 1),
7697
}
7798

7899
expected := nodes.Object{
79-
uast.KeyStart: uast.Position{Offset: 0, Line: 1, Col: 1}.ToObject(),
80-
uast.KeyEnd: uast.Position{Offset: 0, Line: 1, Col: 1}.ToObject(),
100+
uast.KeyStart: fullPos(0, 1, 1),
101+
uast.KeyEnd: fullPos(0, 1, 1),
81102
}
82103

83104
p := NewFillOffsetFromLineCol()
84105
out, err := p.OnCode(data).Do(input)
85106
require.NoError(err)
86107
require.Equal(expected, out)
87108
}
109+
110+
func TestPosIndex(t *testing.T) {
111+
// Verify that a multi-byte Unicode rune does not displace offsets after
112+
// its occurrence in the input. Test few other simple cases as well.
113+
const source = `line1
114+
ё2
115+
a3`
116+
var cases = []uast.Position{
117+
{Offset: 0, Line: 1, Col: 1},
118+
{Offset: 4, Line: 1, Col: 5},
119+
120+
// multi-byte unicode rune
121+
{Offset: 6, Line: 2, Col: 1},
122+
{Offset: 8, Line: 2, Col: 3}, // col is a byte offset+1, not a rune index
123+
124+
{Offset: 10, Line: 3, Col: 1},
125+
{Offset: 11, Line: 3, Col: 2},
126+
127+
{Offset: 12, Line: 3, Col: 3}, // special case — EOF position
128+
}
129+
130+
ind := newPositionIndex([]byte(source))
131+
for _, c := range cases {
132+
t.Run("", func(t *testing.T) {
133+
line, col, err := ind.LineCol(int(c.Offset))
134+
require.NoError(t, err)
135+
require.Equal(t, c.Line, uint32(line))
136+
require.Equal(t, c.Col, uint32(col))
137+
138+
off, err := ind.Offset(int(c.Line), int(c.Col))
139+
require.NoError(t, err)
140+
require.Equal(t, c.Offset, uint32(off))
141+
})
142+
}
143+
}

uast/uast.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ type Position struct {
8282
Offset uint32 `json:"offset"`
8383
// Line is the line number. It is a 1-based index.
8484
Line uint32 `json:"line"`
85-
// Col is the column number (the byte offset of the position relative to
85+
// Col is the column number the byte offset of the position relative to
8686
// a line. It is a 1-based index.
8787
Col uint32 `json:"col"`
8888
}

0 commit comments

Comments
 (0)