1// Copyright 2014 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 parser
16
17import (
18	"bytes"
19	"testing"
20)
21
22var validPrinterTestCases = []struct {
23	name   string
24	input  string
25	output string
26}{
27	{
28		input: `
29foo {}
30`,
31		output: `
32foo {}
33`,
34	},
35	{
36		input: `
37foo(name= "abc",num= 4,)
38`,
39		output: `
40foo {
41    name: "abc",
42    num: 4,
43}
44`,
45	},
46	{
47		input: `
48			foo {
49				stuff: ["asdf", "jkl;", "qwert",
50					"uiop", "bnm,"]
51			}
52			`,
53		output: `
54foo {
55    stuff: [
56        "asdf",
57        "bnm,",
58        "jkl;",
59        "qwert",
60        "uiop",
61    ],
62}
63`,
64	},
65	{
66		input: `
67		        var = "asdf"
68			foo {
69				stuff: ["asdf"] + var,
70			}`,
71		output: `
72var = "asdf"
73foo {
74    stuff: ["asdf"] + var,
75}
76`,
77	},
78	{
79		input: `
80		        var = "asdf"
81			foo {
82				stuff: [
83				    "asdf"
84				] + var,
85			}`,
86		output: `
87var = "asdf"
88foo {
89    stuff: [
90        "asdf",
91    ] + var,
92}
93`,
94	},
95	{
96		input: `
97		        var = "asdf"
98			foo {
99				stuff: ["asdf"] + var + ["qwert"],
100			}`,
101		output: `
102var = "asdf"
103foo {
104    stuff: ["asdf"] + var + ["qwert"],
105}
106`,
107	},
108	{
109		input: `
110		foo {
111			stuff: {
112				isGood: true,
113				name: "bar",
114				num: 4,
115			}
116		}
117		`,
118		output: `
119foo {
120    stuff: {
121        isGood: true,
122        name: "bar",
123        num: 4,
124    },
125}
126`,
127	},
128	{
129		input: `
130// comment1
131foo {
132	// comment2
133	isGood: true,  // comment3
134}
135`,
136		output: `
137// comment1
138foo {
139    // comment2
140    isGood: true, // comment3
141}
142`,
143	},
144	{
145		input: `
146foo {
147	name: "abc",
148	num: 4,
149}
150
151bar  {
152	name: "def",
153	num: 5,
154}
155		`,
156		output: `
157foo {
158    name: "abc",
159    num: 4,
160}
161
162bar {
163    name: "def",
164    num: 5,
165}
166`,
167	},
168	{
169		input: `
170foo {
171    bar: "b" +
172        "a" +
173	"z",
174}
175`,
176		output: `
177foo {
178    bar: "b" +
179        "a" +
180        "z",
181}
182`,
183	},
184	{
185		input: `
186foo = "stuff"
187bar = foo
188baz = foo + bar
189baz += foo
190`,
191		output: `
192foo = "stuff"
193bar = foo
194baz = foo + bar
195baz += foo
196`,
197	},
198	{
199		input: `
200foo = 100
201bar = foo
202baz = foo + bar
203baz += foo
204`,
205		output: `
206foo = 100
207bar = foo
208baz = foo + bar
209baz += foo
210`,
211	},
212	{
213		input: `
214foo = "bar " +
215    "" +
216    "baz"
217`,
218		output: `
219foo = "bar " +
220    "" +
221    "baz"
222`,
223	},
224	{
225		input: `
226//test
227test /* test */ {
228    srcs: [
229        /*"bootstrap/bootstrap.go",
230    "bootstrap/cleanup.go",*/
231        "bootstrap/command.go",
232        "bootstrap/doc.go", //doc.go
233        "bootstrap/config.go", //config.go
234    ],
235    deps: ["libabc"],
236    incs: []
237} //test
238//test
239test2 {
240}
241
242
243//test3
244`,
245		output: `
246//test
247test /* test */ {
248    srcs: [
249        /*"bootstrap/bootstrap.go",
250        "bootstrap/cleanup.go",*/
251        "bootstrap/command.go",
252        "bootstrap/config.go", //config.go
253        "bootstrap/doc.go", //doc.go
254    ],
255    deps: ["libabc"],
256    incs: [],
257} //test
258//test
259
260test2 {
261}
262
263//test3
264`,
265	},
266	{
267		input: `
268// test
269module // test
270
271 {
272    srcs
273   : [
274        "src1.c",
275        "src2.c",
276    ],
277//test
278}
279//test2
280`,
281		output: `
282// test
283module { // test
284    srcs: [
285        "src1.c",
286        "src2.c",
287    ],
288    //test
289}
290
291//test2
292`,
293	},
294	{
295		input: `
296/*test {
297    test: true,
298}*/
299
300test {
301/*test: true,*/
302}
303
304// This
305/* Is *//* A */ // A
306// A
307
308// Multiline
309// Comment
310
311test {}
312
313// This
314/* Is */
315// A
316// Trailing
317
318// Multiline
319// Comment
320`,
321		output: `
322/*test {
323    test: true,
324}*/
325
326test {
327    /*test: true,*/
328}
329
330// This
331/* Is */ /* A */ // A
332// A
333
334// Multiline
335// Comment
336
337test {}
338
339// This
340/* Is */
341// A
342// Trailing
343
344// Multiline
345// Comment
346`,
347	},
348	{
349		input: `
350test // test
351
352// test
353{
354}
355`,
356		output: `
357test { // test
358// test
359}
360`,
361	},
362	{
363		input: `
364// test
365stuff {
366    namespace: "google",
367    string_vars: [
368      {
369          var: "one",
370          values: [ "one_a", "one_b",],
371      },
372      {
373          var: "two",
374          values: [ "two_a", "two_b", ],
375      },
376    ],
377}`,
378		output: `
379// test
380stuff {
381    namespace: "google",
382    string_vars: [
383        {
384            var: "one",
385            values: [
386                "one_a",
387                "one_b",
388            ],
389        },
390        {
391            var: "two",
392            values: [
393                "two_a",
394                "two_b",
395            ],
396        },
397    ],
398}
399`,
400	},
401	{
402		input: `
403// test
404stuff {
405    namespace: "google",
406    list_of_lists: [
407        [ "a", "b" ],
408        [ "c", "d" ],
409    ],
410}
411`,
412		output: `
413// test
414stuff {
415    namespace: "google",
416    list_of_lists: [
417        [
418            "a",
419            "b",
420        ],
421        [
422            "c",
423            "d",
424        ],
425    ],
426}
427`,
428	},
429	{
430		input: `
431// test
432stuff {
433    namespace: "google",
434    list_of_structs: [{ key1: "a", key2: "b" }],
435}
436`,
437		output: `
438// test
439stuff {
440    namespace: "google",
441    list_of_structs: [
442        {
443            key1: "a",
444            key2: "b",
445        },
446    ],
447}
448`,
449	},
450	{
451		input: `
452// test
453foo {
454    stuff: [
455        "a", // great comment
456        "b",
457    ],
458}
459`,
460		output: `
461// test
462foo {
463    stuff: [
464        "a", // great comment
465        "b",
466    ],
467}
468`,
469	},
470	{
471		input: `
472// test
473foo {
474    stuff: [
475        "a",
476        // b comment
477        "b",
478    ],
479}
480`,
481		output: `
482// test
483foo {
484    stuff: [
485        "a",
486        // b comment
487        "b",
488    ],
489}
490`,
491	},
492	{
493		input: `
494// test
495foo {
496    stuff: [
497        "a", // a comment
498        // b comment
499        "b",
500    ],
501}
502`,
503		output: `
504// test
505foo {
506    stuff: [
507        "a", // a comment
508        // b comment
509        "b",
510    ],
511}
512`,
513	},
514	{
515		input: `
516// test
517foo {
518    stuff: [
519        "a",
520        // b comment
521        // on multiline
522        "b",
523    ],
524}
525`,
526		output: `
527// test
528foo {
529    stuff: [
530        "a",
531        // b comment
532        // on multiline
533        "b",
534    ],
535}
536`,
537	},
538	{ // Line comment are treat as groups separator
539		input: `
540// test
541foo {
542    stuff: [
543        "b",
544        // a comment
545        "a",
546    ],
547}
548`,
549		output: `
550// test
551foo {
552    stuff: [
553        "b",
554        // a comment
555        "a",
556    ],
557}
558`,
559	},
560	{
561		name: "Basic selects",
562		input: `
563// test
564foo {
565    stuff: select(soong_config_variable("my_namespace", "my_variable"), {
566        "a": "a2",
567        // test2
568        "b": "b2",
569        // test3
570        default: "c2",
571    }),
572}
573`,
574		output: `
575// test
576foo {
577    stuff: select(soong_config_variable("my_namespace", "my_variable"), {
578        "a": "a2",
579        // test2
580        "b": "b2",
581        // test3
582        default: "c2",
583    }),
584}
585`,
586	},
587	{
588		name: "Remove select with only default",
589		input: `
590// test
591foo {
592    stuff: select(soong_config_variable("my_namespace", "my_variable"), {
593        // test2
594        default: "c2",
595    }),
596}
597`,
598		output: `
599// test
600foo {
601    stuff: "c2", // test2
602}
603`,
604	},
605	{
606		name: "Appended selects",
607		input: `
608// test
609foo {
610    stuff: select(soong_config_variable("my_namespace", "my_variable"), {
611        "a": "a2",
612        // test2
613        "b": "b2",
614        // test3
615        default: "c2",
616    }) + select(release_variable("RELEASE_TEST"), {
617        "d": "d2",
618        "e": "e2",
619        default: "f2",
620    }),
621}
622`,
623		output: `
624// test
625foo {
626    stuff: select(soong_config_variable("my_namespace", "my_variable"), {
627        "a": "a2",
628        // test2
629        "b": "b2",
630        // test3
631        default: "c2",
632    }) + select(release_variable("RELEASE_TEST"), {
633        "d": "d2",
634        "e": "e2",
635        default: "f2",
636    }),
637}
638`,
639	},
640	{
641		name: "Select with unset property",
642		input: `
643foo {
644    stuff: select(soong_config_variable("my_namespace", "my_variable"), {
645        "foo": unset,
646        default: "c2",
647    }),
648}
649`,
650		output: `
651foo {
652    stuff: select(soong_config_variable("my_namespace", "my_variable"), {
653        "foo": unset,
654        default: "c2",
655    }),
656}
657`,
658	},
659	{
660		name: "Multi-condition select",
661		input: `
662foo {
663    stuff: select((arch(), os()), {
664        ("x86", "linux"): "a",
665        (default, default): "b",
666    }),
667}
668`,
669		output: `
670foo {
671    stuff: select((arch(), os()), {
672        ("x86", "linux"): "a",
673        (default, default): "b",
674    }),
675}
676`,
677	},
678	{
679		name: "Multi-condition select with conditions on new lines",
680		input: `
681foo {
682    stuff: select((arch(),
683    os()), {
684        ("x86", "linux"): "a",
685        (default, default): "b",
686    }),
687}
688`,
689		output: `
690foo {
691    stuff: select((
692        arch(),
693        os(),
694    ), {
695        ("x86", "linux"): "a",
696        (default, default): "b",
697    }),
698}
699`,
700	},
701	{
702		name: "Select with multiline inner expression",
703		input: `
704foo {
705    cflags: [
706        "-DPRODUCT_COMPATIBLE_PROPERTY",
707        "-DRIL_SHLIB",
708        "-Wall",
709        "-Wextra",
710        "-Werror",
711    ] + select(soong_config_variable("sim", "sim_count"), {
712        "2": [
713            "-DANDROID_MULTI_SIM",
714            "-DANDROID_SIM_COUNT_2",
715        ],
716        default: [],
717    }),
718}
719`,
720		output: `
721foo {
722    cflags: [
723        "-DPRODUCT_COMPATIBLE_PROPERTY",
724        "-DRIL_SHLIB",
725        "-Wall",
726        "-Werror",
727        "-Wextra",
728    ] + select(soong_config_variable("sim", "sim_count"), {
729        "2": [
730            "-DANDROID_MULTI_SIM",
731            "-DANDROID_SIM_COUNT_2",
732        ],
733        default: [],
734    }),
735}
736`,
737	},
738}
739
740func TestPrinter(t *testing.T) {
741	for _, testCase := range validPrinterTestCases {
742		t.Run(testCase.name, func(t *testing.T) {
743			in := testCase.input[1:]
744			expected := testCase.output[1:]
745
746			r := bytes.NewBufferString(in)
747			file, errs := Parse("", r, NewScope(nil))
748			if len(errs) != 0 {
749				t.Errorf("test case: %s", in)
750				t.Errorf("unexpected errors:")
751				for _, err := range errs {
752					t.Errorf("  %s", err)
753				}
754				t.FailNow()
755			}
756
757			SortLists(file)
758
759			got, err := Print(file)
760			if err != nil {
761				t.Errorf("test case: %s", in)
762				t.Errorf("unexpected error: %s", err)
763				t.FailNow()
764			}
765
766			if string(got) != expected {
767				t.Errorf("test case: %s", in)
768				t.Errorf("  expected: %s", expected)
769				t.Errorf("       got: %s", string(got))
770			}
771		})
772	}
773}
774