github.com/yunabe/lgo@v0.0.0-20190709125917-42c42d410fdf/converter/inspect_test.go (about) 1 package converter 2 3 import ( 4 "go/token" 5 "go/types" 6 "strings" 7 "testing" 8 ) 9 10 func TestInspect(t *testing.T) { 11 tests := []struct { 12 name string 13 src string 14 doc string 15 query string 16 }{ 17 { 18 name: "local variable", 19 src: ` 20 import ( 21 "fmt" 22 ) 23 24 func sum(x, y int) int { return x + y } 25 func f(x int) (y int) { 26 s := sum(x, x) 27 return [cur]s*x 28 }`, 29 doc: "var s int", 30 }, 31 { 32 name: "local const", 33 src: ` 34 func f(x int) (y int) { 35 const s = 10 36 return [cur]s*x 37 }`, 38 doc: "const s untyped int", 39 }, 40 { 41 name: "global_variable", 42 src: ` 43 import ( 44 "fmt" 45 ) 46 47 var ( 48 s int 49 ) 50 51 func sum(x, y int) { [cur]s = x + y }`, 52 doc: "var s int", 53 }, 54 { 55 name: "global_const", 56 src: ` 57 const myVal = 10 58 x := [cur]myVal * 10 59 `, 60 doc: "const myVal untyped int", 61 }, 62 { 63 name: "func", 64 src: ` 65 func fn(x int) int { return x * x } 66 [cur]fn(10) 67 `, 68 doc: "func fn(x int) int", 69 }, { 70 name: "func_args", 71 src: ` 72 func fn(x int) int { return x * x } 73 fn([cur]`, 74 doc: "func fn(x int) int", 75 }, { 76 name: "func_args_closed", 77 src: ` 78 func fn(x int) int { return x * x } 79 fn([cur]) 80 `, 81 doc: "func fn(x int) int", 82 }, { 83 name: "func_args_after_close", 84 src: ` 85 func fn(x int) int { return x * x } 86 fn()[cur] 87 `, 88 }, { 89 name: "func_args_id", 90 src: ` 91 func fn(x int) int { return x * x } 92 n := 10 93 fn(n[cur]) 94 `, 95 doc: "var n int", 96 }, { 97 name: "func_args_comma", 98 src: ` 99 func fn(x int) int { return x * x } 100 n := 10 101 fn(n,[cur]) 102 `, 103 doc: "func fn(x int) int", 104 }, { 105 name: "func_args_nested", 106 src: ` 107 func fn(x int) int { return x * x } 108 func xy(a int) int { return x * x } 109 fn(xy([cur] 110 `, 111 doc: "func xy(a int) int", 112 }, { 113 name: "func_args_selector", 114 src: ` 115 import "bytes" 116 bytes.Compare(nil,[cur])`, 117 query: "bytes.Compare", 118 }, { 119 name: "method", 120 src: ` 121 type typ int 122 func (t typ) Int() int { return int(t) } 123 124 x := typ(123) 125 x.[cur]Int()`, 126 // TODO: Includes a receiver. 127 doc: "func Int() int", 128 }, 129 { 130 name: "interface_method", 131 src: ` 132 type hello interface { 133 sayHello(name string) 134 } 135 var h hello 136 h.[cur]sayHello()`, 137 // TODO: Includes a receiver. 138 doc: "func sayHello(name string)", 139 }, 140 { 141 name: "custom_type_var", 142 src: ` 143 type message string 144 var m message 145 [cur]m`, 146 // TODO: Remove "cmd/hello.". 147 doc: "var m cmd/hello.message", 148 }, 149 { 150 name: "package", 151 src: ` 152 import ( 153 "fmt" 154 ) 155 156 [cur]fmt.Println(0, 1)`, 157 query: "fmt", 158 }, 159 { 160 name: "renamed package", 161 src: ` 162 import ( 163 pkg "fmt" 164 ) 165 166 [cur]pkg.Println(0, 1)`, 167 query: "fmt", 168 }, 169 { 170 name: "package var", 171 src: ` 172 import ( 173 "fmt" 174 "os" 175 ) 176 177 fmt.Fprintln(os.[cur]Stderr, "error")`, 178 query: "os.Stderr", 179 }, 180 { 181 name: "package const", 182 src: ` 183 import ( 184 "io" 185 ) 186 187 x := io.[cur]SeekStart`, 188 query: "io.SeekStart", 189 }, 190 { 191 name: "package func", 192 src: ` 193 import ( 194 "fmt" 195 ) 196 197 fmt.P[cur]rintln(0, 1)`, 198 query: "fmt.Println", 199 }, 200 { 201 name: "method", 202 src: ` 203 import ( 204 "bytes" 205 ) 206 207 var buf bytes.Buffer 208 buf.[cur]Len()`, 209 query: "bytes.Buffer.Len", 210 }, 211 { 212 name: "renamed pkg method", 213 src: ` 214 import ( 215 b "bytes" 216 ) 217 218 var buf b.Buffer 219 buf.[cur]Len()`, 220 query: "bytes.Buffer.Len", 221 }, { 222 name: "package_interface_method", 223 src: ` 224 import ( 225 "bytes" 226 "io" 227 ) 228 229 var buf bytes.Buffer 230 var r io.Reader = &buf 231 r.[cur]Read(nil)`, 232 query: "io.Reader.Read", 233 }, { 234 name: "type", 235 src: ` 236 import ( 237 "flag" 238 ) 239 240 f := flag.F[cur]lag{}`, 241 query: "flag.Flag", 242 }, { 243 // This fails with go1.8 expectedly. 244 name: "field", 245 src: ` 246 import ( 247 "flag" 248 ) 249 250 f := flag.Flag{[cur]Name: "myflag"}`, 251 query: "flag.Flag.Name", 252 }, { 253 name: "local_field_def", 254 src: "type st struct { [cur]val int }", 255 doc: "var val int", 256 }, { 257 name: "local_field_ref", 258 src: ` 259 type st struct { val int } 260 var x st 261 x.[cur]val`, 262 doc: "var val int", 263 }, { 264 name: "invalid_type", 265 src: ` 266 var x foobar 267 [cur]x + 10`, 268 }, 269 { 270 name: "invalid_const_val", 271 src: ` 272 func sum(x, y int) int { return x + y } 273 const x = sum(10, 20) 274 [cur]x + 10`, 275 // TODO: Fix this 276 doc: "const x invalid type", 277 }, 278 { 279 name: "invalid syntax", 280 src: `[cur]x := 3 +`, 281 }, 282 { 283 name: "invalid_syntax_after_cur", 284 src: `[cur]x := 3 + 4 285 y := x +`, 286 doc: "var x int", 287 }, 288 { 289 name: "right_after_id", 290 src: ` 291 func f(x int) (y int) { 292 s := x+1 293 return s[cur]*x 294 }`, 295 doc: "var s int", 296 }, 297 { 298 name: "typename_struct", 299 src: ` 300 type mytype struct { 301 X int 302 Y string 303 } 304 v := [cur]mytype{}`, 305 doc: "type mytype struct{X int; Y string}", 306 }, 307 { 308 name: "typename_interface", 309 src: ` 310 type mytype interface { 311 Method(x int) 312 } 313 v := [cur]mytype(nil)`, 314 doc: "type mytype interface{Method(x int)}", 315 }, 316 { 317 name: "typename_in_var", 318 src: ` 319 type message string 320 var m [cur]message`, 321 doc: "type message string", 322 }, 323 // def_ prefix tests test Inspect on identifiers that define objects. 324 { 325 name: "def_global_variable", 326 src: `var [cur]x = 10`, 327 doc: "var x int", 328 }, 329 { 330 name: "def_func", 331 src: ` 332 func [cur]myFunc(x int) (y int) { return x * 2 } 333 myFunc(10)`, 334 doc: "func myFunc(x int) (y int)", 335 }, 336 { 337 name: "def_method", 338 src: ` 339 type myType int 340 func (myType) [cur]myMethod() {}`, 341 // TODO: Print the receiver 342 doc: "func myMethod()", 343 }, 344 { 345 name: "def_type", 346 src: `type [cur]myType int`, 347 doc: "type myType int", 348 }, { 349 name: "lgo_context", 350 src: `_[cur]ctx.Done()`, 351 doc: "var _ctx github.com/yunabe/lgo/core.LgoContext", 352 }, { 353 name: "lgo_context_method", 354 src: `_ctx.[cur]Done()`, 355 query: "context.Context.Done", 356 }, { 357 name: "lgo_context_infunc", 358 src: ` 359 func f() { 360 _ctx.[cur]Done() 361 }`, 362 query: "context.Context.Done", 363 }, { 364 name: "builtin_error_method", 365 src: ` 366 var err error 367 err.Error[cur] 368 `, 369 query: "builtin.error.Error", 370 }, { 371 name: "builtin_func", 372 src: ` 373 var s []string 374 s = ap[cur]pend(s, "hello")`, 375 query: "builtin.append", 376 }, { 377 name: "builtin_panic", 378 src: `pa[cur]nic("panic")`, 379 query: "builtin.panic", 380 }, { 381 name: "builtin_type", 382 src: `var f fl[cur]oat64`, 383 query: "builtin.float64", 384 }, 385 } 386 for _, tt := range tests { 387 t.Run(tt.name, func(t *testing.T) { 388 src := tt.src 389 pos := token.Pos(strings.Index(src, "[cur]") + 1) 390 if pos == token.NoPos { 391 t.Error("[cur] not found in src") 392 return 393 } 394 395 obj, local := inspectObject(strings.Replace(src, "[cur]", "", -1), pos, &Config{}) 396 doc, query := getDocOrGoDocQuery(obj, local) 397 var queryStr string 398 if query != nil { 399 queryStr = query.pkg 400 if len(query.ids) > 0 { 401 queryStr += "." + strings.Join(query.ids, ".") 402 } 403 } 404 if tt.doc != doc { 405 t.Errorf("Expected %q but got %q", tt.doc, doc) 406 } 407 if tt.query != queryStr { 408 t.Errorf("Expected %q but got %q", tt.query, queryStr) 409 } 410 }) 411 } 412 } 413 414 func TestInspectWithOlds(t *testing.T) { 415 result := Convert(` 416 x := 10 417 X := x + 10 418 `, &Config{LgoPkgPath: "lgo/pkg0"}) 419 if result.Err != nil { 420 t.Error(result.Err) 421 return 422 } 423 olds := []types.Object{result.Pkg.Scope().Lookup("x"), 424 result.Pkg.Scope().Lookup("X"), 425 } 426 tests := []struct{ id, query string }{ 427 {"x", "lgo/pkg0.Def_x"}, 428 {"X", "lgo/pkg0.X"}, 429 } 430 for _, tt := range tests { 431 src := `y := x + X` 432 doc, query := InspectIdent(src, token.Pos(strings.Index(src, tt.id)+1), &Config{ 433 Olds: olds, 434 DefPrefix: "Def_", 435 // RefPrefix is not used. 436 RefPrefix: "Ref_", 437 }) 438 if doc != "" { 439 t.Errorf("Expected an empty doc for %s but got %q", tt.id, doc) 440 } 441 if query != tt.query { 442 t.Errorf("Expected %q for %s but got %q", tt.query, tt.id, query) 443 } 444 } 445 } 446 447 func TestInspectUnnamedStruct(t *testing.T) { 448 result := Convert(` 449 func Gen() struct{Val int} { 450 return struct{Val int}{123} 451 } 452 `, &Config{LgoPkgPath: "lgo/pkg0"}) 453 if result.Err != nil { 454 t.Error(result.Err) 455 return 456 } 457 olds := []types.Object{ 458 result.Pkg.Scope().Lookup("Gen"), 459 } 460 src := `Gen().Val` 461 doc, query := InspectIdent(src, token.Pos(strings.Index(src, "Val")+1), &Config{ 462 Olds: olds, 463 DefPrefix: "Def_", 464 // RefPrefix is not used. 465 RefPrefix: "Ref_", 466 }) 467 if doc != "" { 468 t.Errorf("Unexpected non-empty doc: %q", doc) 469 } 470 if query != "" { 471 t.Errorf("Unexpected non-empty query: %q", query) 472 } 473 }