xref: /aosp_15_r20/build/blueprint/bpmodify/cmd/main_test.go (revision 1fa6dee971e1612fa5cc0aa5ca2d35a22e2c34a3)
1// Copyright 2024 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	"bytes"
19	"strings"
20	"testing"
21
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	addLiteral      *string
33	setString       *string
34	setBool         *string
35	removeProperty  bool
36	replaceProperty string
37	moveProperty    bool
38	newLocation     string
39}{
40	{
41		name: "add",
42		input: `
43			cc_foo {
44				name: "foo",
45			}
46		`,
47		output: `
48			cc_foo {
49				name: "foo",
50				deps: ["bar"],
51			}
52		`,
53		property: "deps",
54		addSet:   "bar",
55	},
56	{
57		name: "remove",
58		input: `
59			cc_foo {
60				name: "foo",
61				deps: ["bar"],
62			}
63		`,
64		output: `
65			cc_foo {
66				name: "foo",
67				deps: [],
68			}
69		`,
70		property:  "deps",
71		removeSet: "bar",
72	},
73	{
74		name: "nested add",
75		input: `
76			cc_foo {
77				name: "foo",
78			}
79		`,
80		output: `
81			cc_foo {
82				name: "foo",
83				arch: {
84					arm: {
85						deps: [
86							"dep2",
87							"nested_dep",],
88					},
89				},
90			}
91		`,
92		property: "arch.arm.deps",
93		addSet:   "nested_dep,dep2",
94	},
95	{
96		name: "nested remove",
97		input: `
98			cc_foo {
99				name: "foo",
100				arch: {
101					arm: {
102						deps: [
103							"dep2",
104							"nested_dep",
105						],
106					},
107				},
108			}
109		`,
110		output: `
111			cc_foo {
112				name: "foo",
113				arch: {
114					arm: {
115						deps: [
116						],
117					},
118				},
119			}
120		`,
121		property:  "arch.arm.deps",
122		removeSet: "nested_dep,dep2",
123	},
124	{
125		name: "add existing",
126		input: `
127			cc_foo {
128				name: "foo",
129				arch: {
130					arm: {
131						deps: [
132							"nested_dep",
133							"dep2",
134						],
135					},
136				},
137			}
138		`,
139		output: `
140			cc_foo {
141				name: "foo",
142				arch: {
143					arm: {
144						deps: [
145							"nested_dep",
146							"dep2",
147						],
148					},
149				},
150			}
151		`,
152		property: "arch.arm.deps",
153		addSet:   "dep2,dep2",
154	},
155	{
156		name: "remove missing",
157		input: `
158			cc_foo {
159				name: "foo",
160				arch: {
161					arm: {
162						deps: [
163							"nested_dep",
164							"dep2",
165						],
166					},
167				},
168			}
169		`,
170		output: `
171			cc_foo {
172				name: "foo",
173				arch: {
174					arm: {
175						deps: [
176							"nested_dep",
177							"dep2",
178						],
179					},
180				},
181			}
182		`,
183		property:  "arch.arm.deps",
184		removeSet: "dep3,dep4",
185	},
186	{
187		name: "remove non existent",
188		input: `
189			cc_foo {
190				name: "foo",
191			}
192		`,
193		output: `
194			cc_foo {
195				name: "foo",
196			}
197		`,
198		property:  "deps",
199		removeSet: "bar",
200	},
201	{
202		name: "remove non existent nested",
203		input: `
204			cc_foo {
205				name: "foo",
206				arch: {},
207			}
208		`,
209		output: `
210			cc_foo {
211				name: "foo",
212				arch: {},
213			}
214		`,
215		property:  "arch.arm.deps",
216		removeSet: "dep3,dep4",
217	},
218	{
219		name: "add numeric sorted",
220		input: `
221			cc_foo {
222				name: "foo",
223				versions: ["1", "2"],
224			}
225		`,
226		output: `
227			cc_foo {
228				name: "foo",
229				versions: [
230					"1",
231					"2",
232					"10",
233				],
234			}
235		`,
236		property: "versions",
237		addSet:   "10",
238	},
239	{
240		name: "add mixed sorted",
241		input: `
242			cc_foo {
243				name: "foo",
244				deps: ["bar-v1-bar", "bar-v2-bar"],
245			}
246		`,
247		output: `
248			cc_foo {
249				name: "foo",
250				deps: [
251					"bar-v1-bar",
252					"bar-v2-bar",
253					"bar-v10-bar",
254				],
255			}
256		`,
257		property: "deps",
258		addSet:   "bar-v10-bar",
259	},
260	{
261		name:  "add a struct with literal",
262		input: `cc_foo {name: "foo"}`,
263		output: `cc_foo {
264    name: "foo",
265    structs: [
266        {
267            version: "1",
268            imports: [
269                "bar1",
270                "bar2",
271            ],
272        },
273    ],
274}
275`,
276		property:   "structs",
277		addLiteral: proptools.StringPtr(`{version: "1", imports: ["bar1", "bar2"]}`),
278	},
279	{
280		name: "set string",
281		input: `
282			cc_foo {
283				name: "foo",
284			}
285		`,
286		output: `
287			cc_foo {
288				name: "foo",
289				foo: "bar",
290			}
291		`,
292		property:  "foo",
293		setString: proptools.StringPtr("bar"),
294	},
295	{
296		name: "set existing string",
297		input: `
298			cc_foo {
299				name: "foo",
300				foo: "baz",
301			}
302		`,
303		output: `
304			cc_foo {
305				name: "foo",
306				foo: "bar",
307			}
308		`,
309		property:  "foo",
310		setString: proptools.StringPtr("bar"),
311	},
312	{
313		name: "set bool",
314		input: `
315			cc_foo {
316				name: "foo",
317			}
318		`,
319		output: `
320			cc_foo {
321				name: "foo",
322				foo: true,
323			}
324		`,
325		property: "foo",
326		setBool:  proptools.StringPtr("true"),
327	},
328	{
329		name: "set existing bool",
330		input: `
331			cc_foo {
332				name: "foo",
333				foo: true,
334			}
335		`,
336		output: `
337			cc_foo {
338				name: "foo",
339				foo: false,
340			}
341		`,
342		property: "foo",
343		setBool:  proptools.StringPtr("false"),
344	},
345	{
346		name: "remove existing property",
347		input: `
348			cc_foo {
349				name: "foo",
350				foo: "baz",
351			}
352		`,
353		output: `
354			cc_foo {
355				name: "foo",
356			}
357		`,
358		property:       "foo",
359		removeProperty: true,
360	}, {
361		name: "remove nested property",
362		input: `
363		cc_foo {
364			name: "foo",
365			foo: {
366				bar: "baz",
367			},
368		}
369	`,
370		output: `
371		cc_foo {
372			name: "foo",
373			foo: {},
374		}
375	`,
376		property:       "foo.bar",
377		removeProperty: true,
378	}, {
379		name: "remove non-existing property",
380		input: `
381			cc_foo {
382				name: "foo",
383				foo: "baz",
384			}
385		`,
386		output: `
387			cc_foo {
388				name: "foo",
389				foo: "baz",
390			}
391		`,
392		property:       "bar",
393		removeProperty: true,
394	}, {
395		name:     "replace property",
396		property: "deps",
397		input: `
398			cc_foo {
399				name: "foo",
400				deps: ["baz", "unchanged"],
401			}
402		`,
403		output: `
404			cc_foo {
405				name: "foo",
406				deps: [
407                "baz_lib",
408                "unchanged",
409				],
410			}
411		`,
412		replaceProperty: "baz=baz_lib,foobar=foobar_lib",
413	}, {
414		name:     "replace property multiple modules",
415		property: "deps,required",
416		input: `
417			cc_foo {
418				name: "foo",
419				deps: ["baz", "unchanged"],
420				unchanged: ["baz"],
421				required: ["foobar"],
422			}
423		`,
424		output: `
425			cc_foo {
426				name: "foo",
427				deps: [
428								"baz_lib",
429								"unchanged",
430				],
431				unchanged: ["baz"],
432				required: ["foobar_lib"],
433			}
434		`,
435		replaceProperty: "baz=baz_lib,foobar=foobar_lib",
436	}, {
437		name:     "replace property string value",
438		property: "name",
439		input: `
440			cc_foo {
441				name: "foo",
442				deps: ["baz"],
443				unchanged: ["baz"],
444				required: ["foobar"],
445			}
446		`,
447		output: `
448			cc_foo {
449				name: "foo_lib",
450				deps: ["baz"],
451				unchanged: ["baz"],
452				required: ["foobar"],
453			}
454		`,
455		replaceProperty: "foo=foo_lib",
456	}, {
457		name:     "replace property string and list values",
458		property: "name,deps",
459		input: `
460			cc_foo {
461				name: "foo",
462				deps: ["baz"],
463				unchanged: ["baz"],
464				required: ["foobar"],
465			}
466		`,
467		output: `
468			cc_foo {
469				name: "foo_lib",
470				deps: ["baz_lib"],
471				unchanged: ["baz"],
472				required: ["foobar"],
473			}
474		`,
475		replaceProperty: "foo=foo_lib,baz=baz_lib",
476	}, {
477		name: "move contents of property into non-existing property",
478		input: `
479			cc_foo {
480				name: "foo",
481				bar: ["barContents"],
482				}
483`,
484		output: `
485			cc_foo {
486				name: "foo",
487				baz: ["barContents"],
488			}
489		`,
490		property:     "bar",
491		moveProperty: true,
492		newLocation:  "baz",
493	}, {
494		name: "move contents of property into existing property",
495		input: `
496			cc_foo {
497				name: "foo",
498				baz: ["bazContents"],
499				bar: ["barContents"],
500			}
501		`,
502		output: `
503			cc_foo {
504				name: "foo",
505				baz: [
506					"bazContents",
507					"barContents",
508				],
509
510			}
511		`,
512		property:     "bar",
513		moveProperty: true,
514		newLocation:  "baz",
515	}, {
516		name: "replace nested",
517		input: `
518		cc_foo {
519			name: "foo",
520			foo: {
521				bar: "baz",
522			},
523		}
524	`,
525		output: `
526		cc_foo {
527			name: "foo",
528			foo: {
529				bar: "baz2",
530			},
531		}
532	`,
533		property:        "foo.bar",
534		replaceProperty: "baz=baz2",
535	},
536}
537
538func simplifyModuleDefinition(def string) string {
539	var result string
540	for _, line := range strings.Split(def, "\n") {
541		result += strings.TrimSpace(line)
542	}
543	return result
544}
545func TestProcessModule(t *testing.T) {
546	for _, testCase := range testCases {
547		t.Run(testCase.name, func(t *testing.T) {
548			targetedProperties.Set(testCase.property)
549			addIdents.Set(testCase.addSet)
550			removeIdents.Set(testCase.removeSet)
551			removeProperty = &testCase.removeProperty
552			moveProperty = &testCase.moveProperty
553			newLocation = testCase.newLocation
554			setString = testCase.setString
555			setBool = testCase.setBool
556			addLiteral = testCase.addLiteral
557			replaceProperty.Set(testCase.replaceProperty)
558
559			targetedModules.Set("foo")
560
561			out := &bytes.Buffer{}
562			err := processFile("", strings.NewReader(testCase.input), out)
563			if err != nil {
564				t.Fatalf("unexpected error: %s", err.Error())
565			}
566			if simplifyModuleDefinition(out.String()) != simplifyModuleDefinition(testCase.output) {
567				t.Errorf("expected module definition:")
568				t.Errorf("  %s", testCase.output)
569				t.Errorf("actual module definition:")
570				t.Errorf("  %s", out.String())
571			}
572		})
573	}
574}
575
576func TestReplacementsCycleError(t *testing.T) {
577	cycleString := "old1=new1,new1=old1"
578	err := replaceProperty.Set(cycleString)
579
580	if err.Error() != "Duplicated replacement name new1" {
581		t.Errorf("Error message did not match")
582		t.Errorf("Expected ")
583		t.Errorf(" Duplicated replacement name new1")
584		t.Errorf("actual error:")
585		t.Errorf("  %s", err.Error())
586		t.FailNow()
587	}
588}
589
590func TestReplacementsDuplicatedError(t *testing.T) {
591	cycleString := "a=b,a=c"
592	err := replaceProperty.Set(cycleString)
593
594	if err.Error() != "Duplicated replacement name a" {
595		t.Errorf("Error message did not match")
596		t.Errorf("Expected ")
597		t.Errorf(" Duplicated replacement name a")
598		t.Errorf("actual error:")
599		t.Errorf("  %s", err.Error())
600		t.FailNow()
601	}
602}
603
604func TestReplacementsMultipleReplacedToSame(t *testing.T) {
605	cycleString := "a=c,d=c"
606	err := replaceProperty.Set(cycleString)
607
608	if err.Error() != "Duplicated replacement name c" {
609		t.Errorf("Error message did not match")
610		t.Errorf("Expected ")
611		t.Errorf(" Duplicated replacement name c")
612		t.Errorf("actual error:")
613		t.Errorf("  %s", err.Error())
614		t.FailNow()
615	}
616}
617