github.com/bytedance/go-tagexpr/v2@v2.9.8/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 "context" 19 "fmt" 20 "reflect" 21 "testing" 22 ) 23 24 func TestReadPairedSymbol(t *testing.T) { 25 var cases = []struct { 26 left, right rune 27 expr, val, lastExprNode string 28 }{ 29 {left: '\'', right: '\'', expr: "'true '+'a'", val: "true ", lastExprNode: "+'a'"}, 30 {left: '(', right: ')', expr: "((0+1)/(2-1)*9)%2", val: "(0+1)/(2-1)*9", lastExprNode: "%2"}, 31 {left: '(', right: ')', expr: `(\)\(\))`, val: `)()`}, 32 {left: '\'', right: '\'', expr: `'\\'`, val: `\\`}, 33 {left: '\'', right: '\'', expr: `'\'\''`, val: `''`}, 34 } 35 for _, c := range cases { 36 t.Log(c.expr) 37 expr := c.expr 38 got := readPairedSymbol(&expr, c.left, c.right) 39 if got == nil { 40 t.Fatalf("expr: %q, got: %v, %q, want: %q, %q", c.expr, got, expr, c.val, c.lastExprNode) 41 } else if *got != c.val || expr != c.lastExprNode { 42 t.Fatalf("expr: %q, got: %q, %q, want: %q, %q", c.expr, *got, expr, c.val, c.lastExprNode) 43 } 44 } 45 } 46 47 func TestReadBoolExprNode(t *testing.T) { 48 var cases = []struct { 49 expr string 50 val bool 51 lastExprNode string 52 }{ 53 {expr: "false", val: false, lastExprNode: ""}, 54 {expr: "true", val: true, lastExprNode: ""}, 55 {expr: "true ", val: true, lastExprNode: " "}, 56 {expr: "!true&", val: false, lastExprNode: "&"}, 57 {expr: "!false|", val: true, lastExprNode: "|"}, 58 {expr: "!!!!false =", val: !!!!false, lastExprNode: " ="}, 59 } 60 for _, c := range cases { 61 t.Log(c.expr) 62 expr := c.expr 63 e := readBoolExprNode(&expr) 64 got := e.Run(context.TODO(), "", nil).(bool) 65 if got != c.val || expr != c.lastExprNode { 66 t.Fatalf("expr: %s, got: %v, %s, want: %v, %s", c.expr, got, expr, c.val, c.lastExprNode) 67 } 68 } 69 } 70 71 func TestReadDigitalExprNode(t *testing.T) { 72 var cases = []struct { 73 expr string 74 val float64 75 lastExprNode string 76 }{ 77 {expr: "0.1 +1", val: 0.1, lastExprNode: " +1"}, 78 {expr: "-1\\1", val: -1, lastExprNode: "\\1"}, 79 {expr: "1a", val: 0, lastExprNode: ""}, 80 {expr: "1", val: 1, lastExprNode: ""}, 81 {expr: "1.1", val: 1.1, lastExprNode: ""}, 82 {expr: "1.1/", val: 1.1, lastExprNode: "/"}, 83 } 84 for _, c := range cases { 85 expr := c.expr 86 e := readDigitalExprNode(&expr) 87 if c.expr == "1a" { 88 if e != nil { 89 t.Fatalf("expr: %s, got:%v, want:%v", c.expr, e.Run(context.TODO(), "", nil), nil) 90 } 91 continue 92 } 93 got := e.Run(context.TODO(), "", nil).(float64) 94 if got != c.val || expr != c.lastExprNode { 95 t.Fatalf("expr: %s, got: %f, %s, want: %f, %s", c.expr, got, expr, c.val, c.lastExprNode) 96 } 97 } 98 } 99 100 func TestFindSelector(t *testing.T) { 101 var cases = []struct { 102 expr string 103 field string 104 name string 105 subSelector []string 106 boolOpposite bool 107 signOpposite bool 108 found bool 109 last string 110 }{ 111 {expr: "$", name: "$", found: true}, 112 {expr: "!!$", name: "$", found: true}, 113 {expr: "!$", name: "$", boolOpposite: true, found: true}, 114 {expr: "+$", name: "$", found: true}, 115 {expr: "--$", name: "$", found: true}, 116 {expr: "-$", name: "$", signOpposite: true, found: true}, 117 {expr: "---$", name: "$", signOpposite: true, found: true}, 118 {expr: "()$", last: "()$"}, 119 {expr: "(0)$", last: "(0)$"}, 120 {expr: "(A)$", field: "A", name: "$", found: true}, 121 {expr: "+(A)$", field: "A", name: "$", found: true}, 122 {expr: "++(A)$", field: "A", name: "$", found: true}, 123 {expr: "!(A)$", field: "A", name: "$", boolOpposite: true, found: true}, 124 {expr: "-(A)$", field: "A", name: "$", signOpposite: true, found: true}, 125 {expr: "(A0)$", field: "A0", name: "$", found: true}, 126 {expr: "!!(A0)$", field: "A0", name: "$", found: true}, 127 {expr: "--(A0)$", field: "A0", name: "$", found: true}, 128 {expr: "(A0)$(A1)$", last: "(A0)$(A1)$"}, 129 {expr: "(A0)$ $(A1)$", field: "A0", name: "$", found: true, last: " $(A1)$"}, 130 {expr: "$a", last: "$a"}, 131 {expr: "$[1]['a']", name: "$", subSelector: []string{"1", "'a'"}, found: true}, 132 {expr: "$[1][]", last: "$[1][]"}, 133 {expr: "$[[]]", last: "$[[]]"}, 134 {expr: "$[[[]]]", last: "$[[[]]]"}, 135 {expr: "$[(A)$[1]]", name: "$", subSelector: []string{"(A)$[1]"}, found: true}, 136 {expr: "$>0&&$<10", name: "$", found: true, last: ">0&&$<10"}, 137 } 138 for _, c := range cases { 139 last := c.expr 140 field, name, subSelector, boolOpposite, signOpposite, found := findSelector(&last) 141 if found != c.found { 142 t.Fatalf("%q found: got: %v, want: %v", c.expr, found, c.found) 143 } 144 if c.boolOpposite && (boolOpposite == nil || !*boolOpposite) { 145 t.Fatalf("%q boolOpposite: got: %v, want: %v", c.expr, boolOpposite, c.boolOpposite) 146 } 147 if c.signOpposite && (signOpposite == nil || !*signOpposite) { 148 t.Fatalf("%q signOpposite: got: %v, want: %v", c.expr, signOpposite, c.signOpposite) 149 } 150 if field != c.field { 151 t.Fatalf("%q field: got: %q, want: %q", c.expr, field, c.field) 152 } 153 if name != c.name { 154 t.Fatalf("%q name: got: %q, want: %q", c.expr, name, c.name) 155 } 156 if !reflect.DeepEqual(subSelector, c.subSelector) { 157 t.Fatalf("%q subSelector: got: %v, want: %v", c.expr, subSelector, c.subSelector) 158 } 159 if last != c.last { 160 t.Fatalf("%q last: got: %q, want: %q", c.expr, last, c.last) 161 } 162 } 163 } 164 func printBoolPtr(b *bool) string { 165 var v interface{} = b 166 if b != nil { 167 v = *b 168 } 169 return fmt.Sprint(v) 170 }