1
16
17 package warn
18
19 import (
20 "bytes"
21 "fmt"
22 "strings"
23 "testing"
24
25 "github.com/bazelbuild/buildtools/build"
26 "github.com/bazelbuild/buildtools/testutils"
27 )
28
29 func checkTypes(t *testing.T, input, output string) {
30 input = strings.TrimLeft(input, "\n")
31 f, err := build.Parse("test.bzl", []byte(input))
32 if err != nil {
33 t.Fatalf("%v", err)
34 }
35 types := DetectTypes(f)
36
37 var edit func(expr build.Expr, stack []build.Expr) build.Expr
38 edit = func(expr build.Expr, stack []build.Expr) build.Expr {
39 t, ok := types[expr]
40 if !ok {
41 return nil
42 }
43
44 build.EditChildren(expr, edit)
45 start, _ := expr.Span()
46 return &build.Ident{
47 Name: fmt.Sprintf("%s:<%s>", t, build.FormatString(expr)),
48 NamePos: start,
49 }
50 }
51
52 build.Edit(f, edit)
53
54 want := []byte(strings.TrimLeft(output, "\n"))
55 have := build.FormatWithoutRewriting(f)
56 if !bytes.Equal(have, want) {
57 t.Errorf("detected types incorrectly: diff shows -expected, +ours")
58 testutils.Tdiff(t, want, have)
59 }
60 }
61
62 func TestTypes(t *testing.T) {
63 checkTypes(t, `
64 b = True
65 b2 = bool("hello")
66 i = 3
67 i2 = int(1.2)
68 f = 1.2
69 f2 = float(3)
70 s = "string"
71 s2 = s
72 s3 = str(42)
73 d = {}
74 d2 = {foo: bar}
75 d3 = dict(**foo)
76 d4 = {k: v for k, v in foo}
77 dep = depset(items=[s, d])
78 foo = bar
79 `, `
80 b = bool:<True>
81 b2 = bool:<bool(string:<"hello">)>
82 i = int:<3>
83 i2 = int:<int(float:<1.2>)>
84 f = float:<1.2>
85 f2 = float:<float(int:<3>)>
86 s = string:<"string">
87 s2 = string:<s>
88 s3 = string:<str(int:<42>)>
89 d = dict:<{}>
90 d2 = dict:<{foo: bar}>
91 d3 = dict:<dict(**foo)>
92 d4 = dict:<{k: v for k, v in foo}>
93 dep = depset:<depset(items = list:<[
94 string:<s>,
95 dict:<d>,
96 ]>)>
97 foo = bar
98 `)
99 }
100
101 func TestScopesFunction(t *testing.T) {
102 checkTypes(t, `
103 s = "string"
104
105 def f():
106 s1 = s
107
108 def g():
109 s2 = s1
110 `, `
111 s = string:<"string">
112
113 def f():
114 s1 = string:<s>
115
116 def g():
117 s2 = s1
118 `)
119 }
120
121 func TestScopesParameters(t *testing.T) {
122 checkTypes(t, `
123 x = 3
124 y = 4
125 z = 5
126
127 foo(y = "bar")
128 foo(x, y = bar(z = z), t + z)
129
130
131 def f(z = "bar"):
132 return z
133
134 bar(x, y, z)
135 `, `
136 x = int:<3>
137 y = int:<4>
138 z = int:<5>
139
140 foo(y = string:<"bar">)
141 foo(int:<x>, y = bar(z = int:<z>), int:<t + int:<z>>)
142
143 def f(z = string:<"bar">):
144 return string:<z>
145
146 bar(int:<x>, int:<y>, int:<z>)
147 `)
148 }
149
150 func TestBinaryOperators(t *testing.T) {
151 checkTypes(t, `
152 i = 1
153 d = {}
154 s = depset()
155
156 i - foo
157 foo - i
158
159 d + bar
160 bar + d
161
162 s | baz
163 baz | s
164 `, `
165 i = int:<1>
166 d = dict:<{}>
167 s = depset:<depset()>
168
169 int:<int:<i> - foo>
170 int:<foo - int:<i>>
171
172 dict:<dict:<d> + bar>
173 dict:<bar + dict:<d>>
174
175 depset:<depset:<s> | baz>
176 depset:<baz | depset:<s>>
177 `)
178 }
179
180 func TestPercentOperator(t *testing.T) {
181 checkTypes(t, `
182 n = 3
183 s = "foo"
184
185 foo % n
186 foo % s
187 foo % bar
188
189 n % foo
190 s % foo
191
192 s %= foo
193 n %= foo
194
195 baz = unknown
196 baz %= s
197 baz
198
199 boq = unknown
200 boq %= n
201 boq
202 `, `
203 n = int:<3>
204 s = string:<"foo">
205
206 foo % int:<n>
207 string:<foo % string:<s>>
208 foo % bar
209
210 int:<int:<n> % foo>
211 string:<string:<s> % foo>
212
213 string:<s> %= foo
214 int:<n> %= foo
215
216 baz = unknown
217 baz %= string:<s>
218 string:<baz>
219
220 boq = unknown
221 boq %= int:<n>
222 boq
223 `)
224 }
225
226 func TestContext(t *testing.T) {
227 checkTypes(t, `
228 def foobar(ctx, foo, bar):
229 ctx
230 ctx.actions
231 ctx.actions.args()
232
233 actions = ctx.actions
234 not_args = actions.args
235 args = actions.args()
236 args
237 `, `
238 def foobar(ctx:<ctx>, foo, bar):
239 ctx:<ctx>
240 ctx.actions:<ctx:<ctx>.actions>
241 ctx.actions.args:<ctx.actions:<ctx:<ctx>.actions>.args()>
242
243 actions = ctx.actions:<ctx:<ctx>.actions>
244 not_args = ctx.actions:<actions>.args
245 args = ctx.actions.args:<ctx.actions:<actions>.args()>
246 ctx.actions.args:<args>
247 `)
248 }
249
250 func TestContextFalse(t *testing.T) {
251 checkTypes(t, `
252 def foobar(foo, bar):
253 ctx
254 ctx.actions
255 ctx.actions.args()
256 `, `
257 def foobar(foo, bar):
258 ctx
259 ctx.actions
260 ctx.actions.args()
261 `)
262 }
263
View as plain text