• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
15 package main
16 
17 import (
18 	"bytes"
19 	"fmt"
20 	"reflect"
21 	"testing"
22 
23 	"google.golang.org/protobuf/encoding/prototext"
24 
25 	bp "android/soong/cmd/extract_apks/bundle_proto"
26 	"android/soong/third_party/zip"
27 )
28 
29 type testConfigDesc struct {
30 	name         string
31 	targetConfig TargetConfig
32 	expected     SelectionResult
33 }
34 
35 type testDesc struct {
36 	protoText string
37 	configs   []testConfigDesc
38 }
39 
40 func TestSelectApks_ApkSet(t *testing.T) {
41 	testCases := []testDesc{
42 		{
43 			protoText: `
44 variant {
45   targeting {
46     sdk_version_targeting {
47       value { min { value: 29 } } } }
48   apk_set {
49     module_metadata {
50       name: "base" targeting {} delivery_type: INSTALL_TIME }
51     apk_description {
52       targeting {
53         screen_density_targeting {
54           value { density_alias: LDPI } }
55         sdk_version_targeting {
56           value { min { value: 21 } } } }
57       path: "splits/base-ldpi.apk"
58       split_apk_metadata { split_id: "config.ldpi" } }
59     apk_description {
60       targeting {
61         screen_density_targeting {
62           value { density_alias: MDPI } }
63         sdk_version_targeting {
64           value { min { value: 21 } } } }
65       path: "splits/base-mdpi.apk"
66       split_apk_metadata { split_id: "config.mdpi" } }
67     apk_description {
68       targeting {
69         sdk_version_targeting {
70           value { min { value: 21 } } } }
71       path: "splits/base-master.apk"
72       split_apk_metadata { is_master_split: true } }
73     apk_description {
74       targeting {
75         abi_targeting {
76           value { alias: ARMEABI_V7A }
77           alternatives { alias: ARM64_V8A }
78           alternatives { alias: X86 }
79           alternatives { alias: X86_64 } }
80         sdk_version_targeting {
81           value { min { value: 21 } } } }
82       path: "splits/base-armeabi_v7a.apk"
83       split_apk_metadata { split_id: "config.armeabi_v7a" } }
84     apk_description {
85       targeting {
86         abi_targeting {
87           value { alias: ARM64_V8A }
88           alternatives { alias: ARMEABI_V7A }
89           alternatives { alias: X86 }
90           alternatives { alias: X86_64 } }
91         sdk_version_targeting {
92           value { min { value: 21 } } } }
93       path: "splits/base-arm64_v8a.apk"
94       split_apk_metadata { split_id: "config.arm64_v8a" } }
95     apk_description {
96       targeting {
97         abi_targeting {
98           value { alias: X86 }
99           alternatives { alias: ARMEABI_V7A }
100           alternatives { alias: ARM64_V8A }
101           alternatives { alias: X86_64 } }
102         sdk_version_targeting {
103           value { min { value: 21 } } } }
104       path: "splits/base-x86.apk"
105       split_apk_metadata { split_id: "config.x86" } }
106     apk_description {
107       targeting {
108         abi_targeting {
109           value { alias: X86_64 }
110           alternatives { alias: ARMEABI_V7A }
111           alternatives { alias: ARM64_V8A }
112           alternatives { alias: X86 } }
113         sdk_version_targeting {
114           value { min { value: 21 } } } }
115       path: "splits/base-x86_64.apk"
116       split_apk_metadata { split_id: "config.x86_64" } } }
117 }
118 bundletool {
119   version: "0.10.3" }
120 
121 `,
122 			configs: []testConfigDesc{
123 				{
124 					name: "one",
125 					targetConfig: TargetConfig{
126 						sdkVersion: 29,
127 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
128 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
129 						},
130 						abis: map[bp.Abi_AbiAlias]int{
131 							bp.Abi_ARMEABI_V7A: 0,
132 							bp.Abi_ARM64_V8A:   1,
133 						},
134 					},
135 					expected: SelectionResult{
136 						"base",
137 						[]string{
138 							"splits/base-ldpi.apk",
139 							"splits/base-mdpi.apk",
140 							"splits/base-master.apk",
141 							"splits/base-armeabi_v7a.apk",
142 						},
143 					},
144 				},
145 				{
146 					name: "two",
147 					targetConfig: TargetConfig{
148 						sdkVersion: 29,
149 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
150 							bp.ScreenDensity_LDPI: true,
151 						},
152 						abis: map[bp.Abi_AbiAlias]int{},
153 					},
154 					expected: SelectionResult{
155 						"base",
156 						[]string{
157 							"splits/base-ldpi.apk",
158 							"splits/base-master.apk",
159 						},
160 					},
161 				},
162 				{
163 					name: "three",
164 					targetConfig: TargetConfig{
165 						sdkVersion: 20,
166 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
167 							bp.ScreenDensity_LDPI: true,
168 						},
169 						abis: map[bp.Abi_AbiAlias]int{},
170 					},
171 					expected: SelectionResult{
172 						"",
173 						nil,
174 					},
175 				},
176 				{
177 					name: "four",
178 					targetConfig: TargetConfig{
179 						sdkVersion: 29,
180 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
181 							bp.ScreenDensity_MDPI: true,
182 						},
183 						abis: map[bp.Abi_AbiAlias]int{
184 							bp.Abi_ARM64_V8A:   0,
185 							bp.Abi_ARMEABI_V7A: 1,
186 						},
187 					},
188 					expected: SelectionResult{
189 						"base",
190 						[]string{
191 							"splits/base-mdpi.apk",
192 							"splits/base-master.apk",
193 							"splits/base-arm64_v8a.apk",
194 						},
195 					},
196 				},
197 			},
198 		},
199 		{
200 			protoText: `
201 variant {
202   targeting {
203     sdk_version_targeting {
204       value { min { value: 10000 } } } }
205   apk_set {
206     module_metadata {
207       name: "base" targeting {} delivery_type: INSTALL_TIME }
208     apk_description {
209       targeting {
210         sdk_version_targeting {
211           value { min { value: 21 } } } }
212       path: "splits/base-master.apk"
213       split_apk_metadata { is_master_split: true } } } }`,
214 			configs: []testConfigDesc{
215 				{
216 					name: "Prerelease",
217 					targetConfig: TargetConfig{
218 						sdkVersion:       30,
219 						screenDpi:        map[bp.ScreenDensity_DensityAlias]bool{},
220 						abis:             map[bp.Abi_AbiAlias]int{},
221 						allowPrereleased: true,
222 					},
223 					expected: SelectionResult{
224 						"base",
225 						[]string{"splits/base-master.apk"},
226 					},
227 				},
228 			},
229 		},
230 		{
231 			protoText: `
232 variant {
233   targeting {
234     sdk_version_targeting {
235       value { min { value: 29 } } } }
236   apk_set {
237     module_metadata {
238       name: "base" targeting {} delivery_type: INSTALL_TIME }
239     apk_description {
240       targeting {}
241       path: "universal.apk"
242       standalone_apk_metadata { fused_module_name: "base" } } } }`,
243 			configs: []testConfigDesc{
244 				{
245 					name:         "Universal",
246 					targetConfig: TargetConfig{sdkVersion: 30},
247 					expected: SelectionResult{
248 						"base",
249 						[]string{"universal.apk"},
250 					},
251 				},
252 			},
253 		},
254 	}
255 	for _, testCase := range testCases {
256 		var toc bp.BuildApksResult
257 		if err := prototext.Unmarshal([]byte(testCase.protoText), &toc); err != nil {
258 			t.Fatal(err)
259 		}
260 		for _, config := range testCase.configs {
261 			actual := selectApks(&toc, config.targetConfig)
262 			if !reflect.DeepEqual(config.expected, actual) {
263 				t.Errorf("%s: expected %v, got %v", config.name, config.expected, actual)
264 			}
265 		}
266 	}
267 }
268 
269 func TestSelectApks_ApexSet(t *testing.T) {
270 	testCases := []testDesc{
271 		{
272 			protoText: `
273 variant {
274   targeting {
275     sdk_version_targeting {
276       value { min { value: 29 } } } }
277   apk_set {
278     module_metadata {
279       name: "base" targeting {} delivery_type: INSTALL_TIME }
280     apk_description {
281       targeting {
282         multi_abi_targeting {
283           value { abi { alias: ARMEABI_V7A } }
284           alternatives { abi { alias: ARM64_V8A } }
285           alternatives { abi { alias: X86 } }
286           alternatives { abi { alias: X86_64 } } }
287         sdk_version_targeting {
288           value { min { value: 21 } } } }
289       path: "standalones/standalone-armeabi_v7a.apex"
290       apex_apk_metadata { } }
291     apk_description {
292       targeting {
293         multi_abi_targeting {
294           value { abi { alias: ARM64_V8A } }
295           alternatives { abi { alias: ARMEABI_V7A } }
296           alternatives { abi { alias: X86 } }
297           alternatives { abi { alias: X86_64 } } }
298         sdk_version_targeting {
299           value { min { value: 21 } } } }
300       path: "standalones/standalone-arm64_v8a.apex"
301       apex_apk_metadata { } }
302     apk_description {
303       targeting {
304         multi_abi_targeting {
305           value { abi { alias: X86 } }
306           alternatives { abi { alias: ARMEABI_V7A } }
307           alternatives { abi { alias: ARM64_V8A } }
308           alternatives { abi { alias: X86_64 } } }
309         sdk_version_targeting {
310           value { min { value: 21 } } } }
311       path: "standalones/standalone-x86.apex"
312       apex_apk_metadata { } }
313     apk_description {
314       targeting {
315         multi_abi_targeting {
316           value { abi { alias: X86_64 } }
317           alternatives { abi { alias: ARMEABI_V7A } }
318           alternatives { abi { alias: ARM64_V8A } }
319           alternatives { abi { alias: X86 } } }
320         sdk_version_targeting {
321           value { min { value: 21 } } } }
322       path: "standalones/standalone-x86_64.apex"
323       apex_apk_metadata { } } }
324 }
325 bundletool {
326   version: "0.10.3" }
327 
328 `,
329 			configs: []testConfigDesc{
330 				{
331 					name: "order matches priorities",
332 					targetConfig: TargetConfig{
333 						sdkVersion: 29,
334 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
335 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
336 						},
337 						abis: map[bp.Abi_AbiAlias]int{
338 							bp.Abi_ARM64_V8A:   0,
339 							bp.Abi_ARMEABI_V7A: 1,
340 						},
341 					},
342 					expected: SelectionResult{
343 						"base",
344 						[]string{
345 							"standalones/standalone-arm64_v8a.apex",
346 						},
347 					},
348 				},
349 				{
350 					name: "order doesn't match priorities",
351 					targetConfig: TargetConfig{
352 						sdkVersion: 29,
353 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
354 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
355 						},
356 						abis: map[bp.Abi_AbiAlias]int{
357 							bp.Abi_ARMEABI_V7A: 0,
358 							bp.Abi_ARM64_V8A:   1,
359 						},
360 					},
361 					expected: SelectionResult{
362 						"base",
363 						[]string{
364 							"standalones/standalone-arm64_v8a.apex",
365 						},
366 					},
367 				},
368 				{
369 					name: "single choice",
370 					targetConfig: TargetConfig{
371 						sdkVersion: 29,
372 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
373 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
374 						},
375 						abis: map[bp.Abi_AbiAlias]int{
376 							bp.Abi_ARMEABI_V7A: 0,
377 						},
378 					},
379 					expected: SelectionResult{
380 						"base",
381 						[]string{
382 							"standalones/standalone-armeabi_v7a.apex",
383 						},
384 					},
385 				},
386 				{
387 					name: "cross platform",
388 					targetConfig: TargetConfig{
389 						sdkVersion: 29,
390 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
391 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
392 						},
393 						abis: map[bp.Abi_AbiAlias]int{
394 							bp.Abi_ARM64_V8A: 0,
395 							bp.Abi_MIPS64:    1,
396 							bp.Abi_X86:       2,
397 						},
398 					},
399 					expected: SelectionResult{
400 						"base",
401 						[]string{
402 							"standalones/standalone-x86.apex",
403 						},
404 					},
405 				},
406 			},
407 		},
408 	}
409 	for _, testCase := range testCases {
410 		var toc bp.BuildApksResult
411 		if err := prototext.Unmarshal([]byte(testCase.protoText), &toc); err != nil {
412 			t.Fatal(err)
413 		}
414 		for _, config := range testCase.configs {
415 			actual := selectApks(&toc, config.targetConfig)
416 			if !reflect.DeepEqual(config.expected, actual) {
417 				t.Errorf("%s: expected %v, got %v", config.name, config.expected, actual)
418 			}
419 		}
420 	}
421 }
422 
423 func TestSelectApks_ApexSet_Variants(t *testing.T) {
424 	testCases := []testDesc{
425 		{
426 			protoText: `
427 variant {
428 	targeting {
429 		sdk_version_targeting {value {min {value: 29}}}
430 		multi_abi_targeting {
431 			value {abi {alias: ARMEABI_V7A}}
432 			alternatives {
433 				abi {alias: ARMEABI_V7A}
434 				abi {alias: ARM64_V8A}
435 			}
436 			alternatives {abi {alias: ARM64_V8A}}
437 			alternatives {abi {alias: X86}}
438 			alternatives {
439 				abi {alias: X86}
440 				abi {alias: X86_64}
441 			}
442 		}
443 	}
444 	apk_set {
445 		module_metadata {
446 			name: "base"
447 			delivery_type: INSTALL_TIME
448 		}
449 		apk_description {
450 			targeting {
451 				multi_abi_targeting {
452 					value {abi {alias: ARMEABI_V7A}}
453 					alternatives {
454 						abi {alias: ARMEABI_V7A}
455 						abi {alias: ARM64_V8A}
456 					}
457 					alternatives {abi {alias: ARM64_V8A}}
458 					alternatives {abi {alias: X86}}
459 					alternatives {
460 						abi {alias: X86}
461 						abi {alias: X86_64}
462 					}
463 				}
464 			}
465 			path: "standalones/standalone-armeabi_v7a.apex"
466 		}
467 	}
468 	variant_number: 0
469 }
470 variant {
471 	targeting {
472 		sdk_version_targeting {value {min {value: 29}}}
473 		multi_abi_targeting {
474 			value {abi {alias: ARM64_V8A}}
475 			alternatives {abi {alias: ARMEABI_V7A}}
476 			alternatives {
477 				abi {alias: ARMEABI_V7A}
478 				abi {alias: ARM64_V8A}
479 			}
480 			alternatives {abi {alias: X86}}
481 			alternatives {
482 				abi {alias: X86}
483 				abi {alias: X86_64}
484 			}
485 		}
486 	}
487 	apk_set {
488 		module_metadata {
489 			name: "base"
490 			delivery_type: INSTALL_TIME
491 		}
492 		apk_description {
493 			targeting {
494 				multi_abi_targeting {
495 					value {abi {alias: ARM64_V8A}}
496 					alternatives {abi {alias: ARMEABI_V7A}}
497 					alternatives {
498 						abi {alias: ARMEABI_V7A}
499 						abi {alias: ARM64_V8A}
500 					}
501 					alternatives {abi {alias: X86}}
502 					alternatives {
503 						abi {alias: X86}
504 						abi {alias: X86_64}
505 					}
506 				}
507 			}
508 			path: "standalones/standalone-arm64_v8a.apex"
509 		}
510 	}
511 	variant_number: 1
512 }
513 variant {
514 	targeting {
515 		sdk_version_targeting {value {min {value: 29}}}
516 		multi_abi_targeting {
517 			value {
518 				abi {alias: ARMEABI_V7A}
519 				abi {alias: ARM64_V8A}
520 			}
521 			alternatives {abi {alias: ARMEABI_V7A}}
522 			alternatives {abi {alias: ARM64_V8A}}
523 			alternatives {abi {alias: X86}}
524 			alternatives {
525 				abi {alias: X86}
526 				abi {alias: X86_64}
527 			}
528 		}
529 	}
530 	apk_set {
531 		module_metadata {
532 			name: "base"
533 			delivery_type: INSTALL_TIME
534 		}
535 		apk_description {
536 			targeting {
537 				multi_abi_targeting {
538 					value {
539 						abi {alias: ARMEABI_V7A}
540 						abi {alias: ARM64_V8A}
541 					}
542 					alternatives {abi {alias: ARMEABI_V7A}}
543 					alternatives {abi {alias: ARM64_V8A}}
544 					alternatives {abi {alias: X86}}
545 					alternatives {
546 						abi {alias: X86}
547 						abi {alias: X86_64}
548 					}
549 				}
550 			}
551 			path: "standalones/standalone-armeabi_v7a.arm64_v8a.apex"
552 		}
553 	}
554 	variant_number: 2
555 }
556 variant {
557 	targeting {
558 		sdk_version_targeting {value {min {value: 29}}}
559 		multi_abi_targeting {
560 			value {abi {alias: X86}}
561 			alternatives {abi {alias: ARMEABI_V7A}}
562 			alternatives {
563 				abi {alias: ARMEABI_V7A}
564 				abi {alias: ARM64_V8A}
565 			}
566 			alternatives {abi {alias: ARM64_V8A}}
567 			alternatives {
568 				abi {alias: X86}
569 				abi {alias: X86_64}
570 			}
571 		}
572 	}
573 	apk_set {
574 		module_metadata {
575 			name: "base"
576 			delivery_type: INSTALL_TIME
577 		}
578 		apk_description {
579 			targeting {
580 				multi_abi_targeting {
581 					value {abi {alias: X86}}
582 					alternatives {abi {alias: ARMEABI_V7A}}
583 					alternatives {
584 						abi {alias: ARMEABI_V7A}
585 						abi {alias: ARM64_V8A}
586 					}
587 					alternatives {abi {alias: ARM64_V8A}}
588 					alternatives {
589 						abi {alias: X86}
590 						abi {alias: X86_64}
591 					}
592 				}
593 			}
594 			path: "standalones/standalone-x86.apex"
595 		}
596 	}
597 	variant_number: 3
598 }
599 variant {
600 	targeting {
601 		sdk_version_targeting {value {min {value: 29}}}
602 		multi_abi_targeting {
603 			value {
604 				abi {alias: X86}
605 				abi {alias: X86_64}
606 			}
607 			alternatives {abi {alias: ARMEABI_V7A}}
608 			alternatives {
609 				abi {alias: ARMEABI_V7A}
610 				abi {alias: ARM64_V8A}
611 			}
612 			alternatives {abi {alias: ARM64_V8A}}
613 			alternatives {abi {alias: X86}}
614 		}
615 	}
616 	apk_set {
617 		module_metadata {
618 			name: "base"
619 			delivery_type: INSTALL_TIME
620 		}
621 		apk_description {
622 			targeting {
623 				multi_abi_targeting {
624 					value {
625 						abi {alias: X86}
626 						abi {alias: X86_64}
627 					}
628 					alternatives {abi {alias: ARMEABI_V7A}}
629 					alternatives {
630 						abi {alias: ARMEABI_V7A}
631 						abi {alias: ARM64_V8A}
632 					}
633 					alternatives {abi {alias: ARM64_V8A}}
634 					alternatives {abi {alias: X86}}
635 				}
636 			}
637 			path: "standalones/standalone-x86.x86_64.apex"
638 		}
639   }
640   variant_number: 4
641 }
642 `,
643 			configs: []testConfigDesc{
644 				{
645 					name: "multi-variant multi-target ARM",
646 					targetConfig: TargetConfig{
647 						sdkVersion: 33,
648 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
649 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
650 						},
651 						abis: map[bp.Abi_AbiAlias]int{
652 							bp.Abi_ARM64_V8A:   0,
653 							bp.Abi_ARMEABI_V7A: 1,
654 						},
655 					},
656 					expected: SelectionResult{
657 						"base",
658 						[]string{
659 							"standalones/standalone-armeabi_v7a.arm64_v8a.apex",
660 						},
661 					},
662 				},
663 				{
664 					name: "multi-variant single-target arm",
665 					targetConfig: TargetConfig{
666 						sdkVersion: 33,
667 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
668 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
669 						},
670 						abis: map[bp.Abi_AbiAlias]int{
671 							bp.Abi_ARMEABI_V7A: 0,
672 						},
673 					},
674 					expected: SelectionResult{
675 						"base",
676 						[]string{
677 							"standalones/standalone-armeabi_v7a.apex",
678 						},
679 					},
680 				},
681 				{
682 					name: "multi-variant single-target arm64",
683 					targetConfig: TargetConfig{
684 						sdkVersion: 33,
685 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
686 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
687 						},
688 						abis: map[bp.Abi_AbiAlias]int{
689 							bp.Abi_ARM64_V8A: 0,
690 						},
691 					},
692 					expected: SelectionResult{
693 						"base",
694 						[]string{
695 							"standalones/standalone-arm64_v8a.apex",
696 						},
697 					},
698 				},
699 				{
700 					name: "multi-variant multi-target x86",
701 					targetConfig: TargetConfig{
702 						sdkVersion: 33,
703 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
704 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
705 						},
706 						abis: map[bp.Abi_AbiAlias]int{
707 							bp.Abi_X86:    0,
708 							bp.Abi_X86_64: 1,
709 						},
710 					},
711 					expected: SelectionResult{
712 						"base",
713 						[]string{
714 							"standalones/standalone-x86.x86_64.apex",
715 						},
716 					},
717 				},
718 				{
719 					name: "multi-variant single-target x86",
720 					targetConfig: TargetConfig{
721 						sdkVersion: 33,
722 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
723 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
724 						},
725 						abis: map[bp.Abi_AbiAlias]int{
726 							bp.Abi_X86: 0,
727 						},
728 					},
729 					expected: SelectionResult{
730 						"base",
731 						[]string{
732 							"standalones/standalone-x86.apex",
733 						},
734 					},
735 				},
736 				{
737 					name: "multi-variant single-target x86_64",
738 					targetConfig: TargetConfig{
739 						sdkVersion: 33,
740 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
741 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
742 						},
743 						abis: map[bp.Abi_AbiAlias]int{
744 							bp.Abi_X86_64: 0,
745 						},
746 					},
747 					expected: SelectionResult{
748 						"base",
749 						[]string{
750 							"standalones/standalone-x86.x86_64.apex",
751 						}},
752 				},
753 				{
754 					name: "multi-variant multi-target cross-target",
755 					targetConfig: TargetConfig{
756 						sdkVersion: 33,
757 						screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
758 							bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
759 						},
760 						abis: map[bp.Abi_AbiAlias]int{
761 							bp.Abi_ARM64_V8A: 0,
762 							bp.Abi_X86_64:    1,
763 						},
764 					},
765 					expected: SelectionResult{
766 						"base",
767 						[]string{
768 							"standalones/standalone-arm64_v8a.apex",
769 						},
770 					},
771 				},
772 			},
773 		},
774 	}
775 	for _, testCase := range testCases {
776 		var toc bp.BuildApksResult
777 		if err := prototext.Unmarshal([]byte(testCase.protoText), &toc); err != nil {
778 			t.Fatal(err)
779 		}
780 		for _, config := range testCase.configs {
781 			t.Run(config.name, func(t *testing.T) {
782 				actual := selectApks(&toc, config.targetConfig)
783 				if !reflect.DeepEqual(config.expected, actual) {
784 					t.Errorf("expected %v, got %v", config.expected, actual)
785 				}
786 			})
787 		}
788 	}
789 }
790 
791 type testZip2ZipWriter struct {
792 	entries map[string]string
793 }
794 
795 func (w testZip2ZipWriter) CopyFrom(file *zip.File, out string) error {
796 	if x, ok := w.entries[out]; ok {
797 		return fmt.Errorf("%s and %s both write to %s", x, file.Name, out)
798 	}
799 	w.entries[out] = file.Name
800 	return nil
801 }
802 
803 type testCaseWriteApks struct {
804 	name       string
805 	moduleName string
806 	stem       string
807 	partition  string
808 	// what we write from what
809 	zipEntries       map[string]string
810 	expectedApkcerts []string
811 }
812 
813 func TestWriteApks(t *testing.T) {
814 	testCases := []testCaseWriteApks{
815 		{
816 			name:       "splits",
817 			moduleName: "mybase",
818 			stem:       "Foo",
819 			partition:  "system",
820 			zipEntries: map[string]string{
821 				"Foo.apk":       "splits/mybase-master.apk",
822 				"Foo-xhdpi.apk": "splits/mybase-xhdpi.apk",
823 			},
824 			expectedApkcerts: []string{
825 				`name="Foo-xhdpi.apk" certificate="PRESIGNED" private_key="" partition="system"`,
826 				`name="Foo.apk" certificate="PRESIGNED" private_key="" partition="system"`,
827 			},
828 		},
829 		{
830 			name:       "universal",
831 			moduleName: "base",
832 			stem:       "Bar",
833 			partition:  "product",
834 			zipEntries: map[string]string{
835 				"Bar.apk": "universal.apk",
836 			},
837 			expectedApkcerts: []string{
838 				`name="Bar.apk" certificate="PRESIGNED" private_key="" partition="product"`,
839 			},
840 		},
841 	}
842 	for _, testCase := range testCases {
843 		t.Run(testCase.name, func(t *testing.T) {
844 			testZipBuf := &bytes.Buffer{}
845 			testZip := zip.NewWriter(testZipBuf)
846 			for _, in := range testCase.zipEntries {
847 				f, _ := testZip.Create(in)
848 				f.Write([]byte(in))
849 			}
850 			testZip.Close()
851 
852 			zipReader, _ := zip.NewReader(bytes.NewReader(testZipBuf.Bytes()), int64(testZipBuf.Len()))
853 
854 			apkSet := ApkSet{entries: make(map[string]*zip.File)}
855 			sel := SelectionResult{moduleName: testCase.moduleName}
856 			for _, f := range zipReader.File {
857 				apkSet.entries[f.Name] = f
858 				sel.entries = append(sel.entries, f.Name)
859 			}
860 
861 			zipWriter := testZip2ZipWriter{make(map[string]string)}
862 			outWriter := &bytes.Buffer{}
863 			config := TargetConfig{stem: testCase.stem}
864 			apkcerts, err := apkSet.writeApks(sel, config, outWriter, zipWriter, testCase.partition)
865 			if err != nil {
866 				t.Error(err)
867 			}
868 			expectedZipEntries := make(map[string]string)
869 			for k, v := range testCase.zipEntries {
870 				if k != testCase.stem+".apk" {
871 					expectedZipEntries[k] = v
872 				}
873 			}
874 			if !reflect.DeepEqual(expectedZipEntries, zipWriter.entries) {
875 				t.Errorf("expected zip entries %v, got %v", testCase.zipEntries, zipWriter.entries)
876 			}
877 			if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
878 				t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
879 			}
880 			if g, w := outWriter.String(), testCase.zipEntries[testCase.stem+".apk"]; !reflect.DeepEqual(g, w) {
881 				t.Errorf("expected output file contents %q, got %q", testCase.stem+".apk", outWriter.String())
882 			}
883 		})
884 	}
885 }
886