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.setupwizardlib.shadows; 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.invocation.InvocationOnMock; 29 import org.mockito.stubbing.Answer; 30 import org.robolectric.annotation.Implementation; 31 import org.robolectric.annotation.Implements; 32 import org.robolectric.annotation.Resetter; 33 34 /** 35 * Shadow class for {@link Car}. Allows tests to control the return values and behavior of the 36 * object. 37 */ 38 @Implements(Car.class) 39 public class ShadowCar { 40 41 private static Car sMockCar = mock(Car.class); 42 private static boolean sIsConnected; 43 private static String sServiceName; 44 private static Object sCarManager; 45 private static boolean sHasConnected; 46 private static boolean sHasDisconnected; 47 48 /** 49 * Returns a mocked version of a {@link Car} object. Will reset 50 */ 51 @Implementation createCar(Context context, ServiceConnection serviceConnection)52 public static Car createCar(Context context, ServiceConnection serviceConnection) { 53 if (serviceConnection != null) { 54 doAnswer(new Answer<Void>() { 55 @Override 56 public Void answer(InvocationOnMock invocation) { 57 serviceConnection.onServiceConnected(null, null); 58 sHasConnected = true; 59 return null; 60 } 61 }).when(sMockCar).connect(); 62 doAnswer(new Answer<Void>() { 63 @Override 64 public Void answer(InvocationOnMock invocation) { 65 sHasDisconnected = true; 66 serviceConnection.onServiceDisconnected(null); 67 return null; 68 } 69 }).when(sMockCar).disconnect(); 70 } 71 doReturn(sIsConnected).when(sMockCar).isConnected(); 72 if (sServiceName != null) { 73 try { 74 doReturn(sCarManager).when(sMockCar).getCarManager(sServiceName); 75 } catch (CarNotConnectedException e) { 76 // do nothing, have to do this because compiler doesn't understand mock can't throw 77 // exception. 78 } 79 } 80 return sMockCar; 81 } 82 83 /** 84 * Sets the isConnected state for the car returned by the {@link #createCar(Context, 85 * ServiceConnection)} method. 86 */ setIsConnected(boolean connected)87 public static void setIsConnected(boolean connected) { 88 sIsConnected = connected; 89 doReturn(connected).when(sMockCar).isConnected(); 90 } 91 92 /** 93 * Sets the manager returned by {@link Car#getCarManager(String)}. 94 * 95 * @param serviceName the name for the service request that should return this car manager. 96 * @param carManager the object returned by a call with this service. 97 */ setCarManager(String serviceName, Object carManager)98 public static void setCarManager(String serviceName, Object carManager) { 99 sServiceName = serviceName; 100 sCarManager = carManager; 101 try { 102 doReturn(carManager).when(sMockCar).getCarManager(serviceName); 103 } catch (CarNotConnectedException e) { 104 // do nothing, have to do this because compiler doesn't understand mock can't throw e. 105 } 106 } 107 108 /** 109 * Returns whether the mock has received a call to connect. 110 */ hasConnected()111 public static boolean hasConnected() { 112 return sHasConnected; 113 } 114 115 /** 116 * Returns whether the mock has received a call to disconnect. 117 */ hasDisconnected()118 public static boolean hasDisconnected() { 119 return sHasDisconnected; 120 } 121 122 /** 123 * Triggers a disconnect on the mock object being held. 124 */ triggerDisconnect()125 public static void triggerDisconnect() { 126 sMockCar.disconnect(); 127 } 128 129 /** 130 * Resets the shadow state, note this will not remove stubbed behavior on references to older 131 * calls to {@link #createCar(Context, ServiceConnection)}. 132 */ 133 @Resetter reset()134 public static void reset() { 135 sMockCar = mock(Car.class); 136 sServiceName = null; 137 sCarManager = null; 138 sIsConnected = false; 139 sHasConnected = false; 140 sHasDisconnected = false; 141 } 142 } 143