1// Copyright 2016 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.
4
5package src
6
7import (
8	"fmt"
9	"testing"
10)
11
12func TestPos(t *testing.T) {
13	f0 := NewFileBase("", "")
14	f1 := NewFileBase("f1", "f1")
15	f2 := NewLinePragmaBase(Pos{}, "f2", "f2", 10, 0)
16	f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", "f3", 100, 1)
17	f4 := NewLinePragmaBase(MakePos(f3, 10, 1), "f4", "f4", 100, 1)
18
19	// line directives with non-1 columns
20	f5 := NewLinePragmaBase(MakePos(f1, 5, 5), "f5", "f5", 10, 1)
21
22	// line directives from issue #19392
23	fp := NewFileBase("p.go", "p.go")
24	fc := NewLinePragmaBase(MakePos(fp, 4, 1), "c.go", "c.go", 10, 1)
25	ft := NewLinePragmaBase(MakePos(fp, 7, 1), "t.go", "t.go", 20, 1)
26	fv := NewLinePragmaBase(MakePos(fp, 10, 1), "v.go", "v.go", 30, 1)
27	ff := NewLinePragmaBase(MakePos(fp, 13, 1), "f.go", "f.go", 40, 1)
28
29	for _, test := range []struct {
30		pos    Pos
31		string string
32
33		// absolute info
34		filename  string
35		line, col uint
36
37		// relative info
38		relFilename     string
39		relLine, relCol uint
40	}{
41		{Pos{}, "<unknown line number>", "", 0, 0, "", 0, 0},
42		{MakePos(nil, 2, 3), ":2:3", "", 2, 3, "", 0, 0},
43		{MakePos(f0, 2, 3), ":2:3", "", 2, 3, "", 2, 3},
44		{MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1, 1},
45		{MakePos(f2, 7, 10), "f2:17[:7:10]", "", 7, 10, "f2", 17, 0 /* line base doesn't specify a column */},
46		{MakePos(f3, 12, 7), "f3:102:7[f1:12:7]", "f1", 12, 7, "f3", 102, 7},
47		{MakePos(f4, 25, 1), "f4:115:1[f3:25:1]", "f3", 25, 1, "f4", 115, 1},
48
49		// line directives with non-1 columns
50		{MakePos(f5, 5, 5), "f5:10:1[f1:5:5]", "f1", 5, 5, "f5", 10, 1},
51		{MakePos(f5, 5, 10), "f5:10:6[f1:5:10]", "f1", 5, 10, "f5", 10, 6},
52		{MakePos(f5, 6, 10), "f5:11:10[f1:6:10]", "f1", 6, 10, "f5", 11, 10},
53
54		// positions from issue #19392
55		{MakePos(fc, 4, 1), "c.go:10:1[p.go:4:1]", "p.go", 4, 1, "c.go", 10, 1},
56		{MakePos(ft, 7, 1), "t.go:20:1[p.go:7:1]", "p.go", 7, 1, "t.go", 20, 1},
57		{MakePos(fv, 10, 1), "v.go:30:1[p.go:10:1]", "p.go", 10, 1, "v.go", 30, 1},
58		{MakePos(ff, 13, 1), "f.go:40:1[p.go:13:1]", "p.go", 13, 1, "f.go", 40, 1},
59	} {
60		pos := test.pos
61		if got := pos.String(); got != test.string {
62			t.Errorf("%s: got %q", test.string, got)
63		}
64
65		// absolute info
66		if got := pos.Filename(); got != test.filename {
67			t.Errorf("%s: got filename %q; want %q", test.string, got, test.filename)
68		}
69		if got := pos.Line(); got != test.line {
70			t.Errorf("%s: got line %d; want %d", test.string, got, test.line)
71		}
72		if got := pos.Col(); got != test.col {
73			t.Errorf("%s: got col %d; want %d", test.string, got, test.col)
74		}
75
76		// relative info
77		if got := pos.RelFilename(); got != test.relFilename {
78			t.Errorf("%s: got relFilename %q; want %q", test.string, got, test.relFilename)
79		}
80		if got := pos.RelLine(); got != test.relLine {
81			t.Errorf("%s: got relLine %d; want %d", test.string, got, test.relLine)
82		}
83		if got := pos.RelCol(); got != test.relCol {
84			t.Errorf("%s: got relCol %d; want %d", test.string, got, test.relCol)
85		}
86	}
87}
88
89func TestPredicates(t *testing.T) {
90	b1 := NewFileBase("b1", "b1")
91	b2 := NewFileBase("b2", "b2")
92	for _, test := range []struct {
93		p, q                 Pos
94		known, before, after bool
95	}{
96		{NoPos, NoPos, false, false, false},
97		{NoPos, MakePos(nil, 1, 0), false, true, false},
98		{MakePos(b1, 0, 0), NoPos, true, false, true},
99		{MakePos(nil, 1, 0), NoPos, true, false, true},
100
101		{MakePos(nil, 1, 1), MakePos(nil, 1, 1), true, false, false},
102		{MakePos(nil, 1, 1), MakePos(nil, 1, 2), true, true, false},
103		{MakePos(nil, 1, 2), MakePos(nil, 1, 1), true, false, true},
104		{MakePos(nil, 123, 1), MakePos(nil, 1, 123), true, false, true},
105
106		{MakePos(b1, 1, 1), MakePos(b1, 1, 1), true, false, false},
107		{MakePos(b1, 1, 1), MakePos(b1, 1, 2), true, true, false},
108		{MakePos(b1, 1, 2), MakePos(b1, 1, 1), true, false, true},
109		{MakePos(b1, 123, 1), MakePos(b1, 1, 123), true, false, true},
110
111		{MakePos(b1, 1, 1), MakePos(b2, 1, 1), true, true, false},
112		{MakePos(b1, 1, 1), MakePos(b2, 1, 2), true, true, false},
113		{MakePos(b1, 1, 2), MakePos(b2, 1, 1), true, true, false},
114		{MakePos(b1, 123, 1), MakePos(b2, 1, 123), true, true, false},
115
116		// special case: unknown column (column too large to represent)
117		{MakePos(nil, 1, colMax+10), MakePos(nil, 1, colMax+20), true, false, false},
118	} {
119		if got := test.p.IsKnown(); got != test.known {
120			t.Errorf("%s known: got %v; want %v", test.p, got, test.known)
121		}
122		if got := test.p.Before(test.q); got != test.before {
123			t.Errorf("%s < %s: got %v; want %v", test.p, test.q, got, test.before)
124		}
125		if got := test.p.After(test.q); got != test.after {
126			t.Errorf("%s > %s: got %v; want %v", test.p, test.q, got, test.after)
127		}
128	}
129}
130
131func TestLico(t *testing.T) {
132	for _, test := range []struct {
133		x         lico
134		string    string
135		line, col uint
136	}{
137		{0, ":0", 0, 0},
138		{makeLico(0, 0), ":0", 0, 0},
139		{makeLico(0, 1), ":0:1", 0, 1},
140		{makeLico(1, 0), ":1", 1, 0},
141		{makeLico(1, 1), ":1:1", 1, 1},
142		{makeLico(2, 3), ":2:3", 2, 3},
143		{makeLico(lineMax, 1), fmt.Sprintf(":%d", lineMax), lineMax, 1},
144		{makeLico(lineMax+1, 1), fmt.Sprintf(":%d", lineMax), lineMax, 1}, // line too large, stick with max. line
145		{makeLico(1, colMax), ":1", 1, colMax},
146		{makeLico(1, colMax+1), ":1", 1, 0}, // column too large
147		{makeLico(lineMax+1, colMax+1), fmt.Sprintf(":%d", lineMax), lineMax, 0},
148	} {
149		x := test.x
150		if got := formatstr("", x.Line(), x.Col(), true); got != test.string {
151			t.Errorf("%s: got %q", test.string, got)
152		}
153	}
154}
155
156func TestIsStmt(t *testing.T) {
157	def := fmt.Sprintf(":%d", PosDefaultStmt)
158	is := fmt.Sprintf(":%d", PosIsStmt)
159	not := fmt.Sprintf(":%d", PosNotStmt)
160
161	for _, test := range []struct {
162		x         lico
163		string    string
164		line, col uint
165	}{
166		{0, ":0" + not, 0, 0},
167		{makeLico(0, 0), ":0" + not, 0, 0},
168		{makeLico(0, 1), ":0:1" + def, 0, 1},
169		{makeLico(1, 0), ":1" + def, 1, 0},
170		{makeLico(1, 1), ":1:1" + def, 1, 1},
171		{makeLico(1, 1).withIsStmt(), ":1:1" + is, 1, 1},
172		{makeLico(1, 1).withNotStmt(), ":1:1" + not, 1, 1},
173		{makeLico(lineMax, 1), fmt.Sprintf(":%d", lineMax) + def, lineMax, 1},
174		{makeLico(lineMax+1, 1), fmt.Sprintf(":%d", lineMax) + def, lineMax, 1}, // line too large, stick with max. line
175		{makeLico(1, colMax), ":1" + def, 1, colMax},
176		{makeLico(1, colMax+1), ":1" + def, 1, 0}, // column too large
177		{makeLico(lineMax+1, colMax+1), fmt.Sprintf(":%d", lineMax) + def, lineMax, 0},
178		{makeLico(lineMax+1, colMax+1).withIsStmt(), fmt.Sprintf(":%d", lineMax) + is, lineMax, 0},
179		{makeLico(lineMax+1, colMax+1).withNotStmt(), fmt.Sprintf(":%d", lineMax) + not, lineMax, 0},
180	} {
181		x := test.x
182		if got := formatstr("", x.Line(), x.Col(), true) + fmt.Sprintf(":%d", x.IsStmt()); got != test.string {
183			t.Errorf("%s: got %q", test.string, got)
184		}
185	}
186}
187
188func TestLogue(t *testing.T) {
189	defp := fmt.Sprintf(":%d", PosDefaultLogue)
190	pro := fmt.Sprintf(":%d", PosPrologueEnd)
191	epi := fmt.Sprintf(":%d", PosEpilogueBegin)
192
193	defs := fmt.Sprintf(":%d", PosDefaultStmt)
194	not := fmt.Sprintf(":%d", PosNotStmt)
195
196	for i, test := range []struct {
197		x         lico
198		string    string
199		line, col uint
200	}{
201		{makeLico(0, 0).withXlogue(PosDefaultLogue), ":0" + not + defp, 0, 0},
202		{makeLico(0, 0).withXlogue(PosPrologueEnd), ":0" + not + pro, 0, 0},
203		{makeLico(0, 0).withXlogue(PosEpilogueBegin), ":0" + not + epi, 0, 0},
204
205		{makeLico(0, 1).withXlogue(PosDefaultLogue), ":0:1" + defs + defp, 0, 1},
206		{makeLico(0, 1).withXlogue(PosPrologueEnd), ":0:1" + defs + pro, 0, 1},
207		{makeLico(0, 1).withXlogue(PosEpilogueBegin), ":0:1" + defs + epi, 0, 1},
208
209		{makeLico(1, 0).withXlogue(PosDefaultLogue), ":1" + defs + defp, 1, 0},
210		{makeLico(1, 0).withXlogue(PosPrologueEnd), ":1" + defs + pro, 1, 0},
211		{makeLico(1, 0).withXlogue(PosEpilogueBegin), ":1" + defs + epi, 1, 0},
212
213		{makeLico(1, 1).withXlogue(PosDefaultLogue), ":1:1" + defs + defp, 1, 1},
214		{makeLico(1, 1).withXlogue(PosPrologueEnd), ":1:1" + defs + pro, 1, 1},
215		{makeLico(1, 1).withXlogue(PosEpilogueBegin), ":1:1" + defs + epi, 1, 1},
216
217		{makeLico(lineMax, 1).withXlogue(PosDefaultLogue), fmt.Sprintf(":%d", lineMax) + defs + defp, lineMax, 1},
218		{makeLico(lineMax, 1).withXlogue(PosPrologueEnd), fmt.Sprintf(":%d", lineMax) + defs + pro, lineMax, 1},
219		{makeLico(lineMax, 1).withXlogue(PosEpilogueBegin), fmt.Sprintf(":%d", lineMax) + defs + epi, lineMax, 1},
220	} {
221		x := test.x
222		if got := formatstr("", x.Line(), x.Col(), true) + fmt.Sprintf(":%d:%d", x.IsStmt(), x.Xlogue()); got != test.string {
223			t.Errorf("%d: %s: got %q", i, test.string, got)
224		}
225	}
226}
227