github.com/mattn/anko@v0.1.10/vm/main_test.go (about)

     1  package vm
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/mattn/anko/env"
    10  	"github.com/mattn/anko/parser"
    11  )
    12  
    13  type (
    14  	testStruct1 struct {
    15  		aInterface interface{}
    16  		aBool      bool
    17  		aInt32     int32
    18  		aInt64     int64
    19  		aFloat32   float32
    20  		aFloat64   float32
    21  		aString    string
    22  		aFunc      func()
    23  
    24  		aPtrInterface      *interface{}
    25  		aPtrBool           *bool
    26  		aPtrInt32          *int32
    27  		aPtrInt64          *int64
    28  		aPtrFloat32        *float32
    29  		aPtrFloat64        *float32
    30  		aPtrString         *string
    31  		aPtrSliceInterface *[]interface{}
    32  		aPtrSliceBool      *[]bool
    33  		aPtrSliceInt32     *[]int32
    34  		aPtrSliceInt64     *[]int64
    35  		aPtrSliceFloat32   *[]float32
    36  		aPtrSliceFloat64   *[]float32
    37  		aPtrSliceString    *[]string
    38  
    39  		aSliceInterface    []interface{}
    40  		aSliceBool         []bool
    41  		aSliceInt32        []int32
    42  		aSliceInt64        []int64
    43  		aSliceFloat32      []float32
    44  		aSliceFloat64      []float32
    45  		aSliceString       []string
    46  		aSlicePtrInterface []*interface{}
    47  		aSlicePtrBool      []*bool
    48  		aSlicePtrInt32     []*int32
    49  		aSlicePtrInt64     []*int64
    50  		aSlicePtrFloat32   []*float32
    51  		aSlicePtrFloat64   []*float32
    52  		aSlicePtrString    []*string
    53  
    54  		aMapInterface    map[string]interface{}
    55  		aMapBool         map[string]bool
    56  		aMapInt32        map[string]int32
    57  		aMapInt64        map[string]int64
    58  		aMapFloat32      map[string]float32
    59  		aMapFloat64      map[string]float32
    60  		aMapString       map[string]string
    61  		aMapPtrInterface map[string]*interface{}
    62  		aMapPtrBool      map[string]*bool
    63  		aMapPtrInt32     map[string]*int32
    64  		aMapPtrInt64     map[string]*int64
    65  		aMapPtrFloat32   map[string]*float32
    66  		aMapPtrFloat64   map[string]*float32
    67  		aMapPtrString    map[string]*string
    68  
    69  		aChanInterface    chan interface{}
    70  		aChanBool         chan bool
    71  		aChanInt32        chan int32
    72  		aChanInt64        chan int64
    73  		aChanFloat32      chan float32
    74  		aChanFloat64      chan float32
    75  		aChanString       chan string
    76  		aChanPtrInterface chan *interface{}
    77  		aChanPtrBool      chan *bool
    78  		aChanPtrInt32     chan *int32
    79  		aChanPtrInt64     chan *int64
    80  		aChanPtrFloat32   chan *float32
    81  		aChanPtrFloat64   chan *float32
    82  		aChanPtrString    chan *string
    83  
    84  		aPtrStruct *testStruct1
    85  	}
    86  	testStruct2 struct {
    87  		aStruct testStruct1
    88  	}
    89  )
    90  
    91  var (
    92  	testVarValue    = reflect.Value{}
    93  	testVarValueP   = &reflect.Value{}
    94  	testVarBool     = true
    95  	testVarBoolP    = &testVarBool
    96  	testVarInt32    = int32(1)
    97  	testVarInt32P   = &testVarInt32
    98  	testVarInt64    = int64(1)
    99  	testVarInt64P   = &testVarInt64
   100  	testVarFloat32  = float32(1)
   101  	testVarFloat32P = &testVarFloat32
   102  	testVarFloat64  = float64(1)
   103  	testVarFloat64P = &testVarFloat64
   104  	testVarString   = "a"
   105  	testVarStringP  = &testVarString
   106  	testVarFunc     = func() int64 { return 1 }
   107  	testVarFuncP    = &testVarFunc
   108  
   109  	testVarValueBool    = reflect.ValueOf(true)
   110  	testVarValueInt32   = reflect.ValueOf(int32(1))
   111  	testVarValueInt64   = reflect.ValueOf(int64(1))
   112  	testVarValueFloat32 = reflect.ValueOf(float32(1.1))
   113  	testVarValueFloat64 = reflect.ValueOf(float64(1.1))
   114  	testVarValueString  = reflect.ValueOf("a")
   115  
   116  	testSliceEmpty []interface{}
   117  	testSlice      = []interface{}{nil, true, int64(1), float64(1.1), "a"}
   118  	testMapEmpty   map[interface{}]interface{}
   119  	testMap        = map[interface{}]interface{}{"a": nil, "b": true, "c": int64(1), "d": float64(1.1), "e": "e"}
   120  )
   121  
   122  // Test is utility struct to make tests easy.
   123  type Test struct {
   124  	Script         string
   125  	ParseError     error
   126  	ParseErrorFunc *func(*testing.T, error)
   127  	EnvSetupFunc   *func(*testing.T, *env.Env)
   128  	Types          map[string]interface{}
   129  	Input          map[string]interface{}
   130  	RunError       error
   131  	RunErrorFunc   *func(*testing.T, error)
   132  	RunOutput      interface{}
   133  	Output         map[string]interface{}
   134  }
   135  
   136  // TestOptions is utility struct to pass options to the test.
   137  type TestOptions struct {
   138  	EnvSetupFunc *func(*testing.T, *env.Env)
   139  	Timeout      time.Duration
   140  }
   141  
   142  // runTests runs VM tests
   143  func runTests(t *testing.T, tests []Test, testOptions *TestOptions, options *Options) {
   144  	for _, test := range tests {
   145  		runTest(t, test, testOptions, options)
   146  	}
   147  }
   148  
   149  // runTest runs VM test
   150  func runTest(t *testing.T, test Test, testOptions *TestOptions, options *Options) {
   151  	timeout := 60 * time.Second
   152  
   153  	// parser.EnableErrorVerbose()
   154  	// parser.EnableDebug(8)
   155  
   156  	stmt, err := parser.ParseSrc(test.Script)
   157  	if test.ParseErrorFunc != nil {
   158  		(*test.ParseErrorFunc)(t, err)
   159  	} else if err != nil && test.ParseError != nil {
   160  		if err.Error() != test.ParseError.Error() {
   161  			t.Errorf("ParseSrc error - received: %v - expected: %v - script: %v", err, test.ParseError, test.Script)
   162  			return
   163  		}
   164  	} else if err != test.ParseError {
   165  		t.Errorf("ParseSrc error - received: %v - expected: %v - script: %v", err, test.ParseError, test.Script)
   166  		return
   167  	}
   168  	// Note: Still want to run the code even after a parse error to see what happens
   169  
   170  	envTest := env.NewEnv()
   171  	if testOptions != nil {
   172  		if testOptions.EnvSetupFunc != nil {
   173  			(*testOptions.EnvSetupFunc)(t, envTest)
   174  		}
   175  		if testOptions.Timeout != 0 {
   176  			timeout = testOptions.Timeout
   177  		}
   178  	}
   179  	if test.EnvSetupFunc != nil {
   180  		(*test.EnvSetupFunc)(t, envTest)
   181  	}
   182  
   183  	for typeName, typeValue := range test.Types {
   184  		err = envTest.DefineType(typeName, typeValue)
   185  		if err != nil {
   186  			t.Errorf("DefineType error: %v - typeName: %v - script: %v", err, typeName, test.Script)
   187  			return
   188  		}
   189  	}
   190  
   191  	for inputName, inputValue := range test.Input {
   192  		err = envTest.Define(inputName, inputValue)
   193  		if err != nil {
   194  			t.Errorf("Define error: %v - inputName: %v - script: %v", err, inputName, test.Script)
   195  			return
   196  		}
   197  	}
   198  
   199  	var value interface{}
   200  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
   201  	value, err = RunContext(ctx, envTest, options, stmt)
   202  	cancel()
   203  	if test.RunErrorFunc != nil {
   204  		(*test.RunErrorFunc)(t, err)
   205  	} else if err != nil && test.RunError != nil {
   206  		if err.Error() != test.RunError.Error() {
   207  			t.Errorf("Run error - received: %v - expected: %v - script: %v", err, test.RunError, test.Script)
   208  			return
   209  		}
   210  	} else if err != test.RunError {
   211  		t.Errorf("Run error - received: %v - expected: %v - script: %v", err, test.RunError, test.Script)
   212  		return
   213  	}
   214  
   215  	if !valueEqual(value, test.RunOutput) {
   216  		t.Errorf("Run output - received: %#v - expected: %#v - script: %v", value, test.RunOutput, test.Script)
   217  		t.Errorf("received type: %T - expected: %T", value, test.RunOutput)
   218  		return
   219  	}
   220  
   221  	for outputName, outputValue := range test.Output {
   222  		value, err = envTest.Get(outputName)
   223  		if err != nil {
   224  			t.Errorf("Get error: %v - outputName: %v - script: %v", err, outputName, test.Script)
   225  			return
   226  		}
   227  
   228  		if !valueEqual(value, outputValue) {
   229  			t.Errorf("outputName %v - received: %#v - expected: %#v - script: %v", outputName, value, outputValue, test.Script)
   230  			t.Errorf("received type: %T - expected: %T", value, outputValue)
   231  			continue
   232  		}
   233  	}
   234  }
   235  
   236  // valueEqual return true if v1 and v2 is same value. If passed function, does
   237  // extra checks otherwise just doing reflect.DeepEqual
   238  func valueEqual(v1 interface{}, v2 interface{}) bool {
   239  	v1RV := reflect.ValueOf(v1)
   240  	switch v1RV.Kind() {
   241  	case reflect.Func:
   242  		// This is best effort to check if functions match, but it could be wrong
   243  		v2RV := reflect.ValueOf(v2)
   244  		if !v1RV.IsValid() || !v2RV.IsValid() {
   245  			if v1RV.IsValid() != !v2RV.IsValid() {
   246  				return false
   247  			}
   248  			return true
   249  		} else if v1RV.Kind() != v2RV.Kind() {
   250  			return false
   251  		} else if v1RV.Type() != v2RV.Type() {
   252  			return false
   253  		} else if v1RV.Pointer() != v2RV.Pointer() {
   254  			// From reflect: If v's Kind is Func, the returned pointer is an underlying code pointer, but not necessarily enough to identify a single function uniquely.
   255  			return false
   256  		}
   257  		return true
   258  	}
   259  	switch value1 := v1.(type) {
   260  	case error:
   261  		switch value2 := v2.(type) {
   262  		case error:
   263  			return value1.Error() == value2.Error()
   264  		}
   265  	}
   266  
   267  	return reflect.DeepEqual(v1, v2)
   268  }