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