1a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal/* 2a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * Copyright (C) 2017 The Android Open Source Project 3a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * 4a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * Licensed under the Apache License, Version 2.0 (the "License"); 5a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * you may not use this file except in compliance with the License. 6a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * You may obtain a copy of the License at 7a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * 8a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * http://www.apache.org/licenses/LICENSE-2.0 9a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * 10a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * Unless required by applicable law or agreed to in writing, software 11a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * distributed under the License is distributed on an "AS IS" BASIS, 12a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * See the License for the specific language governing permissions and 14a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * limitations under the License. 15a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal */ 16a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawalpackage com.android.car.setupwizardlib.robolectric; 17a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal 186fd8a4056d8138b7040fe23e1cf1d4772681fbbaRoshan Agrawalimport android.annotation.NonNull; 192b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen 20a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawalimport org.junit.runners.model.InitializationError; 21a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawalimport org.robolectric.RobolectricTestRunner; 22a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawalimport org.robolectric.annotation.Config; 23a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawalimport org.robolectric.manifest.AndroidManifest; 24a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawalimport org.robolectric.res.Fs; 25a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawalimport org.robolectric.res.ResourcePath; 26a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal 272b780ca656252e9ebe86226e152a010089bf01e0Anthony Chenimport java.net.MalformedURLException; 282b780ca656252e9ebe86226e152a010089bf01e0Anthony Chenimport java.net.URL; 29921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxingimport java.util.HashMap; 30a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawalimport java.util.List; 31921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxingimport java.util.Map; 32a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal 33a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal/** 34a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * Custom test runner for the testing of CarSetupWizardLibrary. This is needed because the 35a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * default behavior for robolectric is just to grab the resource directory in the target package. 36a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * We want to override this to add several spanning different projects. 37a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal */ 38a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawalpublic class CarSetupWizardLibRobolectricTestRunner extends RobolectricTestRunner { 39921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing private static final Map<String, String> AAR_VERSIONS; 402b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen private static final String SUPPORT_RESOURCE_PATH_TEMPLATE = 412b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen "jar:file:prebuilts/sdk/current/androidx/m2repository/androidx/" 422b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen + "%1$s/%1$s/%2$s/%1$s-%2$s.aar!/res"; 43a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal 44921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing static { 45921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing AAR_VERSIONS = new HashMap<>(); 46921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing AAR_VERSIONS.put("car", "1.0.0-alpha3"); 47921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing AAR_VERSIONS.put("appcompat", "1.0.0-alpha1"); 48921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing } 49921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing 50a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal /** 51a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * We don't actually want to change this behavior, so we just call super. 52a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal */ 53a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal public CarSetupWizardLibRobolectricTestRunner(Class<?> testClass) throws InitializationError { 54a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal super(testClass); 55a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal } 56a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal 572b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen private static ResourcePath createResourcePath(@NonNull String filePath) { 582b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen try { 592b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen return new ResourcePath(null, Fs.fromURL(new URL(filePath)), null); 602b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen } catch (MalformedURLException e) { 612b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen throw new RuntimeException("CarSetupWizardRobolectricTestRunner failure", e); 622b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen } 632b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen } 642b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen 652b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen /** 662b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen * Create the resource path for a support library component's JAR. 672b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen */ 682b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen private static String createSupportResourcePathFromJar(@NonNull String componentId) { 69921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing if (!AAR_VERSIONS.containsKey(componentId)) { 70921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing throw new IllegalArgumentException("Unknown component " + componentId 71921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing + ". Update test with appropriate component name and version."); 72921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing } 73921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing return String.format(SUPPORT_RESOURCE_PATH_TEMPLATE, componentId, 74921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing AAR_VERSIONS.get(componentId)); 752b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen } 762b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen 77a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal /** 78a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * We are going to create our own custom manifest so that we can add multiple resource 79a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal * paths to it. This lets us access resources in both Settings and SettingsLib in our tests. 80a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal */ 81a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal @Override 82a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal protected AndroidManifest getAppManifest(Config config) { 83a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal // Using the manifest file's relative path, we can figure out the application directory. 842b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen String appRoot = "frameworks/opt/car/setupwizard/library"; 852b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen String manifestPath = appRoot + "/AndroidManifest.xml"; 862b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen String resDir = appRoot + "/res"; 872b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen String assetsDir = appRoot + config.assetDir(); 88a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal 89a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal // By adding any resources from libraries we need to the AndroidManifest, we can access 90a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal // them from within the parallel universe's resource loader. 912b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen return new AndroidManifest(Fs.fileFromPath(manifestPath), 922b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen Fs.fileFromPath(resDir), Fs.fileFromPath(assetsDir)) { 93a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal @Override 94a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal public List<ResourcePath> getIncludedResourcePaths() { 95a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal List<ResourcePath> paths = super.getIncludedResourcePaths(); 962b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen 972b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen paths.add(createResourcePath("file:" + resDir)); 982b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen paths.add(createResourcePath("file:" + appRoot + "/tests/robotests/res")); 992b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen 1002b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen // Support library resources. These need to point to the prebuilts of support 1012b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen // library and not the source. 1022b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen paths.add(createResourcePath(createSupportResourcePathFromJar("appcompat"))); 1032b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen paths.add(createResourcePath(createSupportResourcePathFromJar("car"))); 1042b780ca656252e9ebe86226e152a010089bf01e0Anthony Chen 105a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal return paths; 106a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal } 107a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal }; 108a636b2634354710e38872b74b7af4f867c464e3fRoshan Agrawal } 109921861167e4a99f5bf7f2315ba2508b0e9db3d05Yao, Yuxing} 110