1// Copyright 2017 Istio 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 checker
16
17import (
18	"fmt"
19	"strings"
20	"testing"
21
22	cfgpb "istio.io/api/policy/v1beta1"
23	"istio.io/pkg/attribute"
24)
25
26func TestTypeCheck(t *testing.T) {
27	af := newAF([]*ad{
28		{"int", cfgpb.INT64},
29		{"bool", cfgpb.BOOL},
30		{"double", cfgpb.DOUBLE},
31		{"string", cfgpb.STRING},
32		{"timestamp", cfgpb.TIMESTAMP},
33		{"ip", cfgpb.IP_ADDRESS},
34		{"email", cfgpb.EMAIL_ADDRESS},
35		{"uri", cfgpb.URI},
36		{"dns", cfgpb.DNS_NAME},
37		{"duration", cfgpb.DURATION},
38		{"stringmap", cfgpb.STRING_MAP},
39	})
40
41	tests := []struct {
42		in  string
43		out cfgpb.ValueType
44		err string
45	}{
46		// identity
47		{"int", cfgpb.INT64, ""},
48		{"bool", cfgpb.BOOL, ""},
49		{"double", cfgpb.DOUBLE, ""},
50		{"string", cfgpb.STRING, ""},
51		{"timestamp", cfgpb.TIMESTAMP, ""},
52		{"ip", cfgpb.IP_ADDRESS, ""},
53		{"email", cfgpb.EMAIL_ADDRESS, ""},
54		{"uri", cfgpb.URI, ""},
55		{"dns", cfgpb.DNS_NAME, ""},
56		{"duration", cfgpb.DURATION, ""},
57		{"stringmap", cfgpb.STRING_MAP, ""},
58		// expressions
59		{"int == 2", cfgpb.BOOL, ""},
60		{"double == 2.0", cfgpb.BOOL, ""},
61		{`string | "foobar"`, cfgpb.STRING, ""},
62		// invalid expressions
63		{"int | bool", cfgpb.VALUE_TYPE_UNSPECIFIED, "typeError"},
64		{"stringmap | ", cfgpb.VALUE_TYPE_UNSPECIFIED, "failed to parse"},
65	}
66
67	for idx, tt := range tests {
68		t.Run(fmt.Sprintf("[%d] %s", idx, tt.in), func(t *testing.T) {
69			ev := NewTypeChecker(af)
70			vt, err := ev.EvalType(tt.in)
71			if tt.err != "" || err != nil {
72				if !strings.Contains(err.Error(), tt.err) {
73					t.Fatalf("EvalType(%s, adf) = %v, wanted err %v", tt.in, err, tt.err)
74				}
75			}
76			if vt != tt.out {
77				t.Fatalf("EvalType(%s, adf) = %v, wanted type %v", tt.in, vt, tt.out)
78			}
79		})
80	}
81}
82
83type ad struct {
84	name string
85	v    cfgpb.ValueType
86}
87
88func newAF(ds []*ad) attribute.AttributeDescriptorFinder {
89	m := make(map[string]*cfgpb.AttributeManifest_AttributeInfo)
90	for _, aa := range ds {
91		m[aa.name] = &cfgpb.AttributeManifest_AttributeInfo{ValueType: aa.v}
92	}
93	return attribute.NewFinder(m)
94}
95