blob: 7260abb64ea6fbf45492eaea568c543252ba42c6 [file] [log] [blame]
Ulya Trafimovich69612672020-10-20 17:41:54 +01001// Copyright 2020 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 dexpreopt
16
17// This file contains unit tests for class loader context structure.
18// For class loader context tests involving .bp files, see TestUsesLibraries in java package.
19
20import (
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000021 "fmt"
Ulya Trafimovich69612672020-10-20 17:41:54 +010022 "reflect"
Jiakai Zhanga4496782023-05-17 16:57:30 +010023 "sort"
Ulya Trafimovich69612672020-10-20 17:41:54 +010024 "strings"
25 "testing"
26
27 "android/soong/android"
28)
29
30func TestCLC(t *testing.T) {
31 // Construct class loader context with the following structure:
32 // .
33 // ├── 29
34 // │   ├── android.hidl.manager
35 // │   └── android.hidl.base
36 // │
37 // └── any
Jiakai Zhanga4496782023-05-17 16:57:30 +010038 // ├── a' (a single quotation mark (') is there to test escaping)
Ulya Trafimovich69612672020-10-20 17:41:54 +010039 // ├── b
40 // ├── c
41 // ├── d
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000042 // │   ├── a2
43 // │   ├── b2
44 // │   └── c2
45 // │   ├── a1
46 // │   └── b1
Ulya Trafimovich69612672020-10-20 17:41:54 +010047 // ├── f
48 // ├── a3
49 // └── b3
50 //
51 ctx := testContext()
52
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010053 optional := false
54
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000055 m := make(ClassLoaderContextMap)
Ulya Trafimovich69612672020-10-20 17:41:54 +010056
Jiakai Zhanga4496782023-05-17 16:57:30 +010057 m.AddContext(ctx, AnySdkVersion, "a'", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +010058 m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
59 m.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010060
61 // Add some libraries with nested subcontexts.
62
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000063 m1 := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +010064 m1.AddContext(ctx, AnySdkVersion, "a1", optional, buildPath(ctx, "a1"), installPath(ctx, "a1"), nil)
65 m1.AddContext(ctx, AnySdkVersion, "b1", optional, buildPath(ctx, "b1"), installPath(ctx, "b1"), nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010066
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000067 m2 := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +010068 m2.AddContext(ctx, AnySdkVersion, "a2", optional, buildPath(ctx, "a2"), installPath(ctx, "a2"), nil)
69 m2.AddContext(ctx, AnySdkVersion, "b2", optional, buildPath(ctx, "b2"), installPath(ctx, "b2"), nil)
70 m2.AddContext(ctx, AnySdkVersion, "c2", optional, buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
Ulya Trafimovich69612672020-10-20 17:41:54 +010071
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000072 m3 := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +010073 m3.AddContext(ctx, AnySdkVersion, "a3", optional, buildPath(ctx, "a3"), installPath(ctx, "a3"), nil)
74 m3.AddContext(ctx, AnySdkVersion, "b3", optional, buildPath(ctx, "b3"), installPath(ctx, "b3"), nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010075
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +010076 m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), m2)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000077 // When the same library is both in conditional and unconditional context, it should be removed
78 // from conditional context.
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +010079 m.AddContext(ctx, 42, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
80 m.AddContext(ctx, AnySdkVersion, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
Ulya Trafimovich18554242020-11-03 15:55:11 +000081
82 // Merge map with implicit root library that is among toplevel contexts => does nothing.
83 m.AddContextMap(m1, "c")
84 // Merge map with implicit root library that is not among toplevel contexts => all subcontexts
85 // of the other map are added as toplevel contexts.
86 m.AddContextMap(m3, "m_g")
Ulya Trafimovich69612672020-10-20 17:41:54 +010087
88 // Compatibility libraries with unknown install paths get default paths.
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +010089 m.AddContext(ctx, 29, AndroidHidlManager, optional, buildPath(ctx, AndroidHidlManager), nil, nil)
90 m.AddContext(ctx, 29, AndroidHidlBase, optional, buildPath(ctx, AndroidHidlBase), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010091
92 // Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
93 // needed as a compatibility library if "android.test.runner" is in CLC as well.
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +010094 m.AddContext(ctx, 30, AndroidTestMock, optional, buildPath(ctx, AndroidTestMock), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010095
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000096 valid, validationError := validateClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +010097
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000098 fixClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +010099
Jiakai Zhang51b2a8b2023-06-26 16:47:38 +0100100 var actualNames []string
101 var actualPaths android.Paths
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100102 var haveUsesLibsReq, haveUsesLibsOpt []string
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000103 if valid && validationError == nil {
Jiakai Zhang51b2a8b2023-06-26 16:47:38 +0100104 actualNames, actualPaths = ComputeClassLoaderContextDependencies(m)
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100105 haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
Ulya Trafimovich69612672020-10-20 17:41:54 +0100106 }
107
108 // Test that validation is successful (all paths are known).
109 t.Run("validate", func(t *testing.T) {
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000110 if !(valid && validationError == nil) {
Ulya Trafimovich69612672020-10-20 17:41:54 +0100111 t.Errorf("invalid class loader context")
112 }
113 })
114
Ulya Trafimovich69612672020-10-20 17:41:54 +0100115 // Test that all expected build paths are gathered.
Jiakai Zhang51b2a8b2023-06-26 16:47:38 +0100116 t.Run("names and paths", func(t *testing.T) {
117 expectedNames := []string{
118 "a'", "a1", "a2", "a3", "android.hidl.base-V1.0-java", "android.hidl.manager-V1.0-java", "b",
119 "b1", "b2", "b3", "c", "c2", "d", "f",
120 }
121 expectedPaths := []string{
Colin Cross7b6a55f2021-11-09 12:34:39 -0800122 "out/soong/android.hidl.manager-V1.0-java.jar", "out/soong/android.hidl.base-V1.0-java.jar",
123 "out/soong/a.jar", "out/soong/b.jar", "out/soong/c.jar", "out/soong/d.jar",
124 "out/soong/a2.jar", "out/soong/b2.jar", "out/soong/c2.jar",
125 "out/soong/a1.jar", "out/soong/b1.jar",
126 "out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
Ulya Trafimovich69612672020-10-20 17:41:54 +0100127 }
Jiakai Zhang51b2a8b2023-06-26 16:47:38 +0100128 actualPathsStrs := actualPaths.Strings()
Jiakai Zhanga4496782023-05-17 16:57:30 +0100129 // The order does not matter.
Jiakai Zhang51b2a8b2023-06-26 16:47:38 +0100130 sort.Strings(expectedNames)
131 sort.Strings(actualNames)
132 android.AssertArrayString(t, "", expectedNames, actualNames)
133 sort.Strings(expectedPaths)
134 sort.Strings(actualPathsStrs)
135 android.AssertArrayString(t, "", expectedPaths, actualPathsStrs)
Jiakai Zhanga4496782023-05-17 16:57:30 +0100136 })
137
138 // Test the JSON passed to construct_context.py.
139 t.Run("json", func(t *testing.T) {
140 // The tree structure within each SDK version should be kept exactly the same when serialized
141 // to JSON. The order matters because the Python script keeps the order within each SDK version
142 // as is.
143 // The JSON is passed to the Python script as a commandline flag, so quotation ('') and escaping
144 // must be performed.
145 android.AssertStringEquals(t, "", strings.TrimSpace(`
146'{"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`), m.DumpForFlag())
Ulya Trafimovich69612672020-10-20 17:41:54 +0100148 })
149
150 // Test for libraries that are added by the manifest_fixer.
151 t.Run("uses libs", func(t *testing.T) {
Jiakai Zhanga4496782023-05-17 16:57:30 +0100152 wantUsesLibsReq := []string{"a'", "b", "c", "d", "f", "a3", "b3"}
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100153 wantUsesLibsOpt := []string{}
154 if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
155 t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
156 }
157 if !reflect.DeepEqual(wantUsesLibsOpt, haveUsesLibsOpt) {
158 t.Errorf("\nwant optional uses libs: %s\nhave optional uses libs: %s", wantUsesLibsOpt, haveUsesLibsOpt)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100159 }
160 })
161}
162
Jeongik Cha19ade892021-04-22 20:55:21 +0900163func TestCLCJson(t *testing.T) {
164 ctx := testContext()
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100165 optional := false
Jeongik Cha19ade892021-04-22 20:55:21 +0900166 m := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100167 m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
168 m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
169 m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
170 m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
Jeongik Cha19ade892021-04-22 20:55:21 +0900171 jsonCLC := toJsonClassLoaderContext(m)
172 restored := fromJsonClassLoaderContext(ctx, jsonCLC)
173 android.AssertIntEquals(t, "The size of the maps should be the same.", len(m), len(restored))
174 for k := range m {
175 a, _ := m[k]
176 b, ok := restored[k]
177 android.AssertBoolEquals(t, "The both maps should have the same keys.", ok, true)
178 android.AssertIntEquals(t, "The size of the elements should be the same.", len(a), len(b))
179 for i, elemA := range a {
180 before := fmt.Sprintf("%v", *elemA)
181 after := fmt.Sprintf("%v", *b[i])
182 android.AssertStringEquals(t, "The content should be the same.", before, after)
183 }
184 }
185}
186
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000187// Test that unknown library paths cause a validation error.
188func testCLCUnknownPath(t *testing.T, whichPath string) {
Ulya Trafimovich69612672020-10-20 17:41:54 +0100189 ctx := testContext()
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100190 optional := false
Ulya Trafimovich69612672020-10-20 17:41:54 +0100191
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000192 m := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000193 if whichPath == "build" {
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100194 m.AddContext(ctx, AnySdkVersion, "a", optional, nil, nil, nil)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000195 } else {
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100196 m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), nil, nil)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000197 }
Ulya Trafimovich69612672020-10-20 17:41:54 +0100198
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000199 // The library should be added to <uses-library> tags by the manifest_fixer.
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000200 t.Run("uses libs", func(t *testing.T) {
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100201 haveUsesLibsReq, haveUsesLibsOpt := m.UsesLibs()
202 wantUsesLibsReq := []string{"a"}
203 wantUsesLibsOpt := []string{}
204 if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
205 t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
206 }
207 if !reflect.DeepEqual(wantUsesLibsOpt, haveUsesLibsOpt) {
208 t.Errorf("\nwant optional uses libs: %s\nhave optional uses libs: %s", wantUsesLibsOpt, haveUsesLibsOpt)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000209 }
210 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100211
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000212 // But CLC cannot be constructed: there is a validation error.
213 _, err := validateClassLoaderContext(m)
214 checkError(t, err, fmt.Sprintf("invalid %s path for <uses-library> \"a\"", whichPath))
215}
216
217// Test that unknown build path is an error.
218func TestCLCUnknownBuildPath(t *testing.T) {
219 testCLCUnknownPath(t, "build")
220}
221
222// Test that unknown install path is an error.
223func TestCLCUnknownInstallPath(t *testing.T) {
224 testCLCUnknownPath(t, "install")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100225}
226
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000227// An attempt to add conditional nested subcontext should fail.
228func TestCLCNestedConditional(t *testing.T) {
229 ctx := testContext()
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100230 optional := false
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000231 m1 := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100232 m1.AddContext(ctx, 42, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000233 m := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100234 err := m.addContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), m1)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000235 checkError(t, err, "nested class loader context shouldn't have conditional part")
236}
237
Paul Duffin06530572022-02-03 17:54:15 +0000238func TestCLCMExcludeLibs(t *testing.T) {
239 ctx := testContext()
240 const optional = false
Paul Duffin06530572022-02-03 17:54:15 +0000241
242 excludeLibs := func(t *testing.T, m ClassLoaderContextMap, excluded_libs ...string) ClassLoaderContextMap {
243 // Dump the CLCM before creating a new copy that excludes a specific set of libraries.
244 before := m.Dump()
245
246 // Create a new CLCM that excludes some libraries.
247 c := m.ExcludeLibs(excluded_libs)
248
249 // Make sure that the original CLCM was not changed.
250 after := m.Dump()
251 android.AssertStringEquals(t, "input CLCM modified", before, after)
252
253 return c
254 }
255
256 t.Run("exclude nothing", func(t *testing.T) {
257 m := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100258 m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
Paul Duffin06530572022-02-03 17:54:15 +0000259
260 a := excludeLibs(t, m)
261
262 android.AssertStringEquals(t, "output CLCM ", `{
263 "28": [
264 {
265 "Name": "a",
266 "Optional": false,
Paul Duffin06530572022-02-03 17:54:15 +0000267 "Host": "out/soong/a.jar",
268 "Device": "/system/a.jar",
269 "Subcontexts": []
270 }
271 ]
272}`, a.Dump())
273 })
274
275 t.Run("one item from list", func(t *testing.T) {
276 m := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100277 m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
278 m.AddContext(ctx, 28, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
Paul Duffin06530572022-02-03 17:54:15 +0000279
280 a := excludeLibs(t, m, "a")
281
282 expected := `{
283 "28": [
284 {
285 "Name": "b",
286 "Optional": false,
Paul Duffin06530572022-02-03 17:54:15 +0000287 "Host": "out/soong/b.jar",
288 "Device": "/system/b.jar",
289 "Subcontexts": []
290 }
291 ]
292}`
293 android.AssertStringEquals(t, "output CLCM ", expected, a.Dump())
294 })
295
296 t.Run("all items from a list", func(t *testing.T) {
297 m := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100298 m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
299 m.AddContext(ctx, 28, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
Paul Duffin06530572022-02-03 17:54:15 +0000300
301 a := excludeLibs(t, m, "a", "b")
302
303 android.AssertStringEquals(t, "output CLCM ", `{}`, a.Dump())
304 })
305
306 t.Run("items from a subcontext", func(t *testing.T) {
307 s := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100308 s.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
309 s.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
Paul Duffin06530572022-02-03 17:54:15 +0000310
311 m := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100312 m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), s)
Paul Duffin06530572022-02-03 17:54:15 +0000313
314 a := excludeLibs(t, m, "b")
315
316 android.AssertStringEquals(t, "output CLCM ", `{
317 "28": [
318 {
319 "Name": "a",
320 "Optional": false,
Paul Duffin06530572022-02-03 17:54:15 +0000321 "Host": "out/soong/a.jar",
322 "Device": "/system/a.jar",
323 "Subcontexts": [
324 {
325 "Name": "c",
326 "Optional": false,
Paul Duffin06530572022-02-03 17:54:15 +0000327 "Host": "out/soong/c.jar",
328 "Device": "/system/c.jar",
329 "Subcontexts": []
330 }
331 ]
332 }
333 ]
334}`, a.Dump())
335 })
336}
337
Ulya Trafimovich91f015e2022-04-27 17:51:49 +0100338// Test that CLC is correctly serialized to JSON.
339func TestCLCtoJSON(t *testing.T) {
340 ctx := testContext()
341 optional := false
Ulya Trafimovich91f015e2022-04-27 17:51:49 +0100342 m := make(ClassLoaderContextMap)
Ulya Trafimovichf5d91bb2022-05-04 12:00:02 +0100343 m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
344 m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
Ulya Trafimovich91f015e2022-04-27 17:51:49 +0100345 android.AssertStringEquals(t, "output CLCM ", `{
346 "28": [
347 {
348 "Name": "a",
349 "Optional": false,
Ulya Trafimovich91f015e2022-04-27 17:51:49 +0100350 "Host": "out/soong/a.jar",
351 "Device": "/system/a.jar",
352 "Subcontexts": []
353 }
354 ],
355 "any": [
356 {
357 "Name": "b",
358 "Optional": false,
Ulya Trafimovich91f015e2022-04-27 17:51:49 +0100359 "Host": "out/soong/b.jar",
360 "Device": "/system/b.jar",
361 "Subcontexts": []
362 }
363 ]
364}`, m.Dump())
365}
366
Ulya Trafimovich69612672020-10-20 17:41:54 +0100367func checkError(t *testing.T, have error, want string) {
368 if have == nil {
369 t.Errorf("\nwant error: '%s'\nhave: none", want)
370 } else if msg := have.Error(); !strings.HasPrefix(msg, want) {
371 t.Errorf("\nwant error: '%s'\nhave error: '%s'\n", want, msg)
372 }
373}
374
375func testContext() android.ModuleInstallPathContext {
376 config := android.TestConfig("out", nil, "", nil)
377 return android.ModuleInstallPathContextForTesting(config)
378}
379
380func buildPath(ctx android.PathContext, lib string) android.Path {
381 return android.PathForOutput(ctx, lib+".jar")
382}
383
384func installPath(ctx android.ModuleInstallPathContext, lib string) android.InstallPath {
385 return android.PathForModuleInstall(ctx, lib+".jar")
386}