xref: /aosp_15_r20/build/soong/dexpreopt/class_loader_context_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2020 Google Inc. All rights reserved.
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage dexpreopt
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Worker// This file contains unit tests for class loader context structure.
18*333d2b36SAndroid Build Coastguard Worker// For class loader context tests involving .bp files, see TestUsesLibraries in java package.
19*333d2b36SAndroid Build Coastguard Worker
20*333d2b36SAndroid Build Coastguard Workerimport (
21*333d2b36SAndroid Build Coastguard Worker	"fmt"
22*333d2b36SAndroid Build Coastguard Worker	"reflect"
23*333d2b36SAndroid Build Coastguard Worker	"sort"
24*333d2b36SAndroid Build Coastguard Worker	"strings"
25*333d2b36SAndroid Build Coastguard Worker	"testing"
26*333d2b36SAndroid Build Coastguard Worker
27*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
28*333d2b36SAndroid Build Coastguard Worker)
29*333d2b36SAndroid Build Coastguard Worker
30*333d2b36SAndroid Build Coastguard Workerfunc TestCLC(t *testing.T) {
31*333d2b36SAndroid Build Coastguard Worker	// Construct class loader context with the following structure:
32*333d2b36SAndroid Build Coastguard Worker	// .
33*333d2b36SAndroid Build Coastguard Worker	// ├── 29
34*333d2b36SAndroid Build Coastguard Worker	// │   ├── android.hidl.manager
35*333d2b36SAndroid Build Coastguard Worker	// │   └── android.hidl.base
36*333d2b36SAndroid Build Coastguard Worker	// │
37*333d2b36SAndroid Build Coastguard Worker	// └── any
38*333d2b36SAndroid Build Coastguard Worker	//     ├── a'  (a single quotation mark (') is there to test escaping)
39*333d2b36SAndroid Build Coastguard Worker	//     ├── b
40*333d2b36SAndroid Build Coastguard Worker	//     ├── c
41*333d2b36SAndroid Build Coastguard Worker	//     ├── d
42*333d2b36SAndroid Build Coastguard Worker	//     │   ├── a2
43*333d2b36SAndroid Build Coastguard Worker	//     │   ├── b2
44*333d2b36SAndroid Build Coastguard Worker	//     │   └── c2
45*333d2b36SAndroid Build Coastguard Worker	//     │       ├── a1
46*333d2b36SAndroid Build Coastguard Worker	//     │       └── b1
47*333d2b36SAndroid Build Coastguard Worker	//     ├── f
48*333d2b36SAndroid Build Coastguard Worker	//     ├── a3
49*333d2b36SAndroid Build Coastguard Worker	//     └── b3
50*333d2b36SAndroid Build Coastguard Worker	//
51*333d2b36SAndroid Build Coastguard Worker	ctx := testContext()
52*333d2b36SAndroid Build Coastguard Worker
53*333d2b36SAndroid Build Coastguard Worker	optional := false
54*333d2b36SAndroid Build Coastguard Worker
55*333d2b36SAndroid Build Coastguard Worker	m := make(ClassLoaderContextMap)
56*333d2b36SAndroid Build Coastguard Worker
57*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, AnySdkVersion, "a'", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
58*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
59*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
60*333d2b36SAndroid Build Coastguard Worker
61*333d2b36SAndroid Build Coastguard Worker	// Add some libraries with nested subcontexts.
62*333d2b36SAndroid Build Coastguard Worker
63*333d2b36SAndroid Build Coastguard Worker	m1 := make(ClassLoaderContextMap)
64*333d2b36SAndroid Build Coastguard Worker	m1.AddContext(ctx, AnySdkVersion, "a1", optional, buildPath(ctx, "a1"), installPath(ctx, "a1"), nil)
65*333d2b36SAndroid Build Coastguard Worker	m1.AddContext(ctx, AnySdkVersion, "b1", optional, buildPath(ctx, "b1"), installPath(ctx, "b1"), nil)
66*333d2b36SAndroid Build Coastguard Worker
67*333d2b36SAndroid Build Coastguard Worker	m2 := make(ClassLoaderContextMap)
68*333d2b36SAndroid Build Coastguard Worker	m2.AddContext(ctx, AnySdkVersion, "a2", optional, buildPath(ctx, "a2"), installPath(ctx, "a2"), nil)
69*333d2b36SAndroid Build Coastguard Worker	m2.AddContext(ctx, AnySdkVersion, "b2", optional, buildPath(ctx, "b2"), installPath(ctx, "b2"), nil)
70*333d2b36SAndroid Build Coastguard Worker	m2.AddContext(ctx, AnySdkVersion, "c2", optional, buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
71*333d2b36SAndroid Build Coastguard Worker
72*333d2b36SAndroid Build Coastguard Worker	m3 := make(ClassLoaderContextMap)
73*333d2b36SAndroid Build Coastguard Worker	m3.AddContext(ctx, AnySdkVersion, "a3", optional, buildPath(ctx, "a3"), installPath(ctx, "a3"), nil)
74*333d2b36SAndroid Build Coastguard Worker	m3.AddContext(ctx, AnySdkVersion, "b3", optional, buildPath(ctx, "b3"), installPath(ctx, "b3"), nil)
75*333d2b36SAndroid Build Coastguard Worker
76*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), m2)
77*333d2b36SAndroid Build Coastguard Worker	// When the same library is both in conditional and unconditional context, it should be removed
78*333d2b36SAndroid Build Coastguard Worker	// from conditional context.
79*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, 42, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
80*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, AnySdkVersion, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
81*333d2b36SAndroid Build Coastguard Worker
82*333d2b36SAndroid Build Coastguard Worker	// Merge map with implicit root library that is among toplevel contexts => does nothing.
83*333d2b36SAndroid Build Coastguard Worker	m.AddContextMap(m1, "c")
84*333d2b36SAndroid Build Coastguard Worker	// Merge map with implicit root library that is not among toplevel contexts => all subcontexts
85*333d2b36SAndroid Build Coastguard Worker	// of the other map are added as toplevel contexts.
86*333d2b36SAndroid Build Coastguard Worker	m.AddContextMap(m3, "m_g")
87*333d2b36SAndroid Build Coastguard Worker
88*333d2b36SAndroid Build Coastguard Worker	// Compatibility libraries with unknown install paths get default paths.
89*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, 29, AndroidHidlManager, optional, buildPath(ctx, AndroidHidlManager), nil, nil)
90*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, 29, AndroidHidlBase, optional, buildPath(ctx, AndroidHidlBase), nil, nil)
91*333d2b36SAndroid Build Coastguard Worker
92*333d2b36SAndroid Build Coastguard Worker	// Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
93*333d2b36SAndroid Build Coastguard Worker	// needed as a compatibility library if "android.test.runner" is in CLC as well.
94*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, 30, AndroidTestMock, optional, buildPath(ctx, AndroidTestMock), nil, nil)
95*333d2b36SAndroid Build Coastguard Worker
96*333d2b36SAndroid Build Coastguard Worker	valid, validationError := validateClassLoaderContext(m)
97*333d2b36SAndroid Build Coastguard Worker
98*333d2b36SAndroid Build Coastguard Worker	fixClassLoaderContext(m)
99*333d2b36SAndroid Build Coastguard Worker
100*333d2b36SAndroid Build Coastguard Worker	var actualNames []string
101*333d2b36SAndroid Build Coastguard Worker	var actualPaths android.Paths
102*333d2b36SAndroid Build Coastguard Worker	var haveUsesLibsReq, haveUsesLibsOpt []string
103*333d2b36SAndroid Build Coastguard Worker	if valid && validationError == nil {
104*333d2b36SAndroid Build Coastguard Worker		actualNames, actualPaths = ComputeClassLoaderContextDependencies(m)
105*333d2b36SAndroid Build Coastguard Worker		haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
106*333d2b36SAndroid Build Coastguard Worker	}
107*333d2b36SAndroid Build Coastguard Worker
108*333d2b36SAndroid Build Coastguard Worker	// Test that validation is successful (all paths are known).
109*333d2b36SAndroid Build Coastguard Worker	t.Run("validate", func(t *testing.T) {
110*333d2b36SAndroid Build Coastguard Worker		if !(valid && validationError == nil) {
111*333d2b36SAndroid Build Coastguard Worker			t.Errorf("invalid class loader context")
112*333d2b36SAndroid Build Coastguard Worker		}
113*333d2b36SAndroid Build Coastguard Worker	})
114*333d2b36SAndroid Build Coastguard Worker
115*333d2b36SAndroid Build Coastguard Worker	// Test that all expected build paths are gathered.
116*333d2b36SAndroid Build Coastguard Worker	t.Run("names and paths", func(t *testing.T) {
117*333d2b36SAndroid Build Coastguard Worker		expectedNames := []string{
118*333d2b36SAndroid Build Coastguard Worker			"a'", "a1", "a2", "a3", "android.hidl.base-V1.0-java", "android.hidl.manager-V1.0-java", "b",
119*333d2b36SAndroid Build Coastguard Worker			"b1", "b2", "b3", "c", "c2", "d", "f",
120*333d2b36SAndroid Build Coastguard Worker		}
121*333d2b36SAndroid Build Coastguard Worker		expectedPaths := []string{
122*333d2b36SAndroid Build Coastguard Worker			"out/soong/android.hidl.manager-V1.0-java.jar", "out/soong/android.hidl.base-V1.0-java.jar",
123*333d2b36SAndroid Build Coastguard Worker			"out/soong/a.jar", "out/soong/b.jar", "out/soong/c.jar", "out/soong/d.jar",
124*333d2b36SAndroid Build Coastguard Worker			"out/soong/a2.jar", "out/soong/b2.jar", "out/soong/c2.jar",
125*333d2b36SAndroid Build Coastguard Worker			"out/soong/a1.jar", "out/soong/b1.jar",
126*333d2b36SAndroid Build Coastguard Worker			"out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
127*333d2b36SAndroid Build Coastguard Worker		}
128*333d2b36SAndroid Build Coastguard Worker		actualPathsStrs := actualPaths.Strings()
129*333d2b36SAndroid Build Coastguard Worker		// The order does not matter.
130*333d2b36SAndroid Build Coastguard Worker		sort.Strings(expectedNames)
131*333d2b36SAndroid Build Coastguard Worker		sort.Strings(actualNames)
132*333d2b36SAndroid Build Coastguard Worker		android.AssertArrayString(t, "", expectedNames, actualNames)
133*333d2b36SAndroid Build Coastguard Worker		sort.Strings(expectedPaths)
134*333d2b36SAndroid Build Coastguard Worker		sort.Strings(actualPathsStrs)
135*333d2b36SAndroid Build Coastguard Worker		android.AssertArrayString(t, "", expectedPaths, actualPathsStrs)
136*333d2b36SAndroid Build Coastguard Worker	})
137*333d2b36SAndroid Build Coastguard Worker
138*333d2b36SAndroid Build Coastguard Worker	// Test the JSON passed to construct_context.py.
139*333d2b36SAndroid Build Coastguard Worker	t.Run("json", func(t *testing.T) {
140*333d2b36SAndroid Build Coastguard Worker		// The tree structure within each SDK version should be kept exactly the same when serialized
141*333d2b36SAndroid Build Coastguard Worker		// to JSON. The order matters because the Python script keeps the order within each SDK version
142*333d2b36SAndroid Build Coastguard Worker		// as is.
143*333d2b36SAndroid Build Coastguard Worker		// The JSON is passed to the Python script as a commandline flag, so quotation ('') and escaping
144*333d2b36SAndroid Build Coastguard Worker		// must be performed.
145*333d2b36SAndroid Build Coastguard Worker		android.AssertStringEquals(t, "", strings.TrimSpace(`
146*333d2b36SAndroid Build Coastguard Worker'{"29":[{"Name":"android.hidl.manager-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.manager-V1.0-java.jar","Device":"/system/framework/android.hidl.manager-V1.0-java.jar","Subcontexts":[]},{"Name":"android.hidl.base-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.base-V1.0-java.jar","Device":"/system/framework/android.hidl.base-V1.0-java.jar","Subcontexts":[]}],"30":[],"42":[],"any":[{"Name":"a'\''","Optional":false,"Host":"out/soong/a.jar","Device":"/system/a.jar","Subcontexts":[]},{"Name":"b","Optional":false,"Host":"out/soong/b.jar","Device":"/system/b.jar","Subcontexts":[]},{"Name":"c","Optional":false,"Host":"out/soong/c.jar","Device":"/system/c.jar","Subcontexts":[]},{"Name":"d","Optional":false,"Host":"out/soong/d.jar","Device":"/system/d.jar","Subcontexts":[{"Name":"a2","Optional":false,"Host":"out/soong/a2.jar","Device":"/system/a2.jar","Subcontexts":[]},{"Name":"b2","Optional":false,"Host":"out/soong/b2.jar","Device":"/system/b2.jar","Subcontexts":[]},{"Name":"c2","Optional":false,"Host":"out/soong/c2.jar","Device":"/system/c2.jar","Subcontexts":[{"Name":"a1","Optional":false,"Host":"out/soong/a1.jar","Device":"/system/a1.jar","Subcontexts":[]},{"Name":"b1","Optional":false,"Host":"out/soong/b1.jar","Device":"/system/b1.jar","Subcontexts":[]}]}]},{"Name":"f","Optional":false,"Host":"out/soong/f.jar","Device":"/system/f.jar","Subcontexts":[]},{"Name":"a3","Optional":false,"Host":"out/soong/a3.jar","Device":"/system/a3.jar","Subcontexts":[]},{"Name":"b3","Optional":false,"Host":"out/soong/b3.jar","Device":"/system/b3.jar","Subcontexts":[]}]}'
147*333d2b36SAndroid Build Coastguard Worker`), m.DumpForFlag())
148*333d2b36SAndroid Build Coastguard Worker	})
149*333d2b36SAndroid Build Coastguard Worker
150*333d2b36SAndroid Build Coastguard Worker	// Test for libraries that are added by the manifest_fixer.
151*333d2b36SAndroid Build Coastguard Worker	t.Run("uses libs", func(t *testing.T) {
152*333d2b36SAndroid Build Coastguard Worker		wantUsesLibsReq := []string{"a'", "b", "c", "d", "f", "a3", "b3"}
153*333d2b36SAndroid Build Coastguard Worker		wantUsesLibsOpt := []string{}
154*333d2b36SAndroid Build Coastguard Worker		if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
155*333d2b36SAndroid Build Coastguard Worker			t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
156*333d2b36SAndroid Build Coastguard Worker		}
157*333d2b36SAndroid Build Coastguard Worker		if !reflect.DeepEqual(wantUsesLibsOpt, haveUsesLibsOpt) {
158*333d2b36SAndroid Build Coastguard Worker			t.Errorf("\nwant optional uses libs: %s\nhave optional uses libs: %s", wantUsesLibsOpt, haveUsesLibsOpt)
159*333d2b36SAndroid Build Coastguard Worker		}
160*333d2b36SAndroid Build Coastguard Worker	})
161*333d2b36SAndroid Build Coastguard Worker}
162*333d2b36SAndroid Build Coastguard Worker
163*333d2b36SAndroid Build Coastguard Workerfunc TestCLCJson(t *testing.T) {
164*333d2b36SAndroid Build Coastguard Worker	ctx := testContext()
165*333d2b36SAndroid Build Coastguard Worker	optional := false
166*333d2b36SAndroid Build Coastguard Worker	m := make(ClassLoaderContextMap)
167*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
168*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
169*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
170*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
171*333d2b36SAndroid Build Coastguard Worker	jsonCLC := toJsonClassLoaderContext(m)
172*333d2b36SAndroid Build Coastguard Worker	restored := fromJsonClassLoaderContext(ctx, jsonCLC)
173*333d2b36SAndroid Build Coastguard Worker	android.AssertIntEquals(t, "The size of the maps should be the same.", len(m), len(restored))
174*333d2b36SAndroid Build Coastguard Worker	for k := range m {
175*333d2b36SAndroid Build Coastguard Worker		a, _ := m[k]
176*333d2b36SAndroid Build Coastguard Worker		b, ok := restored[k]
177*333d2b36SAndroid Build Coastguard Worker		android.AssertBoolEquals(t, "The both maps should have the same keys.", ok, true)
178*333d2b36SAndroid Build Coastguard Worker		android.AssertIntEquals(t, "The size of the elements should be the same.", len(a), len(b))
179*333d2b36SAndroid Build Coastguard Worker		for i, elemA := range a {
180*333d2b36SAndroid Build Coastguard Worker			before := fmt.Sprintf("%v", *elemA)
181*333d2b36SAndroid Build Coastguard Worker			after := fmt.Sprintf("%v", *b[i])
182*333d2b36SAndroid Build Coastguard Worker			android.AssertStringEquals(t, "The content should be the same.", before, after)
183*333d2b36SAndroid Build Coastguard Worker		}
184*333d2b36SAndroid Build Coastguard Worker	}
185*333d2b36SAndroid Build Coastguard Worker}
186*333d2b36SAndroid Build Coastguard Worker
187*333d2b36SAndroid Build Coastguard Worker// Test that unknown library paths cause a validation error.
188*333d2b36SAndroid Build Coastguard Workerfunc testCLCUnknownPath(t *testing.T, whichPath string) {
189*333d2b36SAndroid Build Coastguard Worker	ctx := testContext()
190*333d2b36SAndroid Build Coastguard Worker	optional := false
191*333d2b36SAndroid Build Coastguard Worker
192*333d2b36SAndroid Build Coastguard Worker	m := make(ClassLoaderContextMap)
193*333d2b36SAndroid Build Coastguard Worker	if whichPath == "build" {
194*333d2b36SAndroid Build Coastguard Worker		m.AddContext(ctx, AnySdkVersion, "a", optional, nil, nil, nil)
195*333d2b36SAndroid Build Coastguard Worker	} else {
196*333d2b36SAndroid Build Coastguard Worker		m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), nil, nil)
197*333d2b36SAndroid Build Coastguard Worker	}
198*333d2b36SAndroid Build Coastguard Worker
199*333d2b36SAndroid Build Coastguard Worker	// The library should be added to <uses-library> tags by the manifest_fixer.
200*333d2b36SAndroid Build Coastguard Worker	t.Run("uses libs", func(t *testing.T) {
201*333d2b36SAndroid Build Coastguard Worker		haveUsesLibsReq, haveUsesLibsOpt := m.UsesLibs()
202*333d2b36SAndroid Build Coastguard Worker		wantUsesLibsReq := []string{"a"}
203*333d2b36SAndroid Build Coastguard Worker		wantUsesLibsOpt := []string{}
204*333d2b36SAndroid Build Coastguard Worker		if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
205*333d2b36SAndroid Build Coastguard Worker			t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
206*333d2b36SAndroid Build Coastguard Worker		}
207*333d2b36SAndroid Build Coastguard Worker		if !reflect.DeepEqual(wantUsesLibsOpt, haveUsesLibsOpt) {
208*333d2b36SAndroid Build Coastguard Worker			t.Errorf("\nwant optional uses libs: %s\nhave optional uses libs: %s", wantUsesLibsOpt, haveUsesLibsOpt)
209*333d2b36SAndroid Build Coastguard Worker		}
210*333d2b36SAndroid Build Coastguard Worker	})
211*333d2b36SAndroid Build Coastguard Worker
212*333d2b36SAndroid Build Coastguard Worker	// But CLC cannot be constructed: there is a validation error.
213*333d2b36SAndroid Build Coastguard Worker	_, err := validateClassLoaderContext(m)
214*333d2b36SAndroid Build Coastguard Worker	checkError(t, err, fmt.Sprintf("invalid %s path for <uses-library> \"a\"", whichPath))
215*333d2b36SAndroid Build Coastguard Worker}
216*333d2b36SAndroid Build Coastguard Worker
217*333d2b36SAndroid Build Coastguard Worker// Test that unknown build path is an error.
218*333d2b36SAndroid Build Coastguard Workerfunc TestCLCUnknownBuildPath(t *testing.T) {
219*333d2b36SAndroid Build Coastguard Worker	testCLCUnknownPath(t, "build")
220*333d2b36SAndroid Build Coastguard Worker}
221*333d2b36SAndroid Build Coastguard Worker
222*333d2b36SAndroid Build Coastguard Worker// Test that unknown install path is an error.
223*333d2b36SAndroid Build Coastguard Workerfunc TestCLCUnknownInstallPath(t *testing.T) {
224*333d2b36SAndroid Build Coastguard Worker	testCLCUnknownPath(t, "install")
225*333d2b36SAndroid Build Coastguard Worker}
226*333d2b36SAndroid Build Coastguard Worker
227*333d2b36SAndroid Build Coastguard Worker// An attempt to add conditional nested subcontext should fail.
228*333d2b36SAndroid Build Coastguard Workerfunc TestCLCNestedConditional(t *testing.T) {
229*333d2b36SAndroid Build Coastguard Worker	ctx := testContext()
230*333d2b36SAndroid Build Coastguard Worker	optional := false
231*333d2b36SAndroid Build Coastguard Worker	m1 := make(ClassLoaderContextMap)
232*333d2b36SAndroid Build Coastguard Worker	m1.AddContext(ctx, 42, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
233*333d2b36SAndroid Build Coastguard Worker	m := make(ClassLoaderContextMap)
234*333d2b36SAndroid Build Coastguard Worker	err := m.addContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), m1)
235*333d2b36SAndroid Build Coastguard Worker	checkError(t, err, "nested class loader context shouldn't have conditional part")
236*333d2b36SAndroid Build Coastguard Worker}
237*333d2b36SAndroid Build Coastguard Worker
238*333d2b36SAndroid Build Coastguard Workerfunc TestCLCMExcludeLibs(t *testing.T) {
239*333d2b36SAndroid Build Coastguard Worker	ctx := testContext()
240*333d2b36SAndroid Build Coastguard Worker	const optional = false
241*333d2b36SAndroid Build Coastguard Worker
242*333d2b36SAndroid Build Coastguard Worker	excludeLibs := func(t *testing.T, m ClassLoaderContextMap, excluded_libs ...string) ClassLoaderContextMap {
243*333d2b36SAndroid Build Coastguard Worker		// Dump the CLCM before creating a new copy that excludes a specific set of libraries.
244*333d2b36SAndroid Build Coastguard Worker		before := m.Dump()
245*333d2b36SAndroid Build Coastguard Worker
246*333d2b36SAndroid Build Coastguard Worker		// Create a new CLCM that excludes some libraries.
247*333d2b36SAndroid Build Coastguard Worker		c := m.ExcludeLibs(excluded_libs)
248*333d2b36SAndroid Build Coastguard Worker
249*333d2b36SAndroid Build Coastguard Worker		// Make sure that the original CLCM was not changed.
250*333d2b36SAndroid Build Coastguard Worker		after := m.Dump()
251*333d2b36SAndroid Build Coastguard Worker		android.AssertStringEquals(t, "input CLCM modified", before, after)
252*333d2b36SAndroid Build Coastguard Worker
253*333d2b36SAndroid Build Coastguard Worker		return c
254*333d2b36SAndroid Build Coastguard Worker	}
255*333d2b36SAndroid Build Coastguard Worker
256*333d2b36SAndroid Build Coastguard Worker	t.Run("exclude nothing", func(t *testing.T) {
257*333d2b36SAndroid Build Coastguard Worker		m := make(ClassLoaderContextMap)
258*333d2b36SAndroid Build Coastguard Worker		m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
259*333d2b36SAndroid Build Coastguard Worker
260*333d2b36SAndroid Build Coastguard Worker		a := excludeLibs(t, m)
261*333d2b36SAndroid Build Coastguard Worker
262*333d2b36SAndroid Build Coastguard Worker		android.AssertStringEquals(t, "output CLCM ", `{
263*333d2b36SAndroid Build Coastguard Worker  "28": [
264*333d2b36SAndroid Build Coastguard Worker    {
265*333d2b36SAndroid Build Coastguard Worker      "Name": "a",
266*333d2b36SAndroid Build Coastguard Worker      "Optional": false,
267*333d2b36SAndroid Build Coastguard Worker      "Host": "out/soong/a.jar",
268*333d2b36SAndroid Build Coastguard Worker      "Device": "/system/a.jar",
269*333d2b36SAndroid Build Coastguard Worker      "Subcontexts": []
270*333d2b36SAndroid Build Coastguard Worker    }
271*333d2b36SAndroid Build Coastguard Worker  ]
272*333d2b36SAndroid Build Coastguard Worker}`, a.Dump())
273*333d2b36SAndroid Build Coastguard Worker	})
274*333d2b36SAndroid Build Coastguard Worker
275*333d2b36SAndroid Build Coastguard Worker	t.Run("one item from list", func(t *testing.T) {
276*333d2b36SAndroid Build Coastguard Worker		m := make(ClassLoaderContextMap)
277*333d2b36SAndroid Build Coastguard Worker		m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
278*333d2b36SAndroid Build Coastguard Worker		m.AddContext(ctx, 28, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
279*333d2b36SAndroid Build Coastguard Worker
280*333d2b36SAndroid Build Coastguard Worker		a := excludeLibs(t, m, "a")
281*333d2b36SAndroid Build Coastguard Worker
282*333d2b36SAndroid Build Coastguard Worker		expected := `{
283*333d2b36SAndroid Build Coastguard Worker  "28": [
284*333d2b36SAndroid Build Coastguard Worker    {
285*333d2b36SAndroid Build Coastguard Worker      "Name": "b",
286*333d2b36SAndroid Build Coastguard Worker      "Optional": false,
287*333d2b36SAndroid Build Coastguard Worker      "Host": "out/soong/b.jar",
288*333d2b36SAndroid Build Coastguard Worker      "Device": "/system/b.jar",
289*333d2b36SAndroid Build Coastguard Worker      "Subcontexts": []
290*333d2b36SAndroid Build Coastguard Worker    }
291*333d2b36SAndroid Build Coastguard Worker  ]
292*333d2b36SAndroid Build Coastguard Worker}`
293*333d2b36SAndroid Build Coastguard Worker		android.AssertStringEquals(t, "output CLCM ", expected, a.Dump())
294*333d2b36SAndroid Build Coastguard Worker	})
295*333d2b36SAndroid Build Coastguard Worker
296*333d2b36SAndroid Build Coastguard Worker	t.Run("all items from a list", func(t *testing.T) {
297*333d2b36SAndroid Build Coastguard Worker		m := make(ClassLoaderContextMap)
298*333d2b36SAndroid Build Coastguard Worker		m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
299*333d2b36SAndroid Build Coastguard Worker		m.AddContext(ctx, 28, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
300*333d2b36SAndroid Build Coastguard Worker
301*333d2b36SAndroid Build Coastguard Worker		a := excludeLibs(t, m, "a", "b")
302*333d2b36SAndroid Build Coastguard Worker
303*333d2b36SAndroid Build Coastguard Worker		android.AssertStringEquals(t, "output CLCM ", `{}`, a.Dump())
304*333d2b36SAndroid Build Coastguard Worker	})
305*333d2b36SAndroid Build Coastguard Worker
306*333d2b36SAndroid Build Coastguard Worker	t.Run("items from a subcontext", func(t *testing.T) {
307*333d2b36SAndroid Build Coastguard Worker		s := make(ClassLoaderContextMap)
308*333d2b36SAndroid Build Coastguard Worker		s.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
309*333d2b36SAndroid Build Coastguard Worker		s.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
310*333d2b36SAndroid Build Coastguard Worker
311*333d2b36SAndroid Build Coastguard Worker		m := make(ClassLoaderContextMap)
312*333d2b36SAndroid Build Coastguard Worker		m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), s)
313*333d2b36SAndroid Build Coastguard Worker
314*333d2b36SAndroid Build Coastguard Worker		a := excludeLibs(t, m, "b")
315*333d2b36SAndroid Build Coastguard Worker
316*333d2b36SAndroid Build Coastguard Worker		android.AssertStringEquals(t, "output CLCM ", `{
317*333d2b36SAndroid Build Coastguard Worker  "28": [
318*333d2b36SAndroid Build Coastguard Worker    {
319*333d2b36SAndroid Build Coastguard Worker      "Name": "a",
320*333d2b36SAndroid Build Coastguard Worker      "Optional": false,
321*333d2b36SAndroid Build Coastguard Worker      "Host": "out/soong/a.jar",
322*333d2b36SAndroid Build Coastguard Worker      "Device": "/system/a.jar",
323*333d2b36SAndroid Build Coastguard Worker      "Subcontexts": [
324*333d2b36SAndroid Build Coastguard Worker        {
325*333d2b36SAndroid Build Coastguard Worker          "Name": "c",
326*333d2b36SAndroid Build Coastguard Worker          "Optional": false,
327*333d2b36SAndroid Build Coastguard Worker          "Host": "out/soong/c.jar",
328*333d2b36SAndroid Build Coastguard Worker          "Device": "/system/c.jar",
329*333d2b36SAndroid Build Coastguard Worker          "Subcontexts": []
330*333d2b36SAndroid Build Coastguard Worker        }
331*333d2b36SAndroid Build Coastguard Worker      ]
332*333d2b36SAndroid Build Coastguard Worker    }
333*333d2b36SAndroid Build Coastguard Worker  ]
334*333d2b36SAndroid Build Coastguard Worker}`, a.Dump())
335*333d2b36SAndroid Build Coastguard Worker	})
336*333d2b36SAndroid Build Coastguard Worker}
337*333d2b36SAndroid Build Coastguard Worker
338*333d2b36SAndroid Build Coastguard Worker// Test that CLC is correctly serialized to JSON.
339*333d2b36SAndroid Build Coastguard Workerfunc TestCLCtoJSON(t *testing.T) {
340*333d2b36SAndroid Build Coastguard Worker	ctx := testContext()
341*333d2b36SAndroid Build Coastguard Worker	optional := false
342*333d2b36SAndroid Build Coastguard Worker	m := make(ClassLoaderContextMap)
343*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
344*333d2b36SAndroid Build Coastguard Worker	m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
345*333d2b36SAndroid Build Coastguard Worker	android.AssertStringEquals(t, "output CLCM ", `{
346*333d2b36SAndroid Build Coastguard Worker  "28": [
347*333d2b36SAndroid Build Coastguard Worker    {
348*333d2b36SAndroid Build Coastguard Worker      "Name": "a",
349*333d2b36SAndroid Build Coastguard Worker      "Optional": false,
350*333d2b36SAndroid Build Coastguard Worker      "Host": "out/soong/a.jar",
351*333d2b36SAndroid Build Coastguard Worker      "Device": "/system/a.jar",
352*333d2b36SAndroid Build Coastguard Worker      "Subcontexts": []
353*333d2b36SAndroid Build Coastguard Worker    }
354*333d2b36SAndroid Build Coastguard Worker  ],
355*333d2b36SAndroid Build Coastguard Worker  "any": [
356*333d2b36SAndroid Build Coastguard Worker    {
357*333d2b36SAndroid Build Coastguard Worker      "Name": "b",
358*333d2b36SAndroid Build Coastguard Worker      "Optional": false,
359*333d2b36SAndroid Build Coastguard Worker      "Host": "out/soong/b.jar",
360*333d2b36SAndroid Build Coastguard Worker      "Device": "/system/b.jar",
361*333d2b36SAndroid Build Coastguard Worker      "Subcontexts": []
362*333d2b36SAndroid Build Coastguard Worker    }
363*333d2b36SAndroid Build Coastguard Worker  ]
364*333d2b36SAndroid Build Coastguard Worker}`, m.Dump())
365*333d2b36SAndroid Build Coastguard Worker}
366*333d2b36SAndroid Build Coastguard Worker
367*333d2b36SAndroid Build Coastguard Workerfunc checkError(t *testing.T, have error, want string) {
368*333d2b36SAndroid Build Coastguard Worker	if have == nil {
369*333d2b36SAndroid Build Coastguard Worker		t.Errorf("\nwant error: '%s'\nhave: none", want)
370*333d2b36SAndroid Build Coastguard Worker	} else if msg := have.Error(); !strings.HasPrefix(msg, want) {
371*333d2b36SAndroid Build Coastguard Worker		t.Errorf("\nwant error: '%s'\nhave error: '%s'\n", want, msg)
372*333d2b36SAndroid Build Coastguard Worker	}
373*333d2b36SAndroid Build Coastguard Worker}
374*333d2b36SAndroid Build Coastguard Worker
375*333d2b36SAndroid Build Coastguard Workerfunc testContext() android.ModuleInstallPathContext {
376*333d2b36SAndroid Build Coastguard Worker	config := android.TestConfig("out", nil, "", nil)
377*333d2b36SAndroid Build Coastguard Worker	return android.ModuleInstallPathContextForTesting(config)
378*333d2b36SAndroid Build Coastguard Worker}
379*333d2b36SAndroid Build Coastguard Worker
380*333d2b36SAndroid Build Coastguard Workerfunc buildPath(ctx android.PathContext, lib string) android.Path {
381*333d2b36SAndroid Build Coastguard Worker	return android.PathForOutput(ctx, lib+".jar")
382*333d2b36SAndroid Build Coastguard Worker}
383*333d2b36SAndroid Build Coastguard Worker
384*333d2b36SAndroid Build Coastguard Workerfunc installPath(ctx android.ModuleInstallPathContext, lib string) android.InstallPath {
385*333d2b36SAndroid Build Coastguard Worker	return android.PathForModuleInstall(ctx, lib+".jar")
386*333d2b36SAndroid Build Coastguard Worker}
387