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 }