1// Copyright 2020 Google Inc. All rights reserved.
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 main
16
17import (
18	"strings"
19	"testing"
20
21	"github.com/google/blueprint/parser"
22	"github.com/google/blueprint/proptools"
23)
24
25var testCases = []struct {
26	name      string
27	input     string
28	output    string
29	property  string
30	addSet    string
31	removeSet string
32	setString *string
33}{
34	{
35		name: "add",
36		input: `
37			cc_foo {
38				name: "foo",
39			}
40		`,
41		output: `
42			cc_foo {
43				name: "foo",
44				deps: ["bar"],
45			}
46		`,
47		property: "deps",
48		addSet:   "bar",
49	},
50	{
51		name: "remove",
52		input: `
53			cc_foo {
54				name: "foo",
55				deps: ["bar"],
56			}
57		`,
58		output: `
59			cc_foo {
60				name: "foo",
61				deps: [],
62			}
63		`,
64		property:  "deps",
65		removeSet: "bar",
66	},
67	{
68		name: "nested add",
69		input: `
70			cc_foo {
71				name: "foo",
72			}
73		`,
74		output: `
75			cc_foo {
76				name: "foo",
77				arch: {
78					arm: {
79						deps: [
80							"dep2",
81							"nested_dep",],
82					},
83				},
84			}
85		`,
86		property: "arch.arm.deps",
87		addSet:   "nested_dep,dep2",
88	},
89	{
90		name: "nested remove",
91		input: `
92			cc_foo {
93				name: "foo",
94				arch: {
95					arm: {
96						deps: [
97							"dep2",
98							"nested_dep",
99						],
100					},
101				},
102			}
103		`,
104		output: `
105			cc_foo {
106				name: "foo",
107				arch: {
108					arm: {
109						deps: [
110						],
111					},
112				},
113			}
114		`,
115		property:  "arch.arm.deps",
116		removeSet: "nested_dep,dep2",
117	},
118	{
119		name: "add existing",
120		input: `
121			cc_foo {
122				name: "foo",
123				arch: {
124					arm: {
125						deps: [
126							"nested_dep",
127							"dep2",
128						],
129					},
130				},
131			}
132		`,
133		output: `
134			cc_foo {
135				name: "foo",
136				arch: {
137					arm: {
138						deps: [
139							"nested_dep",
140							"dep2",
141						],
142					},
143				},
144			}
145		`,
146		property: "arch.arm.deps",
147		addSet:   "dep2,dep2",
148	},
149	{
150		name: "remove missing",
151		input: `
152			cc_foo {
153				name: "foo",
154				arch: {
155					arm: {
156						deps: [
157							"nested_dep",
158							"dep2",
159						],
160					},
161				},
162			}
163		`,
164		output: `
165			cc_foo {
166				name: "foo",
167				arch: {
168					arm: {
169						deps: [
170							"nested_dep",
171							"dep2",
172						],
173					},
174				},
175			}
176		`,
177		property:  "arch.arm.deps",
178		removeSet: "dep3,dep4",
179	},
180	{
181		name: "remove non existent",
182		input: `
183			cc_foo {
184				name: "foo",
185			}
186		`,
187		output: `
188			cc_foo {
189				name: "foo",
190			}
191		`,
192		property:  "deps",
193		removeSet: "bar",
194	},
195	{
196		name: "remove non existent nested",
197		input: `
198			cc_foo {
199				name: "foo",
200				arch: {},
201			}
202		`,
203		output: `
204			cc_foo {
205				name: "foo",
206				arch: {},
207			}
208		`,
209		property:  "arch.arm.deps",
210		removeSet: "dep3,dep4",
211	},
212	{
213		name: "add numeric sorted",
214		input: `
215			cc_foo {
216				name: "foo",
217				versions: ["1", "2"],
218			}
219		`,
220		output: `
221			cc_foo {
222				name: "foo",
223				versions: [
224					"1",
225					"2",
226					"10",
227				],
228			}
229		`,
230		property: "versions",
231		addSet:   "10",
232	},
233	{
234		name: "add mixed sorted",
235		input: `
236			cc_foo {
237				name: "foo",
238				deps: ["bar-v1-bar", "bar-v2-bar"],
239			}
240		`,
241		output: `
242			cc_foo {
243				name: "foo",
244				deps: [
245					"bar-v1-bar",
246					"bar-v2-bar",
247					"bar-v10-bar",
248				],
249			}
250		`,
251		property: "deps",
252		addSet:   "bar-v10-bar",
253	},
254	{
255		name: "set string",
256		input: `
257			cc_foo {
258				name: "foo",
259			}
260		`,
261		output: `
262			cc_foo {
263				name: "foo",
264				foo: "bar",
265			}
266		`,
267		property:  "foo",
268		setString: proptools.StringPtr("bar"),
269	},
270	{
271		name: "set existing string",
272		input: `
273			cc_foo {
274				name: "foo",
275				foo: "baz",
276			}
277		`,
278		output: `
279			cc_foo {
280				name: "foo",
281				foo: "bar",
282			}
283		`,
284		property:  "foo",
285		setString: proptools.StringPtr("bar"),
286	},
287}
288
289func simplifyModuleDefinition(def string) string {
290	var result string
291	for _, line := range strings.Split(def, "\n") {
292		result += strings.TrimSpace(line)
293	}
294	return result
295}
296
297func TestProcessModule(t *testing.T) {
298	for i, testCase := range testCases {
299		t.Run(testCase.name, func(t *testing.T) {
300			targetedProperty.Set(testCase.property)
301			addIdents.Set(testCase.addSet)
302			removeIdents.Set(testCase.removeSet)
303			setString = testCase.setString
304
305			inAst, errs := parser.ParseAndEval("", strings.NewReader(testCase.input), parser.NewScope(nil))
306			if len(errs) > 0 {
307				for _, err := range errs {
308					t.Errorf("  %s", err)
309				}
310				t.Errorf("failed to parse:")
311				t.Errorf("%+v", testCase)
312				t.FailNow()
313			}
314
315			if inModule, ok := inAst.Defs[0].(*parser.Module); !ok {
316				t.Fatalf("  input must only contain a single module definition: %s", testCase.input)
317			} else {
318				_, errs := processModule(inModule, "", inAst)
319				if len(errs) > 0 {
320					t.Errorf("test case %d:", i)
321					for _, err := range errs {
322						t.Errorf("  %s", err)
323					}
324				}
325				inModuleText, _ := parser.Print(inAst)
326				inModuleString := string(inModuleText)
327				if simplifyModuleDefinition(inModuleString) != simplifyModuleDefinition(testCase.output) {
328					t.Errorf("test case %d:", i)
329					t.Errorf("expected module definition:")
330					t.Errorf("  %s", testCase.output)
331					t.Errorf("actual module definition:")
332					t.Errorf("  %s", inModuleString)
333				}
334			}
335		})
336	}
337
338}
339