| // Copyright 2016 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 syntax | |
| import ( | |
| "fmt" | |
| "io" | |
| "os" | |
| "strings" | |
| "testing" | |
| ) | |
| func TestPrint(t *testing.T) { | |
| if testing.Short() { | |
| t.Skip("skipping test in short mode") | |
| } | |
| ast, _ := ParseFile(*src_, func(err error) { t.Error(err) }, nil, 0) | |
| if ast != nil { | |
| Fprint(testOut(), ast, LineForm) | |
| fmt.Println() | |
| } | |
| } | |
| type shortBuffer struct { | |
| buf []byte | |
| } | |
| func (w *shortBuffer) Write(data []byte) (n int, err error) { | |
| w.buf = append(w.buf, data...) | |
| n = len(data) | |
| if len(w.buf) > 10 { | |
| err = io.ErrShortBuffer | |
| } | |
| return | |
| } | |
| func TestPrintError(t *testing.T) { | |
| const src = "package p; var x int" | |
| ast, err := Parse(nil, strings.NewReader(src), nil, nil, 0) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| var buf shortBuffer | |
| _, err = Fprint(&buf, ast, 0) | |
| if err == nil || err != io.ErrShortBuffer { | |
| t.Errorf("got err = %s, want %s", err, io.ErrShortBuffer) | |
| } | |
| } | |
| var stringTests = [][2]string{ | |
| dup("package p"), | |
| dup("package p; type _ int; type T1 = struct{}; type ( _ *struct{}; T2 = float32 )"), | |
| // generic type declarations (given type separated with blank from LHS) | |
| dup("package p; type _[T any] struct{}"), | |
| dup("package p; type _[A, B, C interface{m()}] struct{}"), | |
| dup("package p; type _[T any, A, B, C interface{m()}, X, Y, Z interface{~int}] struct{}"), | |
| dup("package p; type _[P *struct{}] struct{}"), | |
| dup("package p; type _[P *T,] struct{}"), | |
| dup("package p; type _[P *T, _ any] struct{}"), | |
| {"package p; type _[P (*T),] struct{}", "package p; type _[P *T,] struct{}"}, | |
| {"package p; type _[P (*T), _ any] struct{}", "package p; type _[P *T, _ any] struct{}"}, | |
| {"package p; type _[P (T),] struct{}", "package p; type _[P T] struct{}"}, | |
| {"package p; type _[P (T), _ any] struct{}", "package p; type _[P T, _ any] struct{}"}, | |
| {"package p; type _[P (*struct{})] struct{}", "package p; type _[P *struct{}] struct{}"}, | |
| {"package p; type _[P ([]int)] struct{}", "package p; type _[P []int] struct{}"}, | |
| {"package p; type _[P ([]int) | int] struct{}", "package p; type _[P []int | int] struct{}"}, | |
| // a type literal in an |-expression indicates a type parameter list (blank after type parameter list and type) | |
| dup("package p; type _[P *[]int] struct{}"), | |
| dup("package p; type _[P T | T] struct{}"), | |
| dup("package p; type _[P T | T | T | T] struct{}"), | |
| dup("package p; type _[P *T | T, Q T] struct{}"), | |
| dup("package p; type _[P *[]T | T] struct{}"), | |
| dup("package p; type _[P *T | T | T | T | ~T] struct{}"), | |
| dup("package p; type _[P *T | T | T | ~T | T] struct{}"), | |
| dup("package p; type _[P *T | T | struct{} | T] struct{}"), | |
| dup("package p; type _[P <-chan int] struct{}"), | |
| dup("package p; type _[P *T | struct{} | T] struct{}"), | |
| // a trailing comma always indicates a (possibly invalid) type parameter list (blank after type parameter list and type) | |
| dup("package p; type _[P *T,] struct{}"), | |
| dup("package p; type _[P *T | T,] struct{}"), | |
| dup("package p; type _[P *T | <-T | T,] struct{}"), | |
| // slice/array type declarations (no blank between array length and element type) | |
| dup("package p; type _ []byte"), | |
| dup("package p; type _ [n]byte"), | |
| dup("package p; type _ [P(T)]byte"), | |
| dup("package p; type _ [P((T))]byte"), | |
| dup("package p; type _ [P * *T]byte"), | |
| dup("package p; type _ [P * T]byte"), | |
| dup("package p; type _ [P(*T)]byte"), | |
| dup("package p; type _ [P(**T)]byte"), | |
| dup("package p; type _ [P * T - T]byte"), | |
| dup("package p; type _ [P * T - T]byte"), | |
| dup("package p; type _ [P * T | T]byte"), | |
| dup("package p; type _ [P * T | <-T | T]byte"), | |
| // generic function declarations | |
| dup("package p; func _[T any]()"), | |
| dup("package p; func _[A, B, C interface{m()}]()"), | |
| dup("package p; func _[T any, A, B, C interface{m()}, X, Y, Z interface{~int}]()"), | |
| // generic functions with elided interfaces in type constraints | |
| dup("package p; func _[P *T]() {}"), | |
| dup("package p; func _[P *T | T | T | T | ~T]() {}"), | |
| dup("package p; func _[P *T | T | struct{} | T]() {}"), | |
| dup("package p; func _[P ~int, Q int | string]() {}"), | |
| dup("package p; func _[P struct{f int}, Q *P]() {}"), | |
| // methods with generic receiver types | |
| dup("package p; func (R[T]) _()"), | |
| dup("package p; func (*R[A, B, C]) _()"), | |
| dup("package p; func (_ *R[A, B, C]) _()"), | |
| // channels | |
| dup("package p; type _ chan chan int"), | |
| dup("package p; type _ chan (<-chan int)"), | |
| dup("package p; type _ chan chan<- int"), | |
| dup("package p; type _ <-chan chan int"), | |
| dup("package p; type _ <-chan <-chan int"), | |
| dup("package p; type _ <-chan chan<- int"), | |
| dup("package p; type _ chan<- chan int"), | |
| dup("package p; type _ chan<- <-chan int"), | |
| dup("package p; type _ chan<- chan<- int"), | |
| // go.dev/issues/69206 | |
| dup("package p; type _[P C] int"), | |
| {"package p; type _[P (C),] int", "package p; type _[P C] int"}, | |
| {"package p; type _[P ((C)),] int", "package p; type _[P C] int"}, | |
| {"package p; type _[P, Q ((C))] int", "package p; type _[P, Q C] int"}, | |
| // go.dev/issues/81633 | |
| {"package p; import ()", "package p"}, | |
| {"package p; const ()", "package p"}, | |
| {"package p; type ()", "package p"}, | |
| {"package p; var ()", "package p"}, | |
| {"package p; func _() { const () }", "package p; func _() { }"}, | |
| {"package p; func _() { type () }", "package p; func _() { }"}, | |
| {"package p; func _() { var () }", "package p; func _() { }"}, | |
| } | |
| func TestPrintString(t *testing.T) { | |
| for _, test := range stringTests { | |
| ast, err := Parse(nil, strings.NewReader(test[0]), nil, nil, 0) | |
| if err != nil { | |
| t.Error(err) | |
| continue | |
| } | |
| if got := String(ast); got != test[1] { | |
| t.Errorf("%q: got %q", test[1], got) | |
| } | |
| } | |
| } | |
| func testOut() io.Writer { | |
| if testing.Verbose() { | |
| return os.Stdout | |
| } | |
| return io.Discard | |
| } | |
| func dup(s string) [2]string { return [2]string{s, s} } | |
| var exprTests = [][2]string{ | |
| // basic type literals | |
| dup("x"), | |
| dup("true"), | |
| dup("42"), | |
| dup("3.1415"), | |
| dup("2.71828i"), | |
| dup(`'a'`), | |
| dup(`"foo"`), | |
| dup("`bar`"), | |
| dup("any"), | |
| // func and composite literals | |
| dup("func() {}"), | |
| dup("[]int{}"), | |
| {"func(x int) complex128 { return 0 }", "func(x int) complex128 {…}"}, | |
| {"[]int{1, 2, 3}", "[]int{…}"}, | |
| // type expressions | |
| dup("[1 << 10]byte"), | |
| dup("[]int"), | |
| dup("*int"), | |
| dup("struct{x int}"), | |
| dup("func()"), | |
| dup("func(int, float32) string"), | |
| dup("interface{m()}"), | |
| dup("interface{m() string; n(x int)}"), | |
| dup("interface{~int}"), | |
| dup("interface{~int | ~float64 | ~string}"), | |
| dup("interface{~int; m()}"), | |
| dup("interface{~int | ~float64 | ~string; m() string; n(x int)}"), | |
| dup("map[string]int"), | |
| dup("chan E"), | |
| dup("<-chan E"), | |
| dup("chan<- E"), | |
| // new interfaces | |
| dup("interface{int}"), | |
| dup("interface{~int}"), | |
| // generic constraints | |
| dup("interface{~a | ~b | ~c; ~int | ~string; float64; m()}"), | |
| dup("interface{int | string}"), | |
| dup("interface{~int | ~string; float64; m()}"), | |
| dup("interface{~T[int, string] | string}"), | |
| // generic types | |
| dup("x[T]"), | |
| dup("x[N | A | S]"), | |
| dup("x[N, A]"), | |
| // non-type expressions | |
| dup("(x)"), | |
| dup("x.f"), | |
| dup("a[i]"), | |
| dup("s[:]"), | |
| dup("s[i:]"), | |
| dup("s[:j]"), | |
| dup("s[i:j]"), | |
| dup("s[:j:k]"), | |
| dup("s[i:j:k]"), | |
| dup("x.(T)"), | |
| dup("x.([10]int)"), | |
| dup("x.([...]int)"), | |
| dup("x.(struct{})"), | |
| dup("x.(struct{x int; y, z float32; E})"), | |
| dup("x.(func())"), | |
| dup("x.(func(x int))"), | |
| dup("x.(func() int)"), | |
| dup("x.(func(x, y int, z float32) (r int))"), | |
| dup("x.(func(a, b, c int))"), | |
| dup("x.(func(x ...T))"), | |
| dup("x.(interface{})"), | |
| dup("x.(interface{m(); n(x int); E})"), | |
| dup("x.(interface{m(); n(x int) T; E; F})"), | |
| dup("x.(map[K]V)"), | |
| dup("x.(chan E)"), | |
| dup("x.(<-chan E)"), | |
| dup("x.(chan<- chan int)"), | |
| dup("x.(chan<- <-chan int)"), | |
| dup("x.(<-chan chan int)"), | |
| dup("x.(chan (<-chan int))"), | |
| dup("f()"), | |
| dup("f(x)"), | |
| dup("int(x)"), | |
| dup("f(x, x + y)"), | |
| dup("f(s...)"), | |
| dup("f(a, s...)"), | |
| // generic functions | |
| dup("f[T]()"), | |
| dup("f[T](T)"), | |
| dup("f[T, T1]()"), | |
| dup("f[T, T1](T, T1)"), | |
| dup("*x"), | |
| dup("&x"), | |
| dup("x + y"), | |
| dup("x + y << (2 * s)"), | |
| } | |
| func TestShortString(t *testing.T) { | |
| for _, test := range exprTests { | |
| src := "package p; var _ = " + test[0] | |
| ast, err := Parse(nil, strings.NewReader(src), nil, nil, 0) | |
| if err != nil { | |
| t.Errorf("%s: %s", test[0], err) | |
| continue | |
| } | |
| x := ast.DeclList[0].(*VarDecl).Values | |
| if got := String(x); got != test[1] { | |
| t.Errorf("%s: got %s, want %s", test[0], got, test[1]) | |
| } | |
| } | |
| } |