1 /* 2 * Copyright (C) 2020 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 package android.car.test.mocks; 17 18 import static org.mockito.ArgumentMatchers.argThat; 19 20 import android.annotation.Nullable; 21 import android.annotation.UserIdInt; 22 import android.content.Intent; 23 import android.content.pm.UserInfo; 24 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 25 import android.os.UserHandle; 26 import android.util.Log; 27 28 import org.mockito.ArgumentMatcher; 29 30 import java.util.Arrays; 31 import java.util.Objects; 32 33 /** 34 * Provides custom mockito matcher for Android / Car objects. 35 * 36 */ 37 public final class CarArgumentMatchers { 38 39 private static final String TAG = CarArgumentMatchers.class.getSimpleName(); 40 41 /** 42 * Matches if a {@link UserInfo} has the given {@code userId}. 43 */ isUserInfo(@serIdInt int userId)44 public static UserInfo isUserInfo(@UserIdInt int userId) { 45 return argThat(new UserInfoMatcher(userId)); 46 } 47 48 /** 49 * Matches if a {@link UserHandle} has the given {@code userId}. 50 */ isUserHandle(@serIdInt int userId)51 public static UserHandle isUserHandle(@UserIdInt int userId) { 52 return argThat(new UserHandleMatcher(userId)); 53 } 54 55 /** 56 * Matches an {@link Intent} for the given action and package name. 57 */ intentFor(String action, String packageName)58 public static Intent intentFor(String action, String packageName) { 59 return argThat(new IntentMatcher(action, packageName)); 60 } 61 62 /** 63 * Matches if a {@link VehiclePropValue} has the given {@code prop}. 64 */ isProperty(int prop)65 public static VehiclePropValue isProperty(int prop) { 66 return argThat(new PropertyIdMatcher(prop)); 67 } 68 69 /** 70 * Matches if a {@link VehiclePropValue} has the given {@code prop} and {@code int32} values. 71 */ isPropertyWithValues(int prop, int...values)72 public static VehiclePropValue isPropertyWithValues(int prop, int...values) { 73 return argThat(new PropertyIdMatcher(prop, values)); 74 } 75 76 private static class UserInfoMatcher implements ArgumentMatcher<UserInfo> { 77 78 public final @UserIdInt int userId; 79 UserInfoMatcher(@serIdInt int userId)80 private UserInfoMatcher(@UserIdInt int userId) { 81 this.userId = userId; 82 } 83 84 @Override matches(@ullable UserInfo argument)85 public boolean matches(@Nullable UserInfo argument) { 86 if (argument == null) { 87 Log.w(TAG, "isUserInfo(): null argument"); 88 return false; 89 } 90 if (argument.id != userId) { 91 Log.w(TAG, "isUserInfo(): argument mismatch (expected " + userId 92 + ", got " + argument.id); 93 return false; 94 } 95 return true; 96 } 97 98 @Override toString()99 public String toString() { 100 return "isUserInfo(userId=" + userId + ")"; 101 } 102 } 103 104 private static class UserHandleMatcher implements ArgumentMatcher<UserHandle> { 105 106 public final @UserIdInt int userId; 107 UserHandleMatcher(@serIdInt int userId)108 private UserHandleMatcher(@UserIdInt int userId) { 109 this.userId = userId; 110 } 111 112 @Override matches(UserHandle argument)113 public boolean matches(UserHandle argument) { 114 if (argument == null) { 115 Log.w(TAG, "isUserHandle(): null argument"); 116 return false; 117 } 118 if (argument.getIdentifier() != userId) { 119 Log.w(TAG, "isUserHandle(): argument mismatch (expected " + userId 120 + ", got " + argument.getIdentifier()); 121 return false; 122 } 123 return true; 124 } 125 126 @Override toString()127 public String toString() { 128 return "isUserHandle(userId=" + userId + ")"; 129 } 130 } 131 132 private static class PropertyIdMatcher implements ArgumentMatcher<VehiclePropValue> { 133 134 final int mProp; 135 private final int[] mValues; 136 PropertyIdMatcher(int prop)137 private PropertyIdMatcher(int prop) { 138 this(prop, null); 139 } 140 PropertyIdMatcher(int prop, int[] values)141 private PropertyIdMatcher(int prop, int[] values) { 142 mProp = prop; 143 mValues = values; 144 } 145 146 @Override matches(VehiclePropValue argument)147 public boolean matches(VehiclePropValue argument) { 148 Log.v(TAG, "PropertyIdMatcher: argument=" + argument); 149 if (argument.prop != mProp) { 150 Log.w(TAG, "PropertyIdMatcher: Invalid prop on " + argument); 151 return false; 152 } 153 if (mValues == null) return true; 154 // Make sure values match 155 if (mValues.length != argument.value.int32Values.size()) { 156 Log.w(TAG, "PropertyIdMatcher: number of values (expected " + mValues.length 157 + ") mismatch on " + argument); 158 return false; 159 } 160 161 for (int i = 0; i < mValues.length; i++) { 162 if (mValues[i] != argument.value.int32Values.get(i)) { 163 Log.w(TAG, "PropertyIdMatcher: value mismatch at index " + i + " on " + argument 164 + ": expected " + Arrays.toString(mValues)); 165 return false; 166 } 167 } 168 return true; 169 } 170 171 @Override toString()172 public String toString() { 173 return "prop: " + mProp + " values: " + Arrays.toString(mValues); 174 } 175 } 176 177 private static final class IntentMatcher implements ArgumentMatcher<Intent> { 178 179 private final String mAction; 180 private final String mPackageName; 181 IntentMatcher(String action, String packageName)182 private IntentMatcher(String action, String packageName) { 183 mAction = Objects.requireNonNull(action, "action cannot be null"); 184 mPackageName = Objects.requireNonNull(packageName, "packageName cannot be null"); 185 } 186 187 @Override matches(Intent argument)188 public boolean matches(Intent argument) { 189 Log.v(TAG, "IntentMatcher: argument=" + argument + ", this=" + this); 190 191 return argument != null && mAction.equals(argument.getAction()) 192 && mPackageName.equals(argument.getPackage()); 193 } 194 195 @Override toString()196 public String toString() { 197 return "intentFor(action=" + mAction + ", pkg=" + mPackageName + ')'; 198 } 199 } 200 CarArgumentMatchers()201 private CarArgumentMatchers() { 202 throw new UnsupportedOperationException("contains only static methods"); 203 } 204 } 205