1// Copyright 2021 CUE Authors
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
15package load
16
17import (
18	"bytes"
19	"io/ioutil"
20	"os"
21	"path/filepath"
22	"testing"
23
24	"cuelang.org/go/cue/ast"
25	"cuelang.org/go/cue/cuecontext"
26	"cuelang.org/go/cue/token"
27	"cuelang.org/go/internal/diff"
28)
29
30var testTagVars = map[string]TagVar{
31	"now":      stringVar("2006-01-02T15:04:05.999999999Z"),
32	"os":       stringVar("m1"),
33	"cwd":      stringVar("home"),
34	"username": stringVar("cueser"),
35	"hostname": stringVar("cuebe"),
36	"rand": {Func: func() (ast.Expr, error) {
37		return ast.NewLit(token.INT, "112950970371208119678246559335704039641"), nil
38	}},
39}
40
41func stringVar(s string) TagVar {
42	return TagVar{Func: func() (ast.Expr, error) { return ast.NewString(s), nil }}
43}
44
45func TestTags(t *testing.T) {
46	dir, _ := ioutil.TempDir("", "")
47	defer os.RemoveAll(dir)
48
49	testCases := []struct {
50		in  string
51		out string
52		err string
53	}{{
54		in: `
55		rand: int    @tag(foo,var=rand)
56		time: string @tag(bar,var=now)
57		host: string @tag(bar,var=hostname)
58		user: string @tag(bar,var=username)
59		cwd:  string @tag(bar,var=cwd)
60		`,
61
62		out: `{
63			rand: 112950970371208119678246559335704039641
64			time: "2006-01-02T15:04:05.999999999Z"
65			host: "cuebe"
66			user: "cueser"
67			cwd:  "home"
68		}`,
69	}, {
70		in: `
71		time: int @tag(bar,var=now)
72		`,
73		err: `time: conflicting values int and "2006-01-02T15:04:05.999999999Z" (mismatched types int and string)`,
74	}, {
75		// Auto inject only on marked places
76		// TODO: Is this the right thing to do?
77		in: `
78			u1: string @tag(bar,var=username)
79			u2: string @tag(bar)
80			`,
81		out: `{
82			u1: "cueser"
83            u2: string // not filled
84        }`,
85	}, {
86		in: `
87		u1: string @tag(bar,var=user)
88		`,
89		err: `tag variable 'user' not found`,
90	}}
91
92	for _, tc := range testCases {
93		t.Run("", func(t *testing.T) {
94			cfg := &Config{
95				Dir: dir,
96				Overlay: map[string]Source{
97					filepath.Join(dir, "foo.cue"): FromString(tc.in),
98				},
99				TagVars: testTagVars,
100			}
101			b := Instances([]string{"foo.cue"}, cfg)[0]
102
103			c := cuecontext.New()
104			got := c.BuildInstance(b)
105			switch err := got.Err(); {
106			case (err == nil) != (tc.err == ""):
107				t.Fatalf("error: got %v; want %v", err, tc.err)
108
109			case err != nil:
110				got := err.Error()
111				if got != tc.err {
112					t.Fatalf("error: got %v; want %v", got, tc.err)
113				}
114
115			default:
116				want := c.CompileString(tc.out)
117				if !got.Equals(want) {
118					_, es := diff.Diff(got, want)
119					b := &bytes.Buffer{}
120					diff.Print(b, es)
121					t.Error(b)
122				}
123			}
124		})
125	}
126}
127