1package buildtags
2
3import "testing"
4
5func TestGoString(t *testing.T) {
6	cases := []struct {
7		Constraint Interface
8		Expect     string
9	}{
10		{Term("amd64"), "// +build amd64\n"},
11		{Any(Opt(Term("linux"), Term("386")), Opt("darwin", Not("cgo"))), "// +build linux,386 darwin,!cgo\n"},
12		{And(Any(Term("linux"), Term("darwin")), Term("386")), "// +build linux darwin\n// +build 386\n"},
13	}
14	for _, c := range cases {
15		got := c.Constraint.ToConstraints().GoString()
16		if got != c.Expect {
17			t.Errorf("constraint %#v GoString() got %q; expected %q", c.Constraint, got, c.Expect)
18		}
19	}
20}
21
22func TestValidateOK(t *testing.T) {
23	cases := []Interface{
24		Term("name"),
25		Term("!name"),
26	}
27	for _, c := range cases {
28		if err := c.ToConstraints().Validate(); err != nil {
29			t.Errorf("unexpected validation error for %#v: %q", c, err)
30		}
31	}
32}
33
34func TestValidateErrors(t *testing.T) {
35	cases := []struct {
36		Constraint    Interface
37		ExpectMessage string
38	}{
39		{Term(""), "empty tag name"},
40		{Term("!"), "empty tag name"},
41		{Term("!!"), "at most one '!' allowed"},
42		{Term("!abc!def"), "character '!' disallowed in tags"},
43		{
44			And(Any(Term("linux"), Term("my-os")), Term("386")).ToConstraints(),
45			"invalid term \"my-os\": character '-' disallowed in tags",
46		},
47	}
48	for _, c := range cases {
49		err := c.Constraint.Validate()
50		if err == nil {
51			t.Fatalf("expect validation error for constraint:\n%s", c.Constraint.GoString())
52		}
53		if err.Error() != c.ExpectMessage {
54			t.Fatalf("unexpected error message\n\tgot:\t%q\n\texpect:\t%q\n", err, c.ExpectMessage)
55		}
56	}
57}
58
59func TestParseConstraintRoundTrip(t *testing.T) {
60	exprs := []string{
61		"amd64",
62		"amd64,linux",
63		"!a",
64		"!a,b c,!d,e",
65		"linux,386 darwin,!cgo",
66	}
67	for _, expr := range exprs {
68		c := AssertParseConstraint(t, expr)
69		got := c.GoString()
70		expect := "// +build " + expr + "\n"
71		if got != expect {
72			t.Fatalf("roundtrip error\n\tgot\t%q\n\texpect\t%q\n", got, expect)
73		}
74	}
75}
76
77func TestParseConstraintError(t *testing.T) {
78	expr := "linux,386 my-os,!cgo"
79	_, err := ParseConstraint(expr)
80	if err == nil {
81		t.Fatalf("expected error parsing %q", expr)
82	}
83}
84
85func TestEvaluate(t *testing.T) {
86	cases := []struct {
87		Constraint Interface
88		Values     map[string]bool
89		Expect     bool
90	}{
91		{Term("a"), SetTags("a"), true},
92		{Term("!a"), SetTags("a"), false},
93		{Term("!a"), SetTags(), true},
94		{Term("inval-id"), SetTags("inval-id"), false},
95
96		{Opt(Term("a"), Term("b")), SetTags(), false},
97		{Opt(Term("a"), Term("b")), SetTags("a"), false},
98		{Opt(Term("a"), Term("b")), SetTags("b"), false},
99		{Opt(Term("a"), Term("b")), SetTags("a", "b"), true},
100		{Opt(Term("a"), Term("b-a-d")), SetTags("a", "b-a-d"), false},
101
102		{
103			Any(Opt(Term("linux"), Term("386")), Opt("darwin", Not("cgo"))),
104			SetTags("linux", "386"),
105			true,
106		},
107		{
108			Any(Opt(Term("linux"), Term("386")), Opt("darwin", Not("cgo"))),
109			SetTags("darwin"),
110			true,
111		},
112		{
113			Any(Opt(Term("linux"), Term("386")), Opt("darwin", Not("cgo"))),
114			SetTags("linux", "darwin", "cgo"),
115			false,
116		},
117
118		{
119			And(Any(Term("linux"), Term("darwin")), Term("386")),
120			SetTags("darwin", "386"),
121			true,
122		},
123	}
124	for _, c := range cases {
125		got := c.Constraint.Evaluate(c.Values)
126		if c.Constraint.Validate() != nil && got {
127			t.Fatal("invalid expressions must evaluate false")
128		}
129		if got != c.Expect {
130			t.Errorf("%#v evaluated with %#v got %v expect %v", c.Constraint, c.Values, got, c.Expect)
131		}
132	}
133}
134
135func AssertParseConstraint(t *testing.T, expr string) Constraint {
136	t.Helper()
137	c, err := ParseConstraint(expr)
138	if err != nil {
139		t.Fatalf("error parsing expression %q: %q", expr, err)
140	}
141	return c
142}
143