github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/android/paths_test.go (about)

     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  
    15  package android
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"reflect"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/google/blueprint/pathtools"
    25  )
    26  
    27  type strsTestCase struct {
    28  	in  []string
    29  	out string
    30  	err []error
    31  }
    32  
    33  var commonValidatePathTestCases = []strsTestCase{
    34  	{
    35  		in:  []string{""},
    36  		out: "",
    37  	},
    38  	{
    39  		in:  []string{"a/b"},
    40  		out: "a/b",
    41  	},
    42  	{
    43  		in:  []string{"a/b", "c"},
    44  		out: "a/b/c",
    45  	},
    46  	{
    47  		in:  []string{"a/.."},
    48  		out: ".",
    49  	},
    50  	{
    51  		in:  []string{"."},
    52  		out: ".",
    53  	},
    54  	{
    55  		in:  []string{".."},
    56  		out: "",
    57  		err: []error{errors.New("Path is outside directory: ..")},
    58  	},
    59  	{
    60  		in:  []string{"../a"},
    61  		out: "",
    62  		err: []error{errors.New("Path is outside directory: ../a")},
    63  	},
    64  	{
    65  		in:  []string{"b/../../a"},
    66  		out: "",
    67  		err: []error{errors.New("Path is outside directory: ../a")},
    68  	},
    69  	{
    70  		in:  []string{"/a"},
    71  		out: "",
    72  		err: []error{errors.New("Path is outside directory: /a")},
    73  	},
    74  	{
    75  		in:  []string{"a", "../b"},
    76  		out: "",
    77  		err: []error{errors.New("Path is outside directory: ../b")},
    78  	},
    79  	{
    80  		in:  []string{"a", "b/../../c"},
    81  		out: "",
    82  		err: []error{errors.New("Path is outside directory: ../c")},
    83  	},
    84  	{
    85  		in:  []string{"a", "./.."},
    86  		out: "",
    87  		err: []error{errors.New("Path is outside directory: ..")},
    88  	},
    89  }
    90  
    91  var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
    92  	{
    93  		in:  []string{"$host/../$a"},
    94  		out: "$a",
    95  	},
    96  }...)
    97  
    98  var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{
    99  	{
   100  		in:  []string{"$host/../$a"},
   101  		out: "",
   102  		err: []error{errors.New("Path contains invalid character($): $host/../$a")},
   103  	},
   104  	{
   105  		in:  []string{"$host/.."},
   106  		out: "",
   107  		err: []error{errors.New("Path contains invalid character($): $host/..")},
   108  	},
   109  }...)
   110  
   111  func TestValidateSafePath(t *testing.T) {
   112  	for _, testCase := range validateSafePathTestCases {
   113  		t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
   114  			ctx := &configErrorWrapper{}
   115  			out, err := validateSafePath(testCase.in...)
   116  			if err != nil {
   117  				reportPathError(ctx, err)
   118  			}
   119  			check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
   120  		})
   121  	}
   122  }
   123  
   124  func TestValidatePath(t *testing.T) {
   125  	for _, testCase := range validatePathTestCases {
   126  		t.Run(strings.Join(testCase.in, ","), func(t *testing.T) {
   127  			ctx := &configErrorWrapper{}
   128  			out, err := validatePath(testCase.in...)
   129  			if err != nil {
   130  				reportPathError(ctx, err)
   131  			}
   132  			check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err)
   133  		})
   134  	}
   135  }
   136  
   137  func TestOptionalPath(t *testing.T) {
   138  	var path OptionalPath
   139  	checkInvalidOptionalPath(t, path)
   140  
   141  	path = OptionalPathForPath(nil)
   142  	checkInvalidOptionalPath(t, path)
   143  }
   144  
   145  func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
   146  	t.Helper()
   147  	if path.Valid() {
   148  		t.Errorf("Uninitialized OptionalPath should not be valid")
   149  	}
   150  	if path.String() != "" {
   151  		t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
   152  	}
   153  	defer func() {
   154  		if r := recover(); r == nil {
   155  			t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath")
   156  		}
   157  	}()
   158  	path.Path()
   159  }
   160  
   161  func check(t *testing.T, testType, testString string,
   162  	got interface{}, err []error,
   163  	expected interface{}, expectedErr []error) {
   164  	t.Helper()
   165  
   166  	printedTestCase := false
   167  	e := func(s string, expected, got interface{}) {
   168  		t.Helper()
   169  		if !printedTestCase {
   170  			t.Errorf("test case %s: %s", testType, testString)
   171  			printedTestCase = true
   172  		}
   173  		t.Errorf("incorrect %s", s)
   174  		t.Errorf("  expected: %s", p(expected))
   175  		t.Errorf("       got: %s", p(got))
   176  	}
   177  
   178  	if !reflect.DeepEqual(expectedErr, err) {
   179  		e("errors:", expectedErr, err)
   180  	}
   181  
   182  	if !reflect.DeepEqual(expected, got) {
   183  		e("output:", expected, got)
   184  	}
   185  }
   186  
   187  func p(in interface{}) string {
   188  	if v, ok := in.([]interface{}); ok {
   189  		s := make([]string, len(v))
   190  		for i := range v {
   191  			s[i] = fmt.Sprintf("%#v", v[i])
   192  		}
   193  		return "[" + strings.Join(s, ", ") + "]"
   194  	} else {
   195  		return fmt.Sprintf("%#v", in)
   196  	}
   197  }
   198  
   199  type moduleInstallPathContextImpl struct {
   200  	androidBaseContextImpl
   201  
   202  	inData         bool
   203  	inSanitizerDir bool
   204  }
   205  
   206  func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem {
   207  	return pathtools.MockFs(nil)
   208  }
   209  
   210  func (m moduleInstallPathContextImpl) Config() Config {
   211  	return m.androidBaseContextImpl.config
   212  }
   213  
   214  func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {}
   215  
   216  func (m moduleInstallPathContextImpl) InstallInData() bool {
   217  	return m.inData
   218  }
   219  
   220  func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool {
   221  	return m.inSanitizerDir
   222  }
   223  
   224  func TestPathForModuleInstall(t *testing.T) {
   225  	testConfig := TestConfig("", nil)
   226  
   227  	hostTarget := Target{Os: Linux}
   228  	deviceTarget := Target{Os: Android}
   229  
   230  	testCases := []struct {
   231  		name string
   232  		ctx  *moduleInstallPathContextImpl
   233  		in   []string
   234  		out  string
   235  	}{
   236  		{
   237  			name: "host binary",
   238  			ctx: &moduleInstallPathContextImpl{
   239  				androidBaseContextImpl: androidBaseContextImpl{
   240  					target: hostTarget,
   241  				},
   242  			},
   243  			in:  []string{"bin", "my_test"},
   244  			out: "host/linux-x86/bin/my_test",
   245  		},
   246  
   247  		{
   248  			name: "system binary",
   249  			ctx: &moduleInstallPathContextImpl{
   250  				androidBaseContextImpl: androidBaseContextImpl{
   251  					target: deviceTarget,
   252  				},
   253  			},
   254  			in:  []string{"bin", "my_test"},
   255  			out: "target/product/test_device/system/bin/my_test",
   256  		},
   257  		{
   258  			name: "vendor binary",
   259  			ctx: &moduleInstallPathContextImpl{
   260  				androidBaseContextImpl: androidBaseContextImpl{
   261  					target: deviceTarget,
   262  					kind:   socSpecificModule,
   263  				},
   264  			},
   265  			in:  []string{"bin", "my_test"},
   266  			out: "target/product/test_device/vendor/bin/my_test",
   267  		},
   268  		{
   269  			name: "odm binary",
   270  			ctx: &moduleInstallPathContextImpl{
   271  				androidBaseContextImpl: androidBaseContextImpl{
   272  					target: deviceTarget,
   273  					kind:   deviceSpecificModule,
   274  				},
   275  			},
   276  			in:  []string{"bin", "my_test"},
   277  			out: "target/product/test_device/odm/bin/my_test",
   278  		},
   279  		{
   280  			name: "product binary",
   281  			ctx: &moduleInstallPathContextImpl{
   282  				androidBaseContextImpl: androidBaseContextImpl{
   283  					target: deviceTarget,
   284  					kind:   productSpecificModule,
   285  				},
   286  			},
   287  			in:  []string{"bin", "my_test"},
   288  			out: "target/product/test_device/product/bin/my_test",
   289  		},
   290  
   291  		{
   292  			name: "system native test binary",
   293  			ctx: &moduleInstallPathContextImpl{
   294  				androidBaseContextImpl: androidBaseContextImpl{
   295  					target: deviceTarget,
   296  				},
   297  				inData: true,
   298  			},
   299  			in:  []string{"nativetest", "my_test"},
   300  			out: "target/product/test_device/data/nativetest/my_test",
   301  		},
   302  		{
   303  			name: "vendor native test binary",
   304  			ctx: &moduleInstallPathContextImpl{
   305  				androidBaseContextImpl: androidBaseContextImpl{
   306  					target: deviceTarget,
   307  					kind:   socSpecificModule,
   308  				},
   309  				inData: true,
   310  			},
   311  			in:  []string{"nativetest", "my_test"},
   312  			out: "target/product/test_device/data/nativetest/my_test",
   313  		},
   314  		{
   315  			name: "odm native test binary",
   316  			ctx: &moduleInstallPathContextImpl{
   317  				androidBaseContextImpl: androidBaseContextImpl{
   318  					target: deviceTarget,
   319  					kind:   deviceSpecificModule,
   320  				},
   321  				inData: true,
   322  			},
   323  			in:  []string{"nativetest", "my_test"},
   324  			out: "target/product/test_device/data/nativetest/my_test",
   325  		},
   326  		{
   327  			name: "product native test binary",
   328  			ctx: &moduleInstallPathContextImpl{
   329  				androidBaseContextImpl: androidBaseContextImpl{
   330  					target: deviceTarget,
   331  					kind:   productSpecificModule,
   332  				},
   333  				inData: true,
   334  			},
   335  			in:  []string{"nativetest", "my_test"},
   336  			out: "target/product/test_device/data/nativetest/my_test",
   337  		},
   338  
   339  		{
   340  			name: "sanitized system binary",
   341  			ctx: &moduleInstallPathContextImpl{
   342  				androidBaseContextImpl: androidBaseContextImpl{
   343  					target: deviceTarget,
   344  				},
   345  				inSanitizerDir: true,
   346  			},
   347  			in:  []string{"bin", "my_test"},
   348  			out: "target/product/test_device/data/asan/system/bin/my_test",
   349  		},
   350  		{
   351  			name: "sanitized vendor binary",
   352  			ctx: &moduleInstallPathContextImpl{
   353  				androidBaseContextImpl: androidBaseContextImpl{
   354  					target: deviceTarget,
   355  					kind:   socSpecificModule,
   356  				},
   357  				inSanitizerDir: true,
   358  			},
   359  			in:  []string{"bin", "my_test"},
   360  			out: "target/product/test_device/data/asan/vendor/bin/my_test",
   361  		},
   362  		{
   363  			name: "sanitized odm binary",
   364  			ctx: &moduleInstallPathContextImpl{
   365  				androidBaseContextImpl: androidBaseContextImpl{
   366  					target: deviceTarget,
   367  					kind:   deviceSpecificModule,
   368  				},
   369  				inSanitizerDir: true,
   370  			},
   371  			in:  []string{"bin", "my_test"},
   372  			out: "target/product/test_device/data/asan/odm/bin/my_test",
   373  		},
   374  		{
   375  			name: "sanitized product binary",
   376  			ctx: &moduleInstallPathContextImpl{
   377  				androidBaseContextImpl: androidBaseContextImpl{
   378  					target: deviceTarget,
   379  					kind:   productSpecificModule,
   380  				},
   381  				inSanitizerDir: true,
   382  			},
   383  			in:  []string{"bin", "my_test"},
   384  			out: "target/product/test_device/data/asan/product/bin/my_test",
   385  		},
   386  
   387  		{
   388  			name: "sanitized system native test binary",
   389  			ctx: &moduleInstallPathContextImpl{
   390  				androidBaseContextImpl: androidBaseContextImpl{
   391  					target: deviceTarget,
   392  				},
   393  				inData:         true,
   394  				inSanitizerDir: true,
   395  			},
   396  			in:  []string{"nativetest", "my_test"},
   397  			out: "target/product/test_device/data/asan/data/nativetest/my_test",
   398  		},
   399  		{
   400  			name: "sanitized vendor native test binary",
   401  			ctx: &moduleInstallPathContextImpl{
   402  				androidBaseContextImpl: androidBaseContextImpl{
   403  					target: deviceTarget,
   404  					kind:   socSpecificModule,
   405  				},
   406  				inData:         true,
   407  				inSanitizerDir: true,
   408  			},
   409  			in:  []string{"nativetest", "my_test"},
   410  			out: "target/product/test_device/data/asan/data/nativetest/my_test",
   411  		},
   412  		{
   413  			name: "sanitized odm native test binary",
   414  			ctx: &moduleInstallPathContextImpl{
   415  				androidBaseContextImpl: androidBaseContextImpl{
   416  					target: deviceTarget,
   417  					kind:   deviceSpecificModule,
   418  				},
   419  				inData:         true,
   420  				inSanitizerDir: true,
   421  			},
   422  			in:  []string{"nativetest", "my_test"},
   423  			out: "target/product/test_device/data/asan/data/nativetest/my_test",
   424  		},
   425  		{
   426  			name: "sanitized product native test binary",
   427  			ctx: &moduleInstallPathContextImpl{
   428  				androidBaseContextImpl: androidBaseContextImpl{
   429  					target: deviceTarget,
   430  					kind:   productSpecificModule,
   431  				},
   432  				inData:         true,
   433  				inSanitizerDir: true,
   434  			},
   435  			in:  []string{"nativetest", "my_test"},
   436  			out: "target/product/test_device/data/asan/data/nativetest/my_test",
   437  		},
   438  	}
   439  
   440  	for _, tc := range testCases {
   441  		t.Run(tc.name, func(t *testing.T) {
   442  			tc.ctx.androidBaseContextImpl.config = testConfig
   443  			output := PathForModuleInstall(tc.ctx, tc.in...)
   444  			if output.basePath.path != tc.out {
   445  				t.Errorf("unexpected path:\n got: %q\nwant: %q\n",
   446  					output.basePath.path,
   447  					tc.out)
   448  			}
   449  		})
   450  	}
   451  }
   452  
   453  func TestDirectorySortedPaths(t *testing.T) {
   454  	makePaths := func() Paths {
   455  		return Paths{
   456  			PathForTesting("a.txt"),
   457  			PathForTesting("a/txt"),
   458  			PathForTesting("a/b/c"),
   459  			PathForTesting("a/b/d"),
   460  			PathForTesting("b"),
   461  			PathForTesting("b/b.txt"),
   462  			PathForTesting("a/a.txt"),
   463  		}
   464  	}
   465  
   466  	expected := []string{
   467  		"a.txt",
   468  		"a/a.txt",
   469  		"a/b/c",
   470  		"a/b/d",
   471  		"a/txt",
   472  		"b",
   473  		"b/b.txt",
   474  	}
   475  
   476  	paths := makePaths()
   477  	reversePaths := ReversePaths(paths)
   478  
   479  	sortedPaths := PathsToDirectorySortedPaths(paths)
   480  	reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths)
   481  
   482  	if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) {
   483  		t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected)
   484  	}
   485  
   486  	if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) {
   487  		t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected)
   488  	}
   489  
   490  	expectedA := []string{
   491  		"a/a.txt",
   492  		"a/b/c",
   493  		"a/b/d",
   494  		"a/txt",
   495  	}
   496  
   497  	inA := sortedPaths.PathsInDirectory("a")
   498  	if !reflect.DeepEqual(inA.Strings(), expectedA) {
   499  		t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA)
   500  	}
   501  
   502  	expectedA_B := []string{
   503  		"a/b/c",
   504  		"a/b/d",
   505  	}
   506  
   507  	inA_B := sortedPaths.PathsInDirectory("a/b")
   508  	if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) {
   509  		t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B)
   510  	}
   511  
   512  	expectedB := []string{
   513  		"b/b.txt",
   514  	}
   515  
   516  	inB := sortedPaths.PathsInDirectory("b")
   517  	if !reflect.DeepEqual(inB.Strings(), expectedB) {
   518  		t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA)
   519  	}
   520  }