github.com/bytedance/go-tagexpr@v2.7.5-0.20210114074101-de5b8743ad85+incompatible/spec_test.go (about) 1 // Copyright 2019 Bytedance Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tagexpr 16 17 import ( 18 "fmt" 19 "reflect" 20 "testing" 21 ) 22 23 func TestReadPairedSymbol(t *testing.T) { 24 var cases = []struct { 25 left, right rune 26 expr, val, lastExprNode string 27 }{ 28 {left: '\'', right: '\'', expr: "'true '+'a'", val: "true ", lastExprNode: "+'a'"}, 29 {left: '(', right: ')', expr: "((0+1)/(2-1)*9)%2", val: "(0+1)/(2-1)*9", lastExprNode: "%2"}, 30 {left: '(', right: ')', expr: `(\)\(\))`, val: `)()`}, 31 {left: '\'', right: '\'', expr: `'\\'`, val: `\\`}, 32 {left: '\'', right: '\'', expr: `'\'\''`, val: `''`}, 33 } 34 for _, c := range cases { 35 t.Log(c.expr) 36 expr := c.expr 37 got := readPairedSymbol(&expr, c.left, c.right) 38 if got == nil { 39 t.Fatalf("expr: %q, got: %v, %q, want: %q, %q", c.expr, got, expr, c.val, c.lastExprNode) 40 } else if *got != c.val || expr != c.lastExprNode { 41 t.Fatalf("expr: %q, got: %q, %q, want: %q, %q", c.expr, *got, expr, c.val, c.lastExprNode) 42 } 43 } 44 } 45 46 func TestReadBoolExprNode(t *testing.T) { 47 var cases = []struct { 48 expr string 49 val bool 50 lastExprNode string 51 }{ 52 {expr: "false", val: false, lastExprNode: ""}, 53 {expr: "true", val: true, lastExprNode: ""}, 54 {expr: "true ", val: true, lastExprNode: " "}, 55 {expr: "!true&", val: false, lastExprNode: "&"}, 56 {expr: "!false|", val: true, lastExprNode: "|"}, 57 {expr: "!!!!false =", val: !!!!false, lastExprNode: " ="}, 58 } 59 for _, c := range cases { 60 t.Log(c.expr) 61 expr := c.expr 62 e := readBoolExprNode(&expr) 63 got := e.Run("", nil).(bool) 64 if got != c.val || expr != c.lastExprNode { 65 t.Fatalf("expr: %s, got: %v, %s, want: %v, %s", c.expr, got, expr, c.val, c.lastExprNode) 66 } 67 } 68 } 69 70 func TestReadDigitalExprNode(t *testing.T) { 71 var cases = []struct { 72 expr string 73 val float64 74 lastExprNode string 75 }{ 76 {expr: "0.1 +1", val: 0.1, lastExprNode: " +1"}, 77 {expr: "-1\\1", val: -1, lastExprNode: "\\1"}, 78 {expr: "1a", val: 0, lastExprNode: ""}, 79 {expr: "1", val: 1, lastExprNode: ""}, 80 {expr: "1.1", val: 1.1, lastExprNode: ""}, 81 {expr: "1.1/", val: 1.1, lastExprNode: "/"}, 82 } 83 for _, c := range cases { 84 expr := c.expr 85 e := readDigitalExprNode(&expr) 86 if c.expr == "1a" { 87 if e != nil { 88 t.Fatalf("expr: %s, got:%v, want:%v", c.expr, e.Run("", nil), nil) 89 } 90 continue 91 } 92 got := e.Run("", nil).(float64) 93 if got != c.val || expr != c.lastExprNode { 94 t.Fatalf("expr: %s, got: %f, %s, want: %f, %s", c.expr, got, expr, c.val, c.lastExprNode) 95 } 96 } 97 } 98 99 func TestFindSelector(t *testing.T) { 100 var cases = []struct { 101 expr string 102 field string 103 name string 104 subSelector []string 105 boolOpposite bool 106 floatOpposite bool 107 found bool 108 last string 109 }{ 110 {expr: "$", name: "$", found: true}, 111 {expr: "!!$", name: "$", found: true}, 112 {expr: "!$", name: "$", boolOpposite: true, found: true}, 113 {expr: "+$", name: "$", found: true}, 114 {expr: "--$", name: "$", found: true}, 115 {expr: "-$", name: "$", floatOpposite: true, found: true}, 116 {expr: "---$", name: "$", floatOpposite: true, found: true}, 117 {expr: "()$", last: "()$"}, 118 {expr: "(0)$", last: "(0)$"}, 119 {expr: "(A)$", field: "A", name: "$", found: true}, 120 {expr: "+(A)$", field: "A", name: "$", found: true}, 121 {expr: "++(A)$", field: "A", name: "$", found: true}, 122 {expr: "!(A)$", field: "A", name: "$", boolOpposite: true, found: true}, 123 {expr: "-(A)$", field: "A", name: "$", floatOpposite: true, found: true}, 124 {expr: "(A0)$", field: "A0", name: "$", found: true}, 125 {expr: "!!(A0)$", field: "A0", name: "$", found: true}, 126 {expr: "--(A0)$", field: "A0", name: "$", found: true}, 127 {expr: "(A0)$(A1)$", last: "(A0)$(A1)$"}, 128 {expr: "(A0)$ $(A1)$", field: "A0", name: "$", found: true, last: " $(A1)$"}, 129 {expr: "$a", last: "$a"}, 130 {expr: "$[1]['a']", name: "$", subSelector: []string{"1", "'a'"}, found: true}, 131 {expr: "$[1][]", last: "$[1][]"}, 132 {expr: "$[[]]", last: "$[[]]"}, 133 {expr: "$[[[]]]", last: "$[[[]]]"}, 134 {expr: "$[(A)$[1]]", name: "$", subSelector: []string{"(A)$[1]"}, found: true}, 135 {expr: "$>0&&$<10", name: "$", found: true, last: ">0&&$<10"}, 136 } 137 for _, c := range cases { 138 last := c.expr 139 field, name, subSelector, boolOpposite, floatOpposite, found := findSelector(&last) 140 if found != c.found { 141 t.Fatalf("%q found: got: %v, want: %v", c.expr, found, c.found) 142 } 143 if c.boolOpposite && (boolOpposite == nil || !*boolOpposite) { 144 t.Fatalf("%q boolOpposite: got: %v, want: %v", c.expr, boolOpposite, c.boolOpposite) 145 } 146 if floatOpposite != c.floatOpposite { 147 t.Fatalf("%q floatOpposite: got: %v, want: %v", c.expr, floatOpposite, c.floatOpposite) 148 } 149 if field != c.field { 150 t.Fatalf("%q field: got: %q, want: %q", c.expr, field, c.field) 151 } 152 if name != c.name { 153 t.Fatalf("%q name: got: %q, want: %q", c.expr, name, c.name) 154 } 155 if !reflect.DeepEqual(subSelector, c.subSelector) { 156 t.Fatalf("%q subSelector: got: %v, want: %v", c.expr, subSelector, c.subSelector) 157 } 158 if last != c.last { 159 t.Fatalf("%q last: got: %q, want: %q", c.expr, last, c.last) 160 } 161 } 162 } 163 func printBoolPtr(b *bool) string { 164 var v interface{} = b 165 if b != nil { 166 v = *b 167 } 168 return fmt.Sprint(v) 169 }