github.com/AndrienkoAleksandr/go@v0.0.19/src/go/build/constraint/expr_test.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package constraint 6 7 import ( 8 "fmt" 9 "reflect" 10 "strings" 11 "testing" 12 ) 13 14 var exprStringTests = []struct { 15 x Expr 16 out string 17 }{ 18 { 19 x: tag("abc"), 20 out: "abc", 21 }, 22 { 23 x: not(tag("abc")), 24 out: "!abc", 25 }, 26 { 27 x: not(and(tag("abc"), tag("def"))), 28 out: "!(abc && def)", 29 }, 30 { 31 x: and(tag("abc"), or(tag("def"), tag("ghi"))), 32 out: "abc && (def || ghi)", 33 }, 34 { 35 x: or(and(tag("abc"), tag("def")), tag("ghi")), 36 out: "(abc && def) || ghi", 37 }, 38 } 39 40 func TestExprString(t *testing.T) { 41 for i, tt := range exprStringTests { 42 t.Run(fmt.Sprint(i), func(t *testing.T) { 43 s := tt.x.String() 44 if s != tt.out { 45 t.Errorf("String() mismatch:\nhave %s\nwant %s", s, tt.out) 46 } 47 }) 48 } 49 } 50 51 var lexTests = []struct { 52 in string 53 out string 54 }{ 55 {"", ""}, 56 {"x", "x"}, 57 {"x.y", "x.y"}, 58 {"x_y", "x_y"}, 59 {"αx", "αx"}, 60 {"αx²", "αx err: invalid syntax at ²"}, 61 {"go1.2", "go1.2"}, 62 {"x y", "x y"}, 63 {"x!y", "x ! y"}, 64 {"&&||!()xy yx ", "&& || ! ( ) xy yx"}, 65 {"x~", "x err: invalid syntax at ~"}, 66 {"x ~", "x err: invalid syntax at ~"}, 67 {"x &", "x err: invalid syntax at &"}, 68 {"x &y", "x err: invalid syntax at &"}, 69 } 70 71 func TestLex(t *testing.T) { 72 for i, tt := range lexTests { 73 t.Run(fmt.Sprint(i), func(t *testing.T) { 74 p := &exprParser{s: tt.in} 75 out := "" 76 for { 77 tok, err := lexHelp(p) 78 if tok == "" && err == nil { 79 break 80 } 81 if out != "" { 82 out += " " 83 } 84 if err != nil { 85 out += "err: " + err.Error() 86 break 87 } 88 out += tok 89 } 90 if out != tt.out { 91 t.Errorf("lex(%q):\nhave %s\nwant %s", tt.in, out, tt.out) 92 } 93 }) 94 } 95 } 96 97 func lexHelp(p *exprParser) (tok string, err error) { 98 defer func() { 99 if e := recover(); e != nil { 100 if e, ok := e.(*SyntaxError); ok { 101 err = e 102 return 103 } 104 panic(e) 105 } 106 }() 107 108 p.lex() 109 return p.tok, nil 110 } 111 112 var parseExprTests = []struct { 113 in string 114 x Expr 115 }{ 116 {"x", tag("x")}, 117 {"x&&y", and(tag("x"), tag("y"))}, 118 {"x||y", or(tag("x"), tag("y"))}, 119 {"(x)", tag("x")}, 120 {"x||y&&z", or(tag("x"), and(tag("y"), tag("z")))}, 121 {"x&&y||z", or(and(tag("x"), tag("y")), tag("z"))}, 122 {"x&&(y||z)", and(tag("x"), or(tag("y"), tag("z")))}, 123 {"(x||y)&&z", and(or(tag("x"), tag("y")), tag("z"))}, 124 {"!(x&&y)", not(and(tag("x"), tag("y")))}, 125 } 126 127 func TestParseExpr(t *testing.T) { 128 for i, tt := range parseExprTests { 129 t.Run(fmt.Sprint(i), func(t *testing.T) { 130 x, err := parseExpr(tt.in) 131 if err != nil { 132 t.Fatal(err) 133 } 134 if x.String() != tt.x.String() { 135 t.Errorf("parseExpr(%q):\nhave %s\nwant %s", tt.in, x, tt.x) 136 } 137 }) 138 } 139 } 140 141 var parseExprErrorTests = []struct { 142 in string 143 err error 144 }{ 145 {"x && ", &SyntaxError{Offset: 5, Err: "unexpected end of expression"}}, 146 {"x && (", &SyntaxError{Offset: 6, Err: "missing close paren"}}, 147 {"x && ||", &SyntaxError{Offset: 5, Err: "unexpected token ||"}}, 148 {"x && !", &SyntaxError{Offset: 6, Err: "unexpected end of expression"}}, 149 {"x && !!", &SyntaxError{Offset: 6, Err: "double negation not allowed"}}, 150 {"x !", &SyntaxError{Offset: 2, Err: "unexpected token !"}}, 151 {"x && (y", &SyntaxError{Offset: 5, Err: "missing close paren"}}, 152 } 153 154 func TestParseError(t *testing.T) { 155 for i, tt := range parseExprErrorTests { 156 t.Run(fmt.Sprint(i), func(t *testing.T) { 157 x, err := parseExpr(tt.in) 158 if err == nil { 159 t.Fatalf("parseExpr(%q) = %v, want error", tt.in, x) 160 } 161 if !reflect.DeepEqual(err, tt.err) { 162 t.Fatalf("parseExpr(%q): wrong error:\nhave %#v\nwant %#v", tt.in, err, tt.err) 163 } 164 }) 165 } 166 } 167 168 var exprEvalTests = []struct { 169 in string 170 ok bool 171 tags string 172 }{ 173 {"x", false, "x"}, 174 {"x && y", false, "x y"}, 175 {"x || y", false, "x y"}, 176 {"!x && yes", true, "x yes"}, 177 {"yes || y", true, "y yes"}, 178 } 179 180 func TestExprEval(t *testing.T) { 181 for i, tt := range exprEvalTests { 182 t.Run(fmt.Sprint(i), func(t *testing.T) { 183 x, err := parseExpr(tt.in) 184 if err != nil { 185 t.Fatal(err) 186 } 187 tags := make(map[string]bool) 188 wantTags := make(map[string]bool) 189 for _, tag := range strings.Fields(tt.tags) { 190 wantTags[tag] = true 191 } 192 hasTag := func(tag string) bool { 193 tags[tag] = true 194 return tag == "yes" 195 } 196 ok := x.Eval(hasTag) 197 if ok != tt.ok || !reflect.DeepEqual(tags, wantTags) { 198 t.Errorf("Eval(%#q):\nhave ok=%v, tags=%v\nwant ok=%v, tags=%v", 199 tt.in, ok, tags, tt.ok, wantTags) 200 } 201 }) 202 } 203 } 204 205 var parsePlusBuildExprTests = []struct { 206 in string 207 x Expr 208 }{ 209 {"x", tag("x")}, 210 {"x,y", and(tag("x"), tag("y"))}, 211 {"x y", or(tag("x"), tag("y"))}, 212 {"x y,z", or(tag("x"), and(tag("y"), tag("z")))}, 213 {"x,y z", or(and(tag("x"), tag("y")), tag("z"))}, 214 {"x,!y !z", or(and(tag("x"), not(tag("y"))), not(tag("z")))}, 215 {"!! x", or(tag("ignore"), tag("x"))}, 216 {"!!x", tag("ignore")}, 217 {"!x", not(tag("x"))}, 218 {"!", tag("ignore")}, 219 {"", tag("ignore")}, 220 } 221 222 func TestParsePlusBuildExpr(t *testing.T) { 223 for i, tt := range parsePlusBuildExprTests { 224 t.Run(fmt.Sprint(i), func(t *testing.T) { 225 x := parsePlusBuildExpr(tt.in) 226 if x.String() != tt.x.String() { 227 t.Errorf("parsePlusBuildExpr(%q):\nhave %v\nwant %v", tt.in, x, tt.x) 228 } 229 }) 230 } 231 } 232 233 var constraintTests = []struct { 234 in string 235 x Expr 236 err string 237 }{ 238 {"//+build !", tag("ignore"), ""}, 239 {"//+build", tag("ignore"), ""}, 240 {"//+build x y", or(tag("x"), tag("y")), ""}, 241 {"// +build x y \n", or(tag("x"), tag("y")), ""}, 242 {"// +build x y \n ", nil, "not a build constraint"}, 243 {"// +build x y \nmore", nil, "not a build constraint"}, 244 {" //+build x y", nil, "not a build constraint"}, 245 246 {"//go:build x && y", and(tag("x"), tag("y")), ""}, 247 {"//go:build x && y\n", and(tag("x"), tag("y")), ""}, 248 {"//go:build x && y\n ", nil, "not a build constraint"}, 249 {"//go:build x && y\nmore", nil, "not a build constraint"}, 250 {" //go:build x && y", nil, "not a build constraint"}, 251 {"//go:build\n", nil, "unexpected end of expression"}, 252 } 253 254 func TestParse(t *testing.T) { 255 for i, tt := range constraintTests { 256 t.Run(fmt.Sprint(i), func(t *testing.T) { 257 x, err := Parse(tt.in) 258 if err != nil { 259 if tt.err == "" { 260 t.Errorf("Constraint(%q): unexpected error: %v", tt.in, err) 261 } else if !strings.Contains(err.Error(), tt.err) { 262 t.Errorf("Constraint(%q): error %v, want %v", tt.in, err, tt.err) 263 } 264 return 265 } 266 if tt.err != "" { 267 t.Errorf("Constraint(%q) = %v, want error %v", tt.in, x, tt.err) 268 return 269 } 270 if x.String() != tt.x.String() { 271 t.Errorf("Constraint(%q):\nhave %v\nwant %v", tt.in, x, tt.x) 272 } 273 }) 274 } 275 } 276 277 var plusBuildLinesTests = []struct { 278 in string 279 out []string 280 err error 281 }{ 282 {"x", []string{"x"}, nil}, 283 {"x && !y", []string{"x,!y"}, nil}, 284 {"x || y", []string{"x y"}, nil}, 285 {"x && (y || z)", []string{"x", "y z"}, nil}, 286 {"!(x && y)", []string{"!x !y"}, nil}, 287 {"x || (y && z)", []string{"x y,z"}, nil}, 288 {"w && (x || (y && z))", []string{"w", "x y,z"}, nil}, 289 {"v || (w && (x || (y && z)))", nil, errComplex}, 290 } 291 292 func TestPlusBuildLines(t *testing.T) { 293 for i, tt := range plusBuildLinesTests { 294 t.Run(fmt.Sprint(i), func(t *testing.T) { 295 x, err := parseExpr(tt.in) 296 if err != nil { 297 t.Fatal(err) 298 } 299 lines, err := PlusBuildLines(x) 300 if err != nil { 301 if tt.err == nil { 302 t.Errorf("PlusBuildLines(%q): unexpected error: %v", tt.in, err) 303 } else if tt.err != err { 304 t.Errorf("PlusBuildLines(%q): error %v, want %v", tt.in, err, tt.err) 305 } 306 return 307 } 308 if tt.err != nil { 309 t.Errorf("PlusBuildLines(%q) = %v, want error %v", tt.in, lines, tt.err) 310 return 311 } 312 var want []string 313 for _, line := range tt.out { 314 want = append(want, "// +build "+line) 315 } 316 if !reflect.DeepEqual(lines, want) { 317 t.Errorf("PlusBuildLines(%q):\nhave %q\nwant %q", tt.in, lines, want) 318 } 319 }) 320 } 321 }