xref: /aosp_15_r20/build/blueprint/bootstrap/bpdoc/properties_test.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2019 Google Inc. All rights reserved.
2*1fa6dee9SAndroid Build Coastguard Worker//
3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*1fa6dee9SAndroid Build Coastguard Worker//
7*1fa6dee9SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*1fa6dee9SAndroid Build Coastguard Worker//
9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License.
14*1fa6dee9SAndroid Build Coastguard Worker
15*1fa6dee9SAndroid Build Coastguard Workerpackage bpdoc
16*1fa6dee9SAndroid Build Coastguard Worker
17*1fa6dee9SAndroid Build Coastguard Workerimport (
18*1fa6dee9SAndroid Build Coastguard Worker	"reflect"
19*1fa6dee9SAndroid Build Coastguard Worker	"strings"
20*1fa6dee9SAndroid Build Coastguard Worker	"testing"
21*1fa6dee9SAndroid Build Coastguard Worker)
22*1fa6dee9SAndroid Build Coastguard Worker
23*1fa6dee9SAndroid Build Coastguard Workerfunc TestExcludeByTag(t *testing.T) {
24*1fa6dee9SAndroid Build Coastguard Worker	r := NewReader(pkgFiles)
25*1fa6dee9SAndroid Build Coastguard Worker	ps, err := r.PropertyStruct(pkgPath, "tagTestProps", reflect.ValueOf(tagTestProps{}))
26*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
27*1fa6dee9SAndroid Build Coastguard Worker		t.Fatal(err)
28*1fa6dee9SAndroid Build Coastguard Worker	}
29*1fa6dee9SAndroid Build Coastguard Worker
30*1fa6dee9SAndroid Build Coastguard Worker	ps.ExcludeByTag("tag1", "a")
31*1fa6dee9SAndroid Build Coastguard Worker
32*1fa6dee9SAndroid Build Coastguard Worker	expected := []string{"c", "d", "g"}
33*1fa6dee9SAndroid Build Coastguard Worker	actual := actualProperties(t, ps.Properties)
34*1fa6dee9SAndroid Build Coastguard Worker	if !reflect.DeepEqual(expected, actual) {
35*1fa6dee9SAndroid Build Coastguard Worker		t.Errorf("unexpected ExcludeByTag result, expected: %q, actual: %q", expected, actual)
36*1fa6dee9SAndroid Build Coastguard Worker	}
37*1fa6dee9SAndroid Build Coastguard Worker}
38*1fa6dee9SAndroid Build Coastguard Worker
39*1fa6dee9SAndroid Build Coastguard Workerfunc TestIncludeByTag(t *testing.T) {
40*1fa6dee9SAndroid Build Coastguard Worker	r := NewReader(pkgFiles)
41*1fa6dee9SAndroid Build Coastguard Worker	ps, err := r.PropertyStruct(pkgPath, "tagTestProps", reflect.ValueOf(tagTestProps{A: "B"}))
42*1fa6dee9SAndroid Build Coastguard Worker	if err != nil {
43*1fa6dee9SAndroid Build Coastguard Worker		t.Fatal(err)
44*1fa6dee9SAndroid Build Coastguard Worker	}
45*1fa6dee9SAndroid Build Coastguard Worker
46*1fa6dee9SAndroid Build Coastguard Worker	ps.IncludeByTag("tag1", "c")
47*1fa6dee9SAndroid Build Coastguard Worker
48*1fa6dee9SAndroid Build Coastguard Worker	expected := []string{"b", "c", "d", "f", "g"}
49*1fa6dee9SAndroid Build Coastguard Worker	actual := actualProperties(t, ps.Properties)
50*1fa6dee9SAndroid Build Coastguard Worker	if !reflect.DeepEqual(expected, actual) {
51*1fa6dee9SAndroid Build Coastguard Worker		t.Errorf("unexpected IncludeByTag result, expected: %q, actual: %q", expected, actual)
52*1fa6dee9SAndroid Build Coastguard Worker	}
53*1fa6dee9SAndroid Build Coastguard Worker}
54*1fa6dee9SAndroid Build Coastguard Worker
55*1fa6dee9SAndroid Build Coastguard Workerfunc TestPropertiesOfReflectionStructs(t *testing.T) {
56*1fa6dee9SAndroid Build Coastguard Worker	testCases := []struct {
57*1fa6dee9SAndroid Build Coastguard Worker		fields             map[string]interface{}
58*1fa6dee9SAndroid Build Coastguard Worker		expectedProperties map[string]Property
59*1fa6dee9SAndroid Build Coastguard Worker		description        string
60*1fa6dee9SAndroid Build Coastguard Worker	}{
61*1fa6dee9SAndroid Build Coastguard Worker		{
62*1fa6dee9SAndroid Build Coastguard Worker			fields: map[string]interface{}{
63*1fa6dee9SAndroid Build Coastguard Worker				"A": "A is a string",
64*1fa6dee9SAndroid Build Coastguard Worker				"B": 0, //B is an int
65*1fa6dee9SAndroid Build Coastguard Worker			},
66*1fa6dee9SAndroid Build Coastguard Worker			expectedProperties: map[string]Property{
67*1fa6dee9SAndroid Build Coastguard Worker				"a": *createProperty("a", "string", ""),
68*1fa6dee9SAndroid Build Coastguard Worker				"b": *createProperty("b", "int", ""),
69*1fa6dee9SAndroid Build Coastguard Worker			},
70*1fa6dee9SAndroid Build Coastguard Worker			description: "struct is composed of primitive types",
71*1fa6dee9SAndroid Build Coastguard Worker		},
72*1fa6dee9SAndroid Build Coastguard Worker		{
73*1fa6dee9SAndroid Build Coastguard Worker			fields: map[string]interface{}{
74*1fa6dee9SAndroid Build Coastguard Worker				"A": "A is a string",
75*1fa6dee9SAndroid Build Coastguard Worker				"B": 0, //B is an int
76*1fa6dee9SAndroid Build Coastguard Worker				"C": props{},
77*1fa6dee9SAndroid Build Coastguard Worker			},
78*1fa6dee9SAndroid Build Coastguard Worker			expectedProperties: map[string]Property{
79*1fa6dee9SAndroid Build Coastguard Worker				"a": *createProperty("a", "string", ""),
80*1fa6dee9SAndroid Build Coastguard Worker				"b": *createProperty("b", "int", ""),
81*1fa6dee9SAndroid Build Coastguard Worker				"c": *createProperty("c", "props", "props docs."),
82*1fa6dee9SAndroid Build Coastguard Worker			},
83*1fa6dee9SAndroid Build Coastguard Worker			description: "struct is composed of primitive types and other structs",
84*1fa6dee9SAndroid Build Coastguard Worker		},
85*1fa6dee9SAndroid Build Coastguard Worker	}
86*1fa6dee9SAndroid Build Coastguard Worker
87*1fa6dee9SAndroid Build Coastguard Worker	r := NewReader(pkgFiles)
88*1fa6dee9SAndroid Build Coastguard Worker	for _, testCase := range testCases {
89*1fa6dee9SAndroid Build Coastguard Worker		structType := reflectionStructType(testCase.fields)
90*1fa6dee9SAndroid Build Coastguard Worker		ps, err := r.PropertyStruct(structType.PkgPath(), structType.String(), reflect.New(structType).Elem())
91*1fa6dee9SAndroid Build Coastguard Worker		if err != nil {
92*1fa6dee9SAndroid Build Coastguard Worker			t.Fatal(err)
93*1fa6dee9SAndroid Build Coastguard Worker		}
94*1fa6dee9SAndroid Build Coastguard Worker		for _, actualProperty := range ps.Properties {
95*1fa6dee9SAndroid Build Coastguard Worker			propName := actualProperty.Name
96*1fa6dee9SAndroid Build Coastguard Worker			assertProperties(t, testCase.expectedProperties[propName], actualProperty)
97*1fa6dee9SAndroid Build Coastguard Worker		}
98*1fa6dee9SAndroid Build Coastguard Worker	}
99*1fa6dee9SAndroid Build Coastguard Worker}
100*1fa6dee9SAndroid Build Coastguard Worker
101*1fa6dee9SAndroid Build Coastguard Workerfunc TestNestUnique(t *testing.T) {
102*1fa6dee9SAndroid Build Coastguard Worker	testCases := []struct {
103*1fa6dee9SAndroid Build Coastguard Worker		src         []Property
104*1fa6dee9SAndroid Build Coastguard Worker		target      []Property
105*1fa6dee9SAndroid Build Coastguard Worker		expected    []Property
106*1fa6dee9SAndroid Build Coastguard Worker		description string
107*1fa6dee9SAndroid Build Coastguard Worker	}{
108*1fa6dee9SAndroid Build Coastguard Worker		{
109*1fa6dee9SAndroid Build Coastguard Worker			src:         []Property{},
110*1fa6dee9SAndroid Build Coastguard Worker			target:      []Property{},
111*1fa6dee9SAndroid Build Coastguard Worker			expected:    []Property{},
112*1fa6dee9SAndroid Build Coastguard Worker			description: "Nest Unique fails for empty slice",
113*1fa6dee9SAndroid Build Coastguard Worker		},
114*1fa6dee9SAndroid Build Coastguard Worker		{
115*1fa6dee9SAndroid Build Coastguard Worker			src:         []Property{*createProperty("a", "string", ""), *createProperty("b", "string", "")},
116*1fa6dee9SAndroid Build Coastguard Worker			target:      []Property{},
117*1fa6dee9SAndroid Build Coastguard Worker			expected:    []Property{*createProperty("a", "string", ""), *createProperty("b", "string", "")},
118*1fa6dee9SAndroid Build Coastguard Worker			description: "Nest Unique fails when all elements are unique",
119*1fa6dee9SAndroid Build Coastguard Worker		},
120*1fa6dee9SAndroid Build Coastguard Worker		{
121*1fa6dee9SAndroid Build Coastguard Worker			src:         []Property{*createProperty("a", "string", ""), *createProperty("b", "string", "")},
122*1fa6dee9SAndroid Build Coastguard Worker			target:      []Property{*createProperty("c", "string", "")},
123*1fa6dee9SAndroid Build Coastguard Worker			expected:    []Property{*createProperty("a", "string", ""), *createProperty("b", "string", ""), *createProperty("c", "string", "")},
124*1fa6dee9SAndroid Build Coastguard Worker			description: "Nest Unique fails when all elements are unique",
125*1fa6dee9SAndroid Build Coastguard Worker		},
126*1fa6dee9SAndroid Build Coastguard Worker		{
127*1fa6dee9SAndroid Build Coastguard Worker			src:         []Property{*createProperty("a", "string", ""), *createProperty("b", "string", "")},
128*1fa6dee9SAndroid Build Coastguard Worker			target:      []Property{*createProperty("a", "string", "")},
129*1fa6dee9SAndroid Build Coastguard Worker			expected:    []Property{*createProperty("a", "string", ""), *createProperty("b", "string", "")},
130*1fa6dee9SAndroid Build Coastguard Worker			description: "Nest Unique fails when nested elements are duplicate",
131*1fa6dee9SAndroid Build Coastguard Worker		},
132*1fa6dee9SAndroid Build Coastguard Worker	}
133*1fa6dee9SAndroid Build Coastguard Worker
134*1fa6dee9SAndroid Build Coastguard Worker	errMsgTemplate := "%s. Expected: %q, Actual: %q"
135*1fa6dee9SAndroid Build Coastguard Worker	for _, testCase := range testCases {
136*1fa6dee9SAndroid Build Coastguard Worker		actual := nestUnique(testCase.src, testCase.target)
137*1fa6dee9SAndroid Build Coastguard Worker		if len(actual) != len(testCase.expected) {
138*1fa6dee9SAndroid Build Coastguard Worker			t.Errorf(errMsgTemplate, testCase.description, testCase.expected, actual)
139*1fa6dee9SAndroid Build Coastguard Worker		}
140*1fa6dee9SAndroid Build Coastguard Worker		for i := 0; i < len(actual); i++ {
141*1fa6dee9SAndroid Build Coastguard Worker			if !actual[i].Equal(testCase.expected[i]) {
142*1fa6dee9SAndroid Build Coastguard Worker				t.Errorf(errMsgTemplate, testCase.description, testCase.expected[i], actual[i])
143*1fa6dee9SAndroid Build Coastguard Worker			}
144*1fa6dee9SAndroid Build Coastguard Worker		}
145*1fa6dee9SAndroid Build Coastguard Worker	}
146*1fa6dee9SAndroid Build Coastguard Worker}
147*1fa6dee9SAndroid Build Coastguard Worker
148*1fa6dee9SAndroid Build Coastguard Worker// Creates a struct using reflection and return its type
149*1fa6dee9SAndroid Build Coastguard Workerfunc reflectionStructType(fields map[string]interface{}) reflect.Type {
150*1fa6dee9SAndroid Build Coastguard Worker	var structFields []reflect.StructField
151*1fa6dee9SAndroid Build Coastguard Worker	for fieldname, obj := range fields {
152*1fa6dee9SAndroid Build Coastguard Worker		structField := reflect.StructField{
153*1fa6dee9SAndroid Build Coastguard Worker			Name: fieldname,
154*1fa6dee9SAndroid Build Coastguard Worker			Type: reflect.TypeOf(obj),
155*1fa6dee9SAndroid Build Coastguard Worker		}
156*1fa6dee9SAndroid Build Coastguard Worker		structFields = append(structFields, structField)
157*1fa6dee9SAndroid Build Coastguard Worker	}
158*1fa6dee9SAndroid Build Coastguard Worker	return reflect.StructOf(structFields)
159*1fa6dee9SAndroid Build Coastguard Worker}
160*1fa6dee9SAndroid Build Coastguard Worker
161*1fa6dee9SAndroid Build Coastguard Worker// Creates a Property object with a subset of its props populated
162*1fa6dee9SAndroid Build Coastguard Workerfunc createProperty(propName string, propType string, propDocs string) *Property {
163*1fa6dee9SAndroid Build Coastguard Worker	return &Property{Name: propName, Type: propType, Text: formatText(propDocs)}
164*1fa6dee9SAndroid Build Coastguard Worker}
165*1fa6dee9SAndroid Build Coastguard Worker
166*1fa6dee9SAndroid Build Coastguard Worker// Asserts that two Property objects are "similar"
167*1fa6dee9SAndroid Build Coastguard Worker// Name, Type and Text properties are checked for similarity
168*1fa6dee9SAndroid Build Coastguard Workerfunc assertProperties(t *testing.T, expected Property, actual Property) {
169*1fa6dee9SAndroid Build Coastguard Worker	assertStrings(t, expected.Name, actual.Name)
170*1fa6dee9SAndroid Build Coastguard Worker	assertStrings(t, expected.Type, actual.Type)
171*1fa6dee9SAndroid Build Coastguard Worker	assertStrings(t, strings.TrimSpace(string(expected.Text)), strings.TrimSpace(string(actual.Text)))
172*1fa6dee9SAndroid Build Coastguard Worker}
173*1fa6dee9SAndroid Build Coastguard Worker
174*1fa6dee9SAndroid Build Coastguard Workerfunc assertStrings(t *testing.T, expected string, actual string) {
175*1fa6dee9SAndroid Build Coastguard Worker	if expected != actual {
176*1fa6dee9SAndroid Build Coastguard Worker		t.Errorf("expected: %s, actual: %s", expected, actual)
177*1fa6dee9SAndroid Build Coastguard Worker	}
178*1fa6dee9SAndroid Build Coastguard Worker}
179*1fa6dee9SAndroid Build Coastguard Worker
180*1fa6dee9SAndroid Build Coastguard Workerfunc actualProperties(t *testing.T, props []Property) []string {
181*1fa6dee9SAndroid Build Coastguard Worker	t.Helper()
182*1fa6dee9SAndroid Build Coastguard Worker
183*1fa6dee9SAndroid Build Coastguard Worker	actual := []string{}
184*1fa6dee9SAndroid Build Coastguard Worker	for _, p := range props {
185*1fa6dee9SAndroid Build Coastguard Worker		actual = append(actual, p.Name)
186*1fa6dee9SAndroid Build Coastguard Worker		actual = append(actual, actualProperties(t, p.Properties)...)
187*1fa6dee9SAndroid Build Coastguard Worker	}
188*1fa6dee9SAndroid Build Coastguard Worker	return actual
189*1fa6dee9SAndroid Build Coastguard Worker}
190