...

Source file src/github.com/PaesslerAG/gval/operator_test.go

Documentation: github.com/PaesslerAG/gval

     1  package gval
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"reflect"
     7  	"testing"
     8  )
     9  
    10  func Test_Infix(t *testing.T) {
    11  	type subTest struct {
    12  		name    string
    13  		a       interface{}
    14  		b       interface{}
    15  		wantRet interface{}
    16  	}
    17  	tests := []struct {
    18  		name string
    19  		infix
    20  		subTests []subTest
    21  	}{
    22  		{
    23  			"number operator",
    24  			infix{
    25  				number: func(a, b float64) (interface{}, error) { return a * b, nil },
    26  			},
    27  			[]subTest{
    28  				{"float64 arguments", 7., 3., 21.},
    29  				{"int arguments", 7, 3, 21.},
    30  				{"string arguments", "7", "3.", 21.},
    31  			},
    32  		},
    33  		{
    34  			"number and string operator",
    35  			infix{
    36  				number: func(a, b float64) (interface{}, error) { return a + b, nil },
    37  				text:   func(a, b string) (interface{}, error) { return fmt.Sprintf("%v%v", a, b), nil },
    38  			},
    39  
    40  			[]subTest{
    41  				{"float64 arguments", 7., 3., 10.},
    42  				{"int arguments", 7, 3, 10.},
    43  				{"number string arguments", "7", "3.", "73."},
    44  				{"string arguments", "hello ", "world", "hello world"},
    45  			},
    46  		},
    47  		{
    48  			"bool operator",
    49  			infix{
    50  				shortCircuit: func(a interface{}) (interface{}, bool) { return false, a == false },
    51  				boolean:      func(a, b bool) (interface{}, error) { return a && b, nil },
    52  			},
    53  
    54  			[]subTest{
    55  				{"bool arguments", false, true, false},
    56  				{"number arguments", 0, true, false},
    57  				{"lower string arguments", "false", "true", false},
    58  				{"upper string arguments", "TRUE", "FALSE", false},
    59  				{"shortCircuit", false, "not a boolean", false},
    60  			},
    61  		},
    62  		{
    63  			"bool, number, text and interface operator",
    64  			infix{
    65  				number:    func(a, b float64) (interface{}, error) { return a == b, nil },
    66  				boolean:   func(a, b bool) (interface{}, error) { return a == b, nil },
    67  				text:      func(a, b string) (interface{}, error) { return a == b, nil },
    68  				arbitrary: func(a, b interface{}) (interface{}, error) { return a == b, nil },
    69  			},
    70  
    71  			[]subTest{
    72  				{"number string and int arguments", "7", 7, true},
    73  				{"bool string and bool arguments", "true", true, true},
    74  				{"string arguments", "hello", "hello", true},
    75  				{"upper string arguments", "TRUE", "FALSE", false},
    76  			},
    77  		},
    78  	}
    79  	for _, tt := range tests {
    80  		t.Run(tt.name, func(t *testing.T) {
    81  			tt.infix.initiate("<" + tt.name + ">")
    82  			builder := tt.infix.builder
    83  			for _, tt := range tt.subTests {
    84  				t.Run(tt.name, func(t *testing.T) {
    85  					eval, err := builder(constant(tt.a), constant(tt.b))
    86  					if err != nil {
    87  						t.Fatal(err)
    88  					}
    89  
    90  					got, err := eval(context.Background(), nil)
    91  					if err != nil {
    92  						t.Fatal(err)
    93  					}
    94  
    95  					if !reflect.DeepEqual(got, tt.wantRet) {
    96  						t.Fatalf("binaryOperator() eval() = %v, want %v", got, tt.wantRet)
    97  					}
    98  				})
    99  			}
   100  		})
   101  	}
   102  }
   103  
   104  func Test_stageStack_push(t *testing.T) {
   105  	p := (*Parser)(nil)
   106  	tests := []struct {
   107  		name   string
   108  		pres   []operatorPrecedence
   109  		expect string
   110  	}{
   111  		{
   112  			"flat",
   113  			[]operatorPrecedence{1, 1, 1, 1},
   114  			"((((AB)C)D)E)",
   115  		},
   116  		{
   117  			"asc",
   118  			[]operatorPrecedence{1, 2, 3, 4},
   119  			"(A(B(C(DE))))",
   120  		},
   121  		{
   122  			"desc",
   123  			[]operatorPrecedence{4, 3, 2, 1},
   124  			"((((AB)C)D)E)",
   125  		},
   126  		{
   127  			"mixed",
   128  			[]operatorPrecedence{1, 2, 1, 1},
   129  			"(((A(BC))D)E)",
   130  		},
   131  	}
   132  	for _, tt := range tests {
   133  		t.Run(tt.name, func(t *testing.T) {
   134  			X := int('A')
   135  
   136  			op := func(a, b Evaluable) (Evaluable, error) {
   137  				return func(c context.Context, o interface{}) (interface{}, error) {
   138  					aa, _ := a.EvalString(c, nil)
   139  					bb, _ := b.EvalString(c, nil)
   140  					s := "(" + aa + bb + ")"
   141  					return s, nil
   142  				}, nil
   143  			}
   144  			stack := stageStack{}
   145  			for _, pre := range tt.pres {
   146  				if err := stack.push(stage{p.Const(string(rune(X))), op, pre}); err != nil {
   147  					t.Fatal(err)
   148  				}
   149  				X++
   150  			}
   151  
   152  			if err := stack.push(stage{p.Const(string(rune(X))), nil, 0}); err != nil {
   153  				t.Fatal(err)
   154  			}
   155  
   156  			if len(stack) != 1 {
   157  				t.Fatalf("stack must hold exactly one element")
   158  			}
   159  
   160  			got, _ := stack[0].EvalString(context.Background(), nil)
   161  			if got != tt.expect {
   162  				t.Fatalf("got %s but expected %s", got, tt.expect)
   163  			}
   164  		})
   165  	}
   166  }
   167  

View as plain text