package xsql import ( "errors" "fmt" "github.com/emqx/kuiper/common" "reflect" "strings" "testing" ) func TestComparison(t *testing.T) { testTime, _ := common.InterfaceToTime(1541152488442, "") data := []struct { m Message r []interface{} }{ { m: map[string]interface{}{ "a": float64(32), "b": float64(72), }, r: []interface{}{ false, true, errors.New("invalid operation float64 = string"), false, true, false, true, }, }, { m: map[string]interface{}{ "a": int64(32), "b": int64(72), }, r: []interface{}{ false, true, errors.New("invalid operation int64 = string"), false, true, false, true, }, }, { m: map[string]interface{}{ "a": "32", "b": "72", }, r: []interface{}{ errors.New("invalid operation string > int64"), errors.New("invalid operation string <= int64"), false, false, true, false, true, }, }, { m: map[string]interface{}{ "a": []interface{}{32, 72}, "b": []interface{}{32, 72}, }, r: []interface{}{ errors.New("> is an invalid operation for []interface {}"), errors.New("<= is an invalid operation for []interface {}"), errors.New("= is an invalid operation for []interface {}"), errors.New(">= is an invalid operation for []interface {}"), errors.New("< is an invalid operation for []interface {}"), errors.New("= is an invalid operation for []interface {}"), errors.New("!= is an invalid operation for []interface {}"), }, }, { m: map[string]interface{}{ "a": map[string]interface{}{"c": 5}, "b": map[string]interface{}{"d": 5}, }, r: []interface{}{ errors.New("> is an invalid operation for map[string]interface {}"), errors.New("<= is an invalid operation for map[string]interface {}"), errors.New("= is an invalid operation for map[string]interface {}"), errors.New(">= is an invalid operation for map[string]interface {}"), errors.New("< is an invalid operation for map[string]interface {}"), errors.New("= is an invalid operation for map[string]interface {}"), errors.New("!= is an invalid operation for map[string]interface {}"), }, }, { m: map[string]interface{}{ "a": float64(55), "b": int64(55), }, r: []interface{}{ false, false, errors.New("invalid operation float64 = string"), true, false, true, false, }, }, { m: map[string]interface{}{ "a": testTime, "b": int64(1541152388442), }, r: []interface{}{ true, false, errors.New("invalid operation time.Time = string"), true, false, false, true, }, }, { m: map[string]interface{}{ "a": testTime, "b": "2020-02-26T02:37:21.822Z", }, r: []interface{}{ true, false, errors.New("invalid operation time.Time = string"), false, true, false, true, }, }, { m: map[string]interface{}{ "a": int64(1541152388442), "b": testTime, }, r: []interface{}{ true, false, errors.New("invalid operation int64 = string"), errors.New("invalid operation int64 >= time.Time"), errors.New("invalid operation int64 < time.Time"), errors.New("invalid operation int64 = time.Time"), errors.New("invalid operation int64 != time.Time"), }, }, { m: map[string]interface{}{ "a": "2020-02-26T02:37:21.822Z", "b": testTime, }, r: []interface{}{ errors.New("invalid operation string > int64"), errors.New("invalid operation string <= int64"), false, errors.New("invalid operation string >= time.Time"), errors.New("invalid operation string < time.Time"), errors.New("invalid operation string = time.Time"), errors.New("invalid operation string != time.Time"), }, }, { m: map[string]interface{}{ "c": "nothing", }, r: []interface{}{ false, false, false, true, false, true, false, }, }, { m: map[string]interface{}{ "a": 12, "c": "nothing", }, r: []interface{}{ false, true, errors.New("invalid operation int64 = string"), false, false, false, true, }, }, } sqls := []string{ "select * from src where a > 72", "select * from src where a <= 32", "select * from src where a = \"string literal\"", "select * from src where a >= b", "select * from src where a < b", "select * from src where a = b", "select * from src where a != b", } var conditions []Expr for _, sql := range sqls { stmt, _ := NewParser(strings.NewReader(sql)).Parse() conditions = append(conditions, stmt.Condition) } fmt.Printf("The test bucket size is %d.\n\n", len(data)*len(sqls)) for i, tt := range data { for j, c := range conditions { tuple := &Tuple{Emitter: "src", Message: tt.m, Timestamp: common.GetNowInMilli(), Metadata: nil} ve := &ValuerEval{Valuer: MultiValuer(tuple, &FunctionValuer{})} result := ve.Eval(c) if !reflect.DeepEqual(tt.r[j], result) { t.Errorf("%d-%d. \nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, j, tt.r[j], result) } } } } func TestCalculation(t *testing.T) { data := []struct { m Message r []interface{} }{ { m: map[string]interface{}{ "a": float64(32), "b": float64(72), }, r: []interface{}{ float64(104), float64(96), float64(0.4444444444444444), float64(32), }, }, { m: map[string]interface{}{ "a": int64(32), "b": int64(72), }, r: []interface{}{ int64(104), int64(96), int64(0), int64(32), }, }, { m: map[string]interface{}{ "a": "32", "b": "72", }, r: []interface{}{ errors.New("invalid operation string + string"), errors.New("invalid operation string * int64"), errors.New("invalid operation string / string"), errors.New("invalid operation string % string"), }, }, { m: map[string]interface{}{ "a": float64(55), "b": int64(55), }, r: []interface{}{ float64(110), float64(165), float64(1), float64(0), }, }, { m: map[string]interface{}{ "a": int64(55), "b": float64(0), }, r: []interface{}{ float64(55), int64(165), errors.New("divided by zero"), errors.New("divided by zero"), }, }, { m: map[string]interface{}{ "c": "nothing", }, r: []interface{}{ nil, nil, nil, nil, }, }, { m: map[string]interface{}{ "a": 12, "c": "nothing", }, r: []interface{}{ nil, int64(36), nil, nil, }, }, } sqls := []string{ "select a + b as t from src", "select a * 3 as t from src", "select a / b as t from src", "select a % b as t from src", } var projects []Expr for _, sql := range sqls { stmt, _ := NewParser(strings.NewReader(sql)).Parse() projects = append(projects, stmt.Fields[0].Expr) } fmt.Printf("The test bucket size is %d.\n\n", len(data)*len(sqls)) for i, tt := range data { for j, c := range projects { tuple := &Tuple{Emitter: "src", Message: tt.m, Timestamp: common.GetNowInMilli(), Metadata: nil} ve := &ValuerEval{Valuer: MultiValuer(tuple, &FunctionValuer{})} result := ve.Eval(c) if !reflect.DeepEqual(tt.r[j], result) { t.Errorf("%d-%d. \nstmt mismatch:\n\nexp=%#v\n\ngot=%#v\n\n", i, j, tt.r[j], result) } } } }