127 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// stm: #unit
 | 
						|
package api
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"os"
 | 
						|
	"os/exec"
 | 
						|
	"path/filepath"
 | 
						|
	"reflect"
 | 
						|
	"runtime"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
)
 | 
						|
 | 
						|
func goCmd() string {
 | 
						|
	var exeSuffix string
 | 
						|
	if runtime.GOOS == "windows" {
 | 
						|
		exeSuffix = ".exe"
 | 
						|
	}
 | 
						|
	path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
 | 
						|
	if _, err := os.Stat(path); err == nil {
 | 
						|
		return path
 | 
						|
	}
 | 
						|
	return "go"
 | 
						|
}
 | 
						|
 | 
						|
func TestDoesntDependOnFFI(t *testing.T) {
 | 
						|
	//stm: @OTHER_IMPLEMENTATION_FFI_DEPENDENCE_001
 | 
						|
	deps, err := exec.Command(goCmd(), "list", "-deps", "github.com/filecoin-project/lotus/api").Output()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	for _, pkg := range strings.Fields(string(deps)) {
 | 
						|
		if pkg == "github.com/filecoin-project/filecoin-ffi" {
 | 
						|
			t.Fatal("api depends on filecoin-ffi")
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestDoesntDependOnBuild(t *testing.T) {
 | 
						|
	//stm: @OTHER_IMPLEMENTATION_FFI_DEPENDENCE_002
 | 
						|
	deps, err := exec.Command(goCmd(), "list", "-deps", "github.com/filecoin-project/lotus/api").Output()
 | 
						|
	if err != nil {
 | 
						|
		t.Fatal(err)
 | 
						|
	}
 | 
						|
	for _, pkg := range strings.Fields(string(deps)) {
 | 
						|
		if pkg == "github.com/filecoin-project/build" {
 | 
						|
			t.Fatal("api depends on filecoin-ffi")
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestReturnTypes(t *testing.T) {
 | 
						|
	//stm: @OTHER_IMPLEMENTATION_001
 | 
						|
	errType := reflect.TypeOf(new(error)).Elem()
 | 
						|
	bareIface := reflect.TypeOf(new(interface{})).Elem()
 | 
						|
	jmarsh := reflect.TypeOf(new(json.Marshaler)).Elem()
 | 
						|
 | 
						|
	tst := func(api interface{}) func(t *testing.T) {
 | 
						|
		return func(t *testing.T) {
 | 
						|
			ra := reflect.TypeOf(api).Elem()
 | 
						|
			for i := 0; i < ra.NumMethod(); i++ {
 | 
						|
				m := ra.Method(i)
 | 
						|
				switch m.Type.NumOut() {
 | 
						|
				case 1: // if 1 return value, it must be an error
 | 
						|
					require.Equal(t, errType, m.Type.Out(0), m.Name)
 | 
						|
 | 
						|
				case 2: // if 2 return values, first cant be an interface/function, second must be an error
 | 
						|
					seen := map[reflect.Type]struct{}{}
 | 
						|
					todo := []reflect.Type{m.Type.Out(0)}
 | 
						|
					for len(todo) > 0 {
 | 
						|
						typ := todo[len(todo)-1]
 | 
						|
						todo = todo[:len(todo)-1]
 | 
						|
 | 
						|
						if _, ok := seen[typ]; ok {
 | 
						|
							continue
 | 
						|
						}
 | 
						|
						seen[typ] = struct{}{}
 | 
						|
 | 
						|
						if typ.Kind() == reflect.Interface && typ != bareIface && !typ.Implements(jmarsh) {
 | 
						|
							t.Error("methods can't return interfaces or struct types not implementing json.Marshaller", m.Name)
 | 
						|
						}
 | 
						|
 | 
						|
						switch typ.Kind() {
 | 
						|
						case reflect.Ptr:
 | 
						|
							fallthrough
 | 
						|
						case reflect.Array:
 | 
						|
							fallthrough
 | 
						|
						case reflect.Slice:
 | 
						|
							fallthrough
 | 
						|
						case reflect.Chan:
 | 
						|
							todo = append(todo, typ.Elem())
 | 
						|
						case reflect.Map:
 | 
						|
							todo = append(todo, typ.Elem())
 | 
						|
							todo = append(todo, typ.Key())
 | 
						|
						case reflect.Struct:
 | 
						|
							for i := 0; i < typ.NumField(); i++ {
 | 
						|
								todo = append(todo, typ.Field(i).Type)
 | 
						|
							}
 | 
						|
						}
 | 
						|
					}
 | 
						|
 | 
						|
					require.NotEqual(t, reflect.Func.String(), m.Type.Out(0).Kind().String(), m.Name)
 | 
						|
					require.Equal(t, errType, m.Type.Out(1), m.Name)
 | 
						|
 | 
						|
				default:
 | 
						|
					t.Error("methods can only have 1 or 2 return values", m.Name)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	t.Run("common", tst(new(Common)))
 | 
						|
	t.Run("full", tst(new(FullNode)))
 | 
						|
	t.Run("miner", tst(new(StorageMiner)))
 | 
						|
	t.Run("worker", tst(new(Worker)))
 | 
						|
}
 | 
						|
 | 
						|
func TestPermTags(t *testing.T) {
 | 
						|
	//stm: @OTHER_IMPLEMENTATION_PERM_TAGS_001
 | 
						|
	_ = PermissionedFullAPI(&FullNodeStruct{})
 | 
						|
	_ = PermissionedStorMinerAPI(&StorageMinerStruct{})
 | 
						|
	_ = PermissionedWorkerAPI(&WorkerStruct{})
 | 
						|
}
 |