github.com/rgonomic/rgo@v0.2.2-0.20220708095818-4747f0905d6e/internal/pkg/types_test.go (about) 1 // Copyright ©2019 The rgonomic 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 5 package pkg 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "go/ast" 11 "os" 12 "path/filepath" 13 "reflect" 14 "sort" 15 "strings" 16 "testing" 17 18 "golang.org/x/tools/go/packages" 19 ) 20 21 func TestAnalyse(t *testing.T) { 22 paths, err := filepath.Glob("./testdata/*") 23 if err != nil { 24 t.Fatalf("unexpected error: %v", err) 25 } 26 for _, path := range paths { 27 fi, err := os.Stat(path) 28 if err != nil { 29 t.Errorf("failed to stat %q: %v", path, err) 30 continue 31 } 32 if !fi.IsDir() { 33 continue 34 } 35 36 info, err := Analyse(filepath.Join("github.com/rgonomic/rgo/internal/pkg", path), "", false) 37 if err != nil { 38 t.Errorf("unexpected error during analysis of %q: %v", path, err) 39 continue 40 } 41 if info.Pkg().Name() != filepath.Base(path) { 42 t.Errorf("unexpected package name: got:%q want:%q", info.Pkg().Name(), filepath.Base(path)) 43 } 44 for _, fn := range info.Funcs { 45 if !fn.Exported() { 46 t.Errorf("unexpected unexported function: %s", fn) 47 } 48 } 49 50 got := make(map[string][]string) 51 for k, v := range info.Unpackers { 52 got["in"] = append(got["in"], k) 53 if k != v.String() { 54 t.Errorf("unexpected type for unpacker key: %s != %s", k, v) 55 } 56 } 57 for k, v := range info.Packers { 58 got["out"] = append(got["out"], k) 59 if k != v.String() { 60 t.Errorf("unexpected type for packer key: %s != %s", k, v) 61 } 62 } 63 for k := range got { 64 sort.Strings(got[k]) 65 } 66 67 want, err := typesFor(path) 68 if err != nil { 69 t.Error(err) 70 } 71 72 if !reflect.DeepEqual(got, want) { 73 t.Errorf("unexpected types in %q:\ngot: %v\nwant:%v", path, got, want) 74 } 75 } 76 } 77 78 func typesFor(path string) (map[string][]string, error) { 79 cfg := &packages.Config{Mode: packages.NeedSyntax} 80 pkgs, err := packages.Load(cfg, "pattern=./"+path) 81 if err != nil { 82 return nil, fmt.Errorf("unexpected error loading %q: %w", path, err) 83 } 84 if len(pkgs) != 1 { 85 return nil, fmt.Errorf("unexpected number of packages for %q: got:%d want:1", path, len(pkgs)) 86 } 87 88 want := make(map[string][]string) 89 for _, f := range pkgs[0].Syntax { 90 for _, decl := range f.Decls { 91 fd, ok := decl.(*ast.FuncDecl) 92 if !ok || fd.Doc == nil { 93 continue 94 } 95 96 var fn map[string][]string 97 err := json.Unmarshal([]byte(strings.TrimPrefix(fd.Doc.List[0].Text, "//")), &fn) 98 if err != nil { 99 return nil, fmt.Errorf("failed to parse parameter types: %w", err) 100 } 101 for k, v := range fn { 102 want[k] = append(want[k], v...) 103 } 104 } 105 } 106 for k := range want { 107 t := want[k] 108 sort.Strings(t) 109 i := 0 110 for _, v := range t { 111 if v != t[i] { 112 i++ 113 t[i] = v 114 } 115 } 116 want[k] = t[:i+1] 117 } 118 119 return want, nil 120 }