• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 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 android
16
17import (
18	"errors"
19	"fmt"
20	"io/ioutil"
21	"os"
22	"reflect"
23	"strings"
24	"testing"
25
26	"github.com/google/blueprint/pathtools"
27	"github.com/google/blueprint/proptools"
28)
29
30type strsTestCase struct {
31	in  []string
32	out string
33	err []error
34}
35
36var commonValidatePathTestCases = []strsTestCase{
37	{
38		in:  []string{""},
39		out: "",
40	},
41	{
42		in:  []string{"a/b"},
43		out: "a/b",
44	},
45	{
46		in:  []string{"a/b", "c"},
47		out: "a/b/c",
48	},
49	{
50		in:  []string{"a/.."},
51		out: ".",
52	},
53	{
54		in:  []string{"."},
55		out: ".",
56	},
57	{
58		in:  []string{".."},
59		out: "",
60		err: []error{errors.New("Path is outside directory: ..")},
61	},
62	{
63		in:  []string{"../a"},
64		out: "",
65		err: []error{errors.New("Path is outside directory: ../a")},
66	},
67	{
68		in:  []string{"b/../../a"},
69		out: "",
70		err: []error{errors.New("Path is outside directory: ../a")},
71	},
72	{
73		in:  []string{"/a"},
74		out: "",
75		err: []error{errors.New("Path is outside directory: /a")},
76	},
77	{
78		in:  []string{"a", "../b"},
79		out: "",
80		err: []error{errors.New("Path is outside directory: ../b")},
81	},
82	{
83		in:  []string{"a", "b/../../c"},
84		out: "",
85		err: []error{errors.New("Path is outside directory: ../c")},
86	},
87	{
88		in:  []string{"a", "./.."},
89		out: "",
90		err: []error{errors.New("Path is outside directory: ..")},
91	},
92}
93
94var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
95	{
96		in:  []string{"$host/../$a"},
97		out: "$a",
98	},
99}...)
100
101var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
102	{
103		in:  []string{"$host/../$a"},
104		out: "",
105		err: []error{errors.New("Path contains invalid character($): $host/../$a")},
106	},
107	{
108		in:  []string{"$host/.."},
109		out: "",
110		err: []error{errors.New("Path contains invalid character($): $host/..")},
111	},
112}...)
113
114func TestValidateSafePath(t *testing.T) {
115	for _, testCase := range validateSafePathTestCases {
116		t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
117			ctx := &configErrorWrapper{}
118			out, err := validateSafePath(testCase.in...)
119			if err != nil {
120				reportPathError(ctx, err)
121			}
122			check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
123		})
124	}
125}
126
127func TestValidatePath(t *testing.T) {
128	for _, testCase := range validatePathTestCases {
129		t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
130			ctx := &configErrorWrapper{}
131			out, err := validatePath(testCase.in...)
132			if err != nil {
133				reportPathError(ctx, err)
134			}
135			check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
136		})
137	}
138}
139
140func TestOptionalPath(t *testing.T) {
141	var path OptionalPath
142	checkInvalidOptionalPath(t, path)
143
144	path = OptionalPathForPath(nil)
145	checkInvalidOptionalPath(t, path)
146}
147
148func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
149	t.Helper()
150	if path.Valid() {
151		t.Errorf("Uninitialized OptionalPath should not be valid")
152	}
153	if path.String() != "" {
154		t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
155	}
156	defer func() {
157		if r := recover(); r == nil {
158			t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
159		}
160	}()
161	path.Path()
162}
163
164func check(t *testing.T, testType, testString string,
165	got interface{}, err []error,
166	expected interface{}, expectedErr []error) {
167	t.Helper()
168
169	printedTestCase := false
170	e := func(s string, expected, got interface{}) {
171		t.Helper()
172		if !printedTestCase {
173			t.Errorf("test case %s: %s", testType, testString)
174			printedTestCase = true
175		}
176		t.Errorf("incorrect %s", s)
177		t.Errorf("  expected: %s", p(expected))
178		t.Errorf("       got: %s", p(got))
179	}
180
181	if !reflect.DeepEqual(expectedErr, err) {
182		e("errors:", expectedErr, err)
183	}
184
185	if !reflect.DeepEqual(expected, got) {
186		e("output:", expected, got)
187	}
188}
189
190func p(in interface{}) string {
191	if v, ok := in.([]interface{}); ok {
192		s := make([]string, len(v))
193		for i := range v {
194			s[i] = fmt.Sprintf("%#v", v[i])
195		}
196		return "[" + strings.Join(s, ", ") + "]"
197	} else {
198		return fmt.Sprintf("%#v", in)
199	}
200}
201
202type moduleInstallPathContextImpl struct {
203	androidBaseContextImpl
204
205	inData         bool
206	inSanitizerDir bool
207	inRecovery     bool
208}
209
210func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
211	return pathtools.MockFs(nil)
212}
213
214func (m moduleInstallPathContextImpl) Config() Config {
215	return m.androidBaseContextImpl.config
216}
217
218func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
219
220func (m moduleInstallPathContextImpl) InstallInData() bool {
221	return m.inData
222}
223
224func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
225	return m.inSanitizerDir
226}
227
228func (m moduleInstallPathContextImpl) InstallInRecovery() bool {
229	return m.inRecovery
230}
231
232func TestPathForModuleInstall(t *testing.T) {
233	testConfig := TestConfig("", nil)
234
235	hostTarget := Target{Os: Linux}
236	deviceTarget := Target{Os: Android}
237
238	testCases := []struct {
239		name string
240		ctx  *moduleInstallPathContextImpl
241		in   []string
242		out  string
243	}{
244		{
245			name: "host binary",
246			ctx: &moduleInstallPathContextImpl{
247				androidBaseContextImpl: androidBaseContextImpl{
248					target: hostTarget,
249				},
250			},
251			in:  []string{"bin", "my_test"},
252			out: "host/linux-x86/bin/my_test",
253		},
254
255		{
256			name: "system binary",
257			ctx: &moduleInstallPathContextImpl{
258				androidBaseContextImpl: androidBaseContextImpl{
259					target: deviceTarget,
260				},
261			},
262			in:  []string{"bin", "my_test"},
263			out: "target/product/test_device/system/bin/my_test",
264		},
265		{
266			name: "vendor binary",
267			ctx: &moduleInstallPathContextImpl{
268				androidBaseContextImpl: androidBaseContextImpl{
269					target: deviceTarget,
270					kind:   socSpecificModule,
271				},
272			},
273			in:  []string{"bin", "my_test"},
274			out: "target/product/test_device/vendor/bin/my_test",
275		},
276		{
277			name: "odm binary",
278			ctx: &moduleInstallPathContextImpl{
279				androidBaseContextImpl: androidBaseContextImpl{
280					target: deviceTarget,
281					kind:   deviceSpecificModule,
282				},
283			},
284			in:  []string{"bin", "my_test"},
285			out: "target/product/test_device/odm/bin/my_test",
286		},
287		{
288			name: "product binary",
289			ctx: &moduleInstallPathContextImpl{
290				androidBaseContextImpl: androidBaseContextImpl{
291					target: deviceTarget,
292					kind:   productSpecificModule,
293				},
294			},
295			in:  []string{"bin", "my_test"},
296			out: "target/product/test_device/product/bin/my_test",
297		},
298		{
299			name: "product_services binary",
300			ctx: &moduleInstallPathContextImpl{
301				androidBaseContextImpl: androidBaseContextImpl{
302					target: deviceTarget,
303					kind:   productServicesSpecificModule,
304				},
305			},
306			in:  []string{"bin", "my_test"},
307			out: "target/product/test_device/product_services/bin/my_test",
308		},
309
310		{
311			name: "system native test binary",
312			ctx: &moduleInstallPathContextImpl{
313				androidBaseContextImpl: androidBaseContextImpl{
314					target: deviceTarget,
315				},
316				inData: true,
317			},
318			in:  []string{"nativetest", "my_test"},
319			out: "target/product/test_device/data/nativetest/my_test",
320		},
321		{
322			name: "vendor native test binary",
323			ctx: &moduleInstallPathContextImpl{
324				androidBaseContextImpl: androidBaseContextImpl{
325					target: deviceTarget,
326					kind:   socSpecificModule,
327				},
328				inData: true,
329			},
330			in:  []string{"nativetest", "my_test"},
331			out: "target/product/test_device/data/nativetest/my_test",
332		},
333		{
334			name: "odm native test binary",
335			ctx: &moduleInstallPathContextImpl{
336				androidBaseContextImpl: androidBaseContextImpl{
337					target: deviceTarget,
338					kind:   deviceSpecificModule,
339				},
340				inData: true,
341			},
342			in:  []string{"nativetest", "my_test"},
343			out: "target/product/test_device/data/nativetest/my_test",
344		},
345		{
346			name: "product native test binary",
347			ctx: &moduleInstallPathContextImpl{
348				androidBaseContextImpl: androidBaseContextImpl{
349					target: deviceTarget,
350					kind:   productSpecificModule,
351				},
352				inData: true,
353			},
354			in:  []string{"nativetest", "my_test"},
355			out: "target/product/test_device/data/nativetest/my_test",
356		},
357
358		{
359			name: "product_services native test binary",
360			ctx: &moduleInstallPathContextImpl{
361				androidBaseContextImpl: androidBaseContextImpl{
362					target: deviceTarget,
363					kind:   productServicesSpecificModule,
364				},
365				inData: true,
366			},
367			in:  []string{"nativetest", "my_test"},
368			out: "target/product/test_device/data/nativetest/my_test",
369		},
370
371		{
372			name: "sanitized system binary",
373			ctx: &moduleInstallPathContextImpl{
374				androidBaseContextImpl: androidBaseContextImpl{
375					target: deviceTarget,
376				},
377				inSanitizerDir: true,
378			},
379			in:  []string{"bin", "my_test"},
380			out: "target/product/test_device/data/asan/system/bin/my_test",
381		},
382		{
383			name: "sanitized vendor binary",
384			ctx: &moduleInstallPathContextImpl{
385				androidBaseContextImpl: androidBaseContextImpl{
386					target: deviceTarget,
387					kind:   socSpecificModule,
388				},
389				inSanitizerDir: true,
390			},
391			in:  []string{"bin", "my_test"},
392			out: "target/product/test_device/data/asan/vendor/bin/my_test",
393		},
394		{
395			name: "sanitized odm binary",
396			ctx: &moduleInstallPathContextImpl{
397				androidBaseContextImpl: androidBaseContextImpl{
398					target: deviceTarget,
399					kind:   deviceSpecificModule,
400				},
401				inSanitizerDir: true,
402			},
403			in:  []string{"bin", "my_test"},
404			out: "target/product/test_device/data/asan/odm/bin/my_test",
405		},
406		{
407			name: "sanitized product binary",
408			ctx: &moduleInstallPathContextImpl{
409				androidBaseContextImpl: androidBaseContextImpl{
410					target: deviceTarget,
411					kind:   productSpecificModule,
412				},
413				inSanitizerDir: true,
414			},
415			in:  []string{"bin", "my_test"},
416			out: "target/product/test_device/data/asan/product/bin/my_test",
417		},
418
419		{
420			name: "sanitized product_services binary",
421			ctx: &moduleInstallPathContextImpl{
422				androidBaseContextImpl: androidBaseContextImpl{
423					target: deviceTarget,
424					kind:   productServicesSpecificModule,
425				},
426				inSanitizerDir: true,
427			},
428			in:  []string{"bin", "my_test"},
429			out: "target/product/test_device/data/asan/product_services/bin/my_test",
430		},
431
432		{
433			name: "sanitized system native test binary",
434			ctx: &moduleInstallPathContextImpl{
435				androidBaseContextImpl: androidBaseContextImpl{
436					target: deviceTarget,
437				},
438				inData:         true,
439				inSanitizerDir: true,
440			},
441			in:  []string{"nativetest", "my_test"},
442			out: "target/product/test_device/data/asan/data/nativetest/my_test",
443		},
444		{
445			name: "sanitized vendor native test binary",
446			ctx: &moduleInstallPathContextImpl{
447				androidBaseContextImpl: androidBaseContextImpl{
448					target: deviceTarget,
449					kind:   socSpecificModule,
450				},
451				inData:         true,
452				inSanitizerDir: true,
453			},
454			in:  []string{"nativetest", "my_test"},
455			out: "target/product/test_device/data/asan/data/nativetest/my_test",
456		},
457		{
458			name: "sanitized odm native test binary",
459			ctx: &moduleInstallPathContextImpl{
460				androidBaseContextImpl: androidBaseContextImpl{
461					target: deviceTarget,
462					kind:   deviceSpecificModule,
463				},
464				inData:         true,
465				inSanitizerDir: true,
466			},
467			in:  []string{"nativetest", "my_test"},
468			out: "target/product/test_device/data/asan/data/nativetest/my_test",
469		},
470		{
471			name: "sanitized product native test binary",
472			ctx: &moduleInstallPathContextImpl{
473				androidBaseContextImpl: androidBaseContextImpl{
474					target: deviceTarget,
475					kind:   productSpecificModule,
476				},
477				inData:         true,
478				inSanitizerDir: true,
479			},
480			in:  []string{"nativetest", "my_test"},
481			out: "target/product/test_device/data/asan/data/nativetest/my_test",
482		},
483		{
484			name: "sanitized product_services native test binary",
485			ctx: &moduleInstallPathContextImpl{
486				androidBaseContextImpl: androidBaseContextImpl{
487					target: deviceTarget,
488					kind:   productServicesSpecificModule,
489				},
490				inData:         true,
491				inSanitizerDir: true,
492			},
493			in:  []string{"nativetest", "my_test"},
494			out: "target/product/test_device/data/asan/data/nativetest/my_test",
495		},
496	}
497
498	for _, tc := range testCases {
499		t.Run(tc.name, func(t *testing.T) {
500			tc.ctx.androidBaseContextImpl.config = testConfig
501			output := PathForModuleInstall(tc.ctx, tc.in...)
502			if output.basePath.path != tc.out {
503				t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
504					output.basePath.path,
505					tc.out)
506			}
507		})
508	}
509}
510
511func TestDirectorySortedPaths(t *testing.T) {
512	config := TestConfig("out", nil)
513
514	ctx := PathContextForTesting(config, map[string][]byte{
515		"a.txt":   nil,
516		"a/txt":   nil,
517		"a/b/c":   nil,
518		"a/b/d":   nil,
519		"b":       nil,
520		"b/b.txt": nil,
521		"a/a.txt": nil,
522	})
523
524	makePaths := func() Paths {
525		return Paths{
526			PathForSource(ctx, "a.txt"),
527			PathForSource(ctx, "a/txt"),
528			PathForSource(ctx, "a/b/c"),
529			PathForSource(ctx, "a/b/d"),
530			PathForSource(ctx, "b"),
531			PathForSource(ctx, "b/b.txt"),
532			PathForSource(ctx, "a/a.txt"),
533		}
534	}
535
536	expected := []string{
537		"a.txt",
538		"a/a.txt",
539		"a/b/c",
540		"a/b/d",
541		"a/txt",
542		"b",
543		"b/b.txt",
544	}
545
546	paths := makePaths()
547	reversePaths := ReversePaths(paths)
548
549	sortedPaths := PathsToDirectorySortedPaths(paths)
550	reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
551
552	if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
553		t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
554	}
555
556	if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
557		t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
558	}
559
560	expectedA := []string{
561		"a/a.txt",
562		"a/b/c",
563		"a/b/d",
564		"a/txt",
565	}
566
567	inA := sortedPaths.PathsInDirectory("a")
568	if !reflect.DeepEqual(inA.Strings(), expectedA) {
569		t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
570	}
571
572	expectedA_B := []string{
573		"a/b/c",
574		"a/b/d",
575	}
576
577	inA_B := sortedPaths.PathsInDirectory("a/b")
578	if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
579		t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
580	}
581
582	expectedB := []string{
583		"b/b.txt",
584	}
585
586	inB := sortedPaths.PathsInDirectory("b")
587	if !reflect.DeepEqual(inB.Strings(), expectedB) {
588		t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
589	}
590}
591
592func TestMaybeRel(t *testing.T) {
593	testCases := []struct {
594		name   string
595		base   string
596		target string
597		out    string
598		isRel  bool
599	}{
600		{
601			name:   "normal",
602			base:   "a/b/c",
603			target: "a/b/c/d",
604			out:    "d",
605			isRel:  true,
606		},
607		{
608			name:   "parent",
609			base:   "a/b/c/d",
610			target: "a/b/c",
611			isRel:  false,
612		},
613		{
614			name:   "not relative",
615			base:   "a/b",
616			target: "c/d",
617			isRel:  false,
618		},
619		{
620			name:   "abs1",
621			base:   "/a",
622			target: "a",
623			isRel:  false,
624		},
625		{
626			name:   "abs2",
627			base:   "a",
628			target: "/a",
629			isRel:  false,
630		},
631	}
632
633	for _, testCase := range testCases {
634		t.Run(testCase.name, func(t *testing.T) {
635			ctx := &configErrorWrapper{}
636			out, isRel := MaybeRel(ctx, testCase.base, testCase.target)
637			if len(ctx.errors) > 0 {
638				t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v",
639					testCase.base, testCase.target, ctx.errors)
640			}
641			if isRel != testCase.isRel || out != testCase.out {
642				t.Errorf("MaybeRel(..., %s, %s) want %v, %v got %v, %v",
643					testCase.base, testCase.target, testCase.out, testCase.isRel, out, isRel)
644			}
645		})
646	}
647}
648
649func TestPathForSource(t *testing.T) {
650	testCases := []struct {
651		name     string
652		buildDir string
653		src      string
654		err      string
655	}{
656		{
657			name:     "normal",
658			buildDir: "out",
659			src:      "a/b/c",
660		},
661		{
662			name:     "abs",
663			buildDir: "out",
664			src:      "/a/b/c",
665			err:      "is outside directory",
666		},
667		{
668			name:     "in out dir",
669			buildDir: "out",
670			src:      "out/a/b/c",
671			err:      "is in output",
672		},
673	}
674
675	funcs := []struct {
676		name string
677		f    func(ctx PathContext, pathComponents ...string) (SourcePath, error)
678	}{
679		{"pathForSource", pathForSource},
680		{"safePathForSource", safePathForSource},
681	}
682
683	for _, f := range funcs {
684		t.Run(f.name, func(t *testing.T) {
685			for _, test := range testCases {
686				t.Run(test.name, func(t *testing.T) {
687					testConfig := TestConfig(test.buildDir, nil)
688					ctx := &configErrorWrapper{config: testConfig}
689					_, err := f.f(ctx, test.src)
690					if len(ctx.errors) > 0 {
691						t.Fatalf("unexpected errors %v", ctx.errors)
692					}
693					if err != nil {
694						if test.err == "" {
695							t.Fatalf("unexpected error %q", err.Error())
696						} else if !strings.Contains(err.Error(), test.err) {
697							t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error())
698						}
699					} else {
700						if test.err != "" {
701							t.Fatalf("missing error %q", test.err)
702						}
703					}
704				})
705			}
706		})
707	}
708}
709
710type pathForModuleSrcTestModule struct {
711	ModuleBase
712	props struct {
713		Srcs         []string `android:"path"`
714		Exclude_srcs []string `android:"path"`
715
716		Src *string `android:"path"`
717
718		Module_handles_missing_deps bool
719	}
720
721	src string
722	rel string
723
724	srcs []string
725	rels []string
726
727	missingDeps []string
728}
729
730func pathForModuleSrcTestModuleFactory() Module {
731	module := &pathForModuleSrcTestModule{}
732	module.AddProperties(&module.props)
733	InitAndroidModule(module)
734	return module
735}
736
737func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
738	var srcs Paths
739	if p.props.Module_handles_missing_deps {
740		srcs, p.missingDeps = PathsAndMissingDepsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
741	} else {
742		srcs = PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs)
743	}
744	p.srcs = srcs.Strings()
745
746	for _, src := range srcs {
747		p.rels = append(p.rels, src.Rel())
748	}
749
750	if p.props.Src != nil {
751		src := PathForModuleSrc(ctx, *p.props.Src)
752		if src != nil {
753			p.src = src.String()
754			p.rel = src.Rel()
755		}
756	}
757
758	if !p.props.Module_handles_missing_deps {
759		p.missingDeps = ctx.GetMissingDependencies()
760	}
761}
762
763type pathForModuleSrcTestCase struct {
764	name string
765	bp   string
766	srcs []string
767	rels []string
768	src  string
769	rel  string
770}
771
772func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSrcTestCase) {
773	for _, test := range tests {
774		t.Run(test.name, func(t *testing.T) {
775			config := TestConfig(buildDir, nil)
776			ctx := NewTestContext()
777
778			ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
779			ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory))
780
781			fgBp := `
782				filegroup {
783					name: "a",
784					srcs: ["src/a"],
785				}
786			`
787
788			mockFS := map[string][]byte{
789				"fg/Android.bp":     []byte(fgBp),
790				"foo/Android.bp":    []byte(test.bp),
791				"fg/src/a":          nil,
792				"foo/src/b":         nil,
793				"foo/src/c":         nil,
794				"foo/src/d":         nil,
795				"foo/src/e/e":       nil,
796				"foo/src_special/$": nil,
797			}
798
799			ctx.MockFileSystem(mockFS)
800
801			ctx.Register()
802			_, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp"})
803			FailIfErrored(t, errs)
804			_, errs = ctx.PrepareBuildActions(config)
805			FailIfErrored(t, errs)
806
807			m := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
808
809			if g, w := m.srcs, test.srcs; !reflect.DeepEqual(g, w) {
810				t.Errorf("want srcs %q, got %q", w, g)
811			}
812
813			if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) {
814				t.Errorf("want rels %q, got %q", w, g)
815			}
816
817			if g, w := m.src, test.src; g != w {
818				t.Errorf("want src %q, got %q", w, g)
819			}
820
821			if g, w := m.rel, test.rel; g != w {
822				t.Errorf("want rel %q, got %q", w, g)
823			}
824		})
825	}
826}
827
828func TestPathsForModuleSrc(t *testing.T) {
829	tests := []pathForModuleSrcTestCase{
830		{
831			name: "path",
832			bp: `
833			test {
834				name: "foo",
835				srcs: ["src/b"],
836			}`,
837			srcs: []string{"foo/src/b"},
838			rels: []string{"src/b"},
839		},
840		{
841			name: "glob",
842			bp: `
843			test {
844				name: "foo",
845				srcs: [
846					"src/*",
847					"src/e/*",
848				],
849			}`,
850			srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
851			rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
852		},
853		{
854			name: "recursive glob",
855			bp: `
856			test {
857				name: "foo",
858				srcs: ["src/**/*"],
859			}`,
860			srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"},
861			rels: []string{"src/b", "src/c", "src/d", "src/e/e"},
862		},
863		{
864			name: "filegroup",
865			bp: `
866			test {
867				name: "foo",
868				srcs: [":a"],
869			}`,
870			srcs: []string{"fg/src/a"},
871			rels: []string{"src/a"},
872		},
873		{
874			name: "special characters glob",
875			bp: `
876			test {
877				name: "foo",
878				srcs: ["src_special/*"],
879			}`,
880			srcs: []string{"foo/src_special/$"},
881			rels: []string{"src_special/$"},
882		},
883	}
884
885	buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_test")
886	if err != nil {
887		t.Fatal(err)
888	}
889	defer os.RemoveAll(buildDir)
890
891	testPathForModuleSrc(t, buildDir, tests)
892}
893
894func TestPathForModuleSrc(t *testing.T) {
895	tests := []pathForModuleSrcTestCase{
896		{
897			name: "path",
898			bp: `
899			test {
900				name: "foo",
901				src: "src/b",
902			}`,
903			src: "foo/src/b",
904			rel: "src/b",
905		},
906		{
907			name: "glob",
908			bp: `
909			test {
910				name: "foo",
911				src: "src/e/*",
912			}`,
913			src: "foo/src/e/e",
914			rel: "src/e/e",
915		},
916		{
917			name: "filegroup",
918			bp: `
919			test {
920				name: "foo",
921				src: ":a",
922			}`,
923			src: "fg/src/a",
924			rel: "src/a",
925		},
926		{
927			name: "special characters glob",
928			bp: `
929			test {
930				name: "foo",
931				src: "src_special/*",
932			}`,
933			src: "foo/src_special/$",
934			rel: "src_special/$",
935		},
936	}
937
938	buildDir, err := ioutil.TempDir("", "soong_path_for_module_src_test")
939	if err != nil {
940		t.Fatal(err)
941	}
942	defer os.RemoveAll(buildDir)
943
944	testPathForModuleSrc(t, buildDir, tests)
945}
946
947func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) {
948	buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_allow_missing_dependencies_test")
949	if err != nil {
950		t.Fatal(err)
951	}
952	defer os.RemoveAll(buildDir)
953
954	config := TestConfig(buildDir, nil)
955	config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
956
957	ctx := NewTestContext()
958	ctx.SetAllowMissingDependencies(true)
959
960	ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory))
961
962	bp := `
963		test {
964			name: "foo",
965			srcs: [":a"],
966			exclude_srcs: [":b"],
967			src: ":c",
968		}
969
970		test {
971			name: "bar",
972			srcs: [":d"],
973			exclude_srcs: [":e"],
974			module_handles_missing_deps: true,
975		}
976	`
977
978	mockFS := map[string][]byte{
979		"Android.bp": []byte(bp),
980	}
981
982	ctx.MockFileSystem(mockFS)
983
984	ctx.Register()
985	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
986	FailIfErrored(t, errs)
987	_, errs = ctx.PrepareBuildActions(config)
988	FailIfErrored(t, errs)
989
990	foo := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule)
991
992	if g, w := foo.missingDeps, []string{"a", "b", "c"}; !reflect.DeepEqual(g, w) {
993		t.Errorf("want foo missing deps %q, got %q", w, g)
994	}
995
996	if g, w := foo.srcs, []string{}; !reflect.DeepEqual(g, w) {
997		t.Errorf("want foo srcs %q, got %q", w, g)
998	}
999
1000	if g, w := foo.src, ""; g != w {
1001		t.Errorf("want foo src %q, got %q", w, g)
1002	}
1003
1004	bar := ctx.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule)
1005
1006	if g, w := bar.missingDeps, []string{"d", "e"}; !reflect.DeepEqual(g, w) {
1007		t.Errorf("want bar missing deps %q, got %q", w, g)
1008	}
1009
1010	if g, w := bar.srcs, []string{}; !reflect.DeepEqual(g, w) {
1011		t.Errorf("want bar srcs %q, got %q", w, g)
1012	}
1013}
1014
1015func ExampleOutputPath_ReplaceExtension() {
1016	ctx := &configErrorWrapper{
1017		config: TestConfig("out", nil),
1018	}
1019	p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
1020	p2 := p.ReplaceExtension(ctx, "oat")
1021	fmt.Println(p, p2)
1022	fmt.Println(p.Rel(), p2.Rel())
1023
1024	// Output:
1025	// out/system/framework/boot.art out/system/framework/boot.oat
1026	// boot.art boot.oat
1027}
1028
1029func ExampleOutputPath_FileInSameDir() {
1030	ctx := &configErrorWrapper{
1031		config: TestConfig("out", nil),
1032	}
1033	p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art")
1034	p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex")
1035	fmt.Println(p, p2)
1036	fmt.Println(p.Rel(), p2.Rel())
1037
1038	// Output:
1039	// out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
1040	// boot.art oat/arm/boot.vdex
1041}
1042