1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.settings.testutils;
18 
19 import static org.mockito.Mockito.doAnswer;
20 import static org.mockito.Mockito.doReturn;
21 import static org.mockito.Mockito.mock;
22 
23 import android.car.Car;
24 import android.car.CarNotConnectedException;
25 import android.content.Context;
26 import android.content.ServiceConnection;
27 
28 import org.mockito.stubbing.Answer;
29 import org.robolectric.annotation.Implementation;
30 import org.robolectric.annotation.Implements;
31 import org.robolectric.annotation.Resetter;
32 
33 /**
34  * Shadow class for {@link Car}. Components in car support library expects
35  * this class to be available at run time.
36  */
37 @Implements(Car.class)
38 public class ShadowCar {
39 
40     private static Car sMockCar = mock(Car.class);
41     private static boolean sIsConnected;
42     private static String sServiceName;
43     private static Object sCarManager;
44 
45     /**
46      * Returns a mocked version of a {@link Car} object.
47      */
48     @Implementation
createCar(Context context, ServiceConnection serviceConnection)49     protected static Car createCar(Context context, ServiceConnection serviceConnection) {
50         if (serviceConnection != null) {
51             doAnswer((Answer<Void>) invocation -> {
52                 serviceConnection.onServiceConnected(null, null);
53                 return null;
54             }).when(sMockCar).connect();
55             doAnswer((Answer<Void>) invocation -> {
56                 serviceConnection.onServiceDisconnected(null);
57                 return null;
58             }).when(sMockCar).disconnect();
59         }
60         doReturn(sIsConnected).when(sMockCar).isConnected();
61         if (sServiceName != null) {
62             try {
63                 doReturn(sCarManager).when(sMockCar).getCarManager(sServiceName);
64             } catch (CarNotConnectedException e) {
65                 // do nothing, have to do this because compiler doesn't understand mock can't throw
66                 // exception.
67             }
68         }
69         return sMockCar;
70     }
71 
72     /**
73      * Returns a mocked version of a {@link Car} object.
74      */
75     @Implementation
createCar(Context context)76     protected static Car createCar(Context context) {
77         doReturn(sIsConnected).when(sMockCar).isConnected();
78         if (sServiceName != null) {
79             try {
80                 doReturn(sCarManager).when(sMockCar).getCarManager(sServiceName);
81             } catch (CarNotConnectedException e) {
82                 // do nothing, have to do this because compiler doesn't understand mock can't throw
83                 // exception.
84             }
85         }
86         return sMockCar;
87     }
88 
89     /**
90      * Sets the manager returned by {@link Car#getCarManager(String)}.
91      *
92      * @param serviceName the name for the service request that should return this car manager.
93      * @param carManager  the object returned by a call with this service.
94      */
setCarManager(String serviceName, Object carManager)95     public static void setCarManager(String serviceName, Object carManager) {
96         sServiceName = serviceName;
97         sCarManager = carManager;
98         try {
99             doReturn(carManager).when(sMockCar).getCarManager(serviceName);
100         } catch (CarNotConnectedException e) {
101             // do nothing, have to do this because compiler doesn't understand mock can't throw e.
102         }
103     }
104 
105     /**
106      * Resets the shadow state, note this will not remove stubbed behavior on references to older
107      * calls to {@link #createCar(Context, ServiceConnection)}.
108      */
109     @Resetter
reset()110     public static void reset() {
111         sMockCar = mock(Car.class);
112         sServiceName = null;
113         sCarManager = null;
114         sIsConnected = false;
115     }
116 }
117