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  }