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 17 package android.content.pm.parsing.result 18 19 import android.content.pm.PackageManager 20 import android.os.Build 21 import android.platform.test.annotations.Presubmit 22 import com.google.common.truth.Truth.assertThat 23 import org.junit.After 24 import org.junit.Assume.assumeFalse 25 import org.junit.Before 26 import org.junit.BeforeClass 27 import org.junit.Test 28 import org.mockito.ArgumentMatchers.anyLong 29 import org.mockito.Mockito.anyInt 30 import org.mockito.Mockito.anyString 31 import org.mockito.Mockito.never 32 import org.mockito.Mockito.spy 33 import org.mockito.Mockito.times 34 import org.mockito.Mockito.verify 35 import org.mockito.Mockito.verifyNoMoreInteractions 36 import java.io.IOException 37 38 @Presubmit 39 class ParseInputAndResultTest { 40 41 companion object { 42 43 private const val TEST_PACKAGE = "com.android.test" 44 45 private const val ENABLED_ERROR = 11L 46 private const val DISABLED_ERROR = 22L 47 48 @JvmStatic 49 @BeforeClass assumeNotDebugnull50 fun assumeNotDebug() { 51 // None of these tests consider cases where debugging logic is enabled 52 assumeFalse(ParseTypeImpl.DEBUG_FILL_STACK_TRACE) 53 assumeFalse(ParseTypeImpl.DEBUG_LOG_ON_ERROR) 54 assumeFalse(ParseTypeImpl.DEBUG_THROW_ALL_ERRORS) 55 } 56 } 57 58 private lateinit var mockCallback: ParseInput.Callback 59 private lateinit var input: ParseInput 60 61 @Before createInputnull62 fun createInput() { 63 // Use an open class instead off a lambda so it can be spied 64 open class TestCallback : ParseInput.Callback { 65 override fun isChangeEnabled(changeId: Long, pkgName: String, targetSdk: Int): Boolean { 66 return when (changeId) { 67 ENABLED_ERROR -> targetSdk > Build.VERSION_CODES.Q 68 DISABLED_ERROR -> false 69 else -> throw IllegalStateException("changeId $changeId is not mocked for test") 70 } 71 } 72 } 73 74 mockCallback = spy(TestCallback()) 75 input = ParseTypeImpl(mockCallback) 76 } 77 78 @Test errorCodenull79 fun errorCode() { 80 val errorCode = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE 81 val result = input.error<Any?>(errorCode) 82 assertError(result) 83 assertThat(result.errorCode).isEqualTo(errorCode) 84 assertThat(result.errorMessage).isNull() 85 assertThat(result.exception).isNull() 86 } 87 88 @Test errorMessagenull89 fun errorMessage() { 90 val errorMessage = "Test error" 91 val result = input.error<Any?>(errorMessage) 92 assertError(result) 93 assertThat(result.errorCode).isNotEqualTo(PackageManager.INSTALL_SUCCEEDED) 94 assertThat(result.errorMessage).isEqualTo(errorMessage) 95 assertThat(result.exception).isNull() 96 } 97 98 @Test errorCodeAndMessagenull99 fun errorCodeAndMessage() { 100 val errorCode = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE 101 val errorMessage = "Test error" 102 val result = input.error<Any?>(errorCode, errorMessage) 103 assertError(result) 104 assertThat(result.errorCode).isEqualTo(errorCode) 105 assertThat(result.errorMessage).isEqualTo(errorMessage) 106 assertThat(result.exception).isNull() 107 } 108 109 @Test errorCodeAndMessageAndExceptionnull110 fun errorCodeAndMessageAndException() { 111 val errorCode = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE 112 val errorMessage = "Test error" 113 val exception = IOException() 114 val result = input.error<Any?>(errorCode, errorMessage, exception) 115 assertError(result) 116 assertThat(result.errorCode).isEqualTo(errorCode) 117 assertThat(result.errorMessage).isEqualTo(errorMessage) 118 assertThat(result.exception).isSameInstanceAs(exception) 119 } 120 121 @Test errorCarryResultnull122 fun errorCarryResult() { 123 val errorCode = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE 124 val errorMessage = "Test error" 125 val exception = IOException() 126 val result = input.error<Any?>(errorCode, errorMessage, exception) 127 assertError(result) 128 assertThat(result.errorCode).isEqualTo(errorCode) 129 assertThat(result.errorMessage).isEqualTo(errorMessage) 130 assertThat(result.exception).isSameInstanceAs(exception) 131 132 val carriedResult = input.error<Int>(result) 133 assertError(carriedResult) 134 assertThat(carriedResult.errorCode).isEqualTo(errorCode) 135 assertThat(carriedResult.errorMessage).isEqualTo(errorMessage) 136 assertThat(carriedResult.exception).isSameInstanceAs(exception) 137 } 138 139 @Test successnull140 fun success() { 141 val value = "Test success" 142 assertSuccess(value, input.success(value)) 143 } 144 145 @Test deferErrorEnableFirstSdkQnull146 fun deferErrorEnableFirstSdkQ() { 147 assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.Q)) 148 149 assertSuccess(input.deferError("Test error", ENABLED_ERROR)) 150 } 151 152 @Test deferErrorEnableLastSdkQnull153 fun deferErrorEnableLastSdkQ() { 154 assertSuccess(input.deferError("Test error", ENABLED_ERROR)) 155 156 assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.Q)) 157 } 158 159 @Test deferErrorEnableFirstSdkRnull160 fun deferErrorEnableFirstSdkR() { 161 val error = "Test error" 162 assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R)) 163 164 val deferResult = input.deferError(error, ENABLED_ERROR) 165 assertError(deferResult) 166 assertThat(deferResult.errorCode).isNotEqualTo(PackageManager.INSTALL_SUCCEEDED) 167 assertThat(deferResult.errorMessage).isEqualTo(error) 168 assertThat(deferResult.exception).isNull() 169 } 170 171 @Test deferErrorEnableLastSdkRnull172 fun deferErrorEnableLastSdkR() { 173 val error = "Test error" 174 assertSuccess(input.deferError(error, ENABLED_ERROR)) 175 176 val result = input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R) 177 assertError(result) 178 assertThat(result.errorCode).isNotEqualTo(PackageManager.INSTALL_SUCCEEDED) 179 assertThat(result.errorMessage).isEqualTo(error) 180 assertThat(result.exception).isNull() 181 } 182 183 @Test enableDeferredErrorAndSuccessSdkQnull184 fun enableDeferredErrorAndSuccessSdkQ() { 185 val value = "Test success" 186 assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.Q)) 187 188 assertSuccess(value, input.success(value)) 189 } 190 191 @Test enableDeferredErrorAndSuccessSdkRnull192 fun enableDeferredErrorAndSuccessSdkR() { 193 val value = "Test success" 194 assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R)) 195 196 assertSuccess(value, input.success(value)) 197 } 198 199 @Test multipleDeferErrorKeepsFirstnull200 fun multipleDeferErrorKeepsFirst() { 201 val errorOne = "Test error one" 202 val errorTwo = "Test error two" 203 204 assertSuccess(input.deferError(errorOne, ENABLED_ERROR)) 205 assertSuccess(input.deferError(errorTwo, ENABLED_ERROR)) 206 207 val result = input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R) 208 assertError(result) 209 assertThat(result.errorCode).isNotEqualTo(PackageManager.INSTALL_SUCCEEDED) 210 assertThat(result.errorMessage).isEqualTo(errorOne) 211 assertThat(result.exception).isNull() 212 } 213 214 @Test multipleDisabledErrorsQueriesOnceEnableFirstnull215 fun multipleDisabledErrorsQueriesOnceEnableFirst() { 216 val errorOne = "Test error one" 217 val errorTwo = "Test error two" 218 219 assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R)) 220 221 assertSuccess(input.deferError(errorOne, DISABLED_ERROR)) 222 223 verify(mockCallback, times(1)).isChangeEnabled(anyLong(), anyString(), anyInt()) 224 225 assertSuccess(input.deferError(errorTwo, DISABLED_ERROR)) 226 227 verifyNoMoreInteractions(mockCallback) 228 } 229 230 @Test multipleDisabledErrorsQueriesOnceEnableSecondnull231 fun multipleDisabledErrorsQueriesOnceEnableSecond() { 232 val errorOne = "Test error one" 233 val errorTwo = "Test error two" 234 235 assertSuccess(input.deferError(errorOne, DISABLED_ERROR)) 236 237 verify(mockCallback, never()).isChangeEnabled(anyLong(), anyString(), anyInt()) 238 239 assertSuccess(input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R)) 240 241 verify(mockCallback, times(1)).isChangeEnabled(anyLong(), anyString(), anyInt()) 242 243 assertSuccess(input.deferError(errorTwo, DISABLED_ERROR)) 244 245 verifyNoMoreInteractions(mockCallback) 246 } 247 248 @After verifyResetnull249 fun verifyReset() { 250 var result = (input as ParseTypeImpl).reset() as ParseResult<*> 251 result.assertReset() 252 253 // The deferred error is not directly accessible, so attempt to re-enable the deferred 254 // error and assert it was also reset. 255 result = input.enableDeferredError(TEST_PACKAGE, Build.VERSION_CODES.R) 256 result.assertReset() 257 } 258 assertSuccessnull259 private fun assertSuccess(result: ParseResult<*>) = assertSuccess(null, result) 260 261 private fun assertSuccess(expected: Any? = null, result: ParseResult<*>) { 262 assertThat(result.isError).isFalse() 263 assertThat(result.isSuccess).isTrue() 264 assertThat(result.result).isSameInstanceAs(expected) 265 assertThat(result.errorCode).isEqualTo(PackageManager.INSTALL_SUCCEEDED) 266 assertThat(result.errorMessage).isNull() 267 assertThat(result.exception).isNull() 268 } 269 assertErrornull270 private fun assertError(result: ParseResult<*>) { 271 assertThat(result.isError).isTrue() 272 assertThat(result.isSuccess).isFalse() 273 assertThat(result.result).isNull() 274 } 275 ParseResultnull276 private fun ParseResult<*>.assertReset() { 277 assertThat(this.isSuccess).isTrue() 278 assertThat(this.isError).isFalse() 279 assertThat(this.errorCode).isEqualTo(PackageManager.INSTALL_SUCCEEDED) 280 assertThat(this.errorMessage).isNull() 281 assertThat(this.exception).isNull() 282 } 283 } 284