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 com.android.testutils 18 19 import android.os.Build 20 import org.junit.Assume.assumeTrue 21 import org.junit.rules.TestRule 22 import org.junit.runner.Description 23 import org.junit.runners.model.Statement 24 25 /** 26 * Returns true if the development SDK version of the device is in the provided range. 27 * 28 * If the device is not using a release SDK, the development SDK is considered to be higher than 29 * [Build.VERSION.SDK_INT]. 30 */ 31 fun isDevSdkInRange(minExclusive: Int?, maxInclusive: Int?): Boolean { 32 // In-development API n+1 will have SDK_INT == n and CODENAME != REL. 33 // Stable API n has SDK_INT == n and CODENAME == REL. 34 val release = "REL" == Build.VERSION.CODENAME 35 val sdkInt = Build.VERSION.SDK_INT 36 val devApiLevel = sdkInt + if (release) 0 else 1 37 38 return (minExclusive == null || devApiLevel > minExclusive) && 39 (maxInclusive == null || devApiLevel <= maxInclusive) 40 } 41 42 /** 43 * A test rule to ignore tests based on the development SDK level. 44 * 45 * If the device is not using a release SDK, the development SDK is considered to be higher than 46 * [Build.VERSION.SDK_INT]. 47 * 48 * @param ignoreClassUpTo Skip all tests in the class if the device dev SDK is <= this value. 49 * @param ignoreClassAfter Skip all tests in the class if the device dev SDK is > this value. 50 */ 51 class DevSdkIgnoreRule @JvmOverloads constructor( 52 private val ignoreClassUpTo: Int? = null, 53 private val ignoreClassAfter: Int? = null 54 ) : TestRule { 55 override fun apply(base: Statement, description: Description): Statement { 56 return IgnoreBySdkStatement(base, description) 57 } 58 59 /** 60 * Ignore the test for any development SDK that is strictly after [value]. 61 * 62 * If the device is not using a release SDK, the development SDK is considered to be higher 63 * than [Build.VERSION.SDK_INT]. 64 */ 65 annotation class IgnoreAfter(val value: Int) 66 67 /** 68 * Ignore the test for any development SDK that lower than or equal to [value]. 69 * 70 * If the device is not using a release SDK, the development SDK is considered to be higher 71 * than [Build.VERSION.SDK_INT]. 72 */ 73 annotation class IgnoreUpTo(val value: Int) 74 75 private inner class IgnoreBySdkStatement( 76 private val base: Statement, 77 private val description: Description 78 ) : Statement() { 79 override fun evaluate() { 80 val ignoreAfter = description.getAnnotation(IgnoreAfter::class.java) 81 val ignoreUpTo = description.getAnnotation(IgnoreUpTo::class.java) 82 83 val message = "Skipping test for build ${Build.VERSION.CODENAME} " + 84 "with SDK ${Build.VERSION.SDK_INT}" 85 assumeTrue(message, isDevSdkInRange(ignoreClassUpTo, ignoreClassAfter)) 86 assumeTrue(message, isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) 87 base.evaluate() 88 } 89 } 90 }