...

Source file src/go/build/constraint/expr_test.go

Documentation: go/build/constraint

		 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  }
	 322  

View as plain text