Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d2d5731 authored by Chalard Jean's avatar Chalard Jean Committed by Automerger Merge Worker
Browse files

Merge "Add a test runner to ignore tests on old SDKs" am: e8bc7ae4 am:...

Merge "Add a test runner to ignore tests on old SDKs" am: e8bc7ae4 am: 71b27182 am: 1345eecb am: 2cee744e am: a7e8b83c

Change-Id: Ib1a4b3cf5229e12ee5f0c63b665cc2f92566db6c
parents c251dd57 a7e8b83c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ java_library {
        "androidx.annotation_annotation",
    ],
    static_libs: [
        "androidx.test.ext.junit",
        "net-tests-utils-multivariant",
    ],
}
+21 −10
Original line number Diff line number Diff line
@@ -22,6 +22,23 @@ import org.junit.rules.TestRule
import org.junit.runner.Description
import org.junit.runners.model.Statement

/**
 * Returns true if the development SDK version of the device is in the provided range.
 *
 * If the device is not using a release SDK, the development SDK is considered to be higher than
 * [Build.VERSION.SDK_INT].
 */
fun isDevSdkInRange(minExclusive: Int?, maxInclusive: Int?): Boolean {
    // In-development API n+1 will have SDK_INT == n and CODENAME != REL.
    // Stable API n has SDK_INT == n and CODENAME == REL.
    val release = "REL" == Build.VERSION.CODENAME
    val sdkInt = Build.VERSION.SDK_INT
    val devApiLevel = sdkInt + if (release) 0 else 1

    return (minExclusive == null || devApiLevel > minExclusive) &&
            (maxInclusive == null || devApiLevel <= maxInclusive)
}

/**
 * A test rule to ignore tests based on the development SDK level.
 *
@@ -63,16 +80,10 @@ class DevSdkIgnoreRule @JvmOverloads constructor(
            val ignoreAfter = description.getAnnotation(IgnoreAfter::class.java)
            val ignoreUpTo = description.getAnnotation(IgnoreUpTo::class.java)

            // In-development API n+1 will have SDK_INT == n and CODENAME != REL.
            // Stable API n has SDK_INT == n and CODENAME == REL.
            val release = "REL" == Build.VERSION.CODENAME
            val sdkInt = Build.VERSION.SDK_INT
            val devApiLevel = sdkInt + if (release) 0 else 1
            val message = "Skipping test for ${if (!release) "non-" else ""}release SDK $sdkInt"
            assumeTrue(message, ignoreClassAfter == null || devApiLevel <= ignoreClassAfter)
            assumeTrue(message, ignoreClassUpTo == null || devApiLevel > ignoreClassUpTo)
            assumeTrue(message, ignoreAfter == null || devApiLevel <= ignoreAfter.value)
            assumeTrue(message, ignoreUpTo == null || devApiLevel > ignoreUpTo.value)
            val message = "Skipping test for build ${Build.VERSION.CODENAME} " +
                    "with SDK ${Build.VERSION.SDK_INT}"
            assumeTrue(message, isDevSdkInRange(ignoreClassUpTo, ignoreClassAfter))
            assumeTrue(message, isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value))
            base.evaluate()
        }
    }
+72 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.testutils

import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import org.junit.runner.Description
import org.junit.runner.Runner
import org.junit.runner.notification.RunNotifier

/**
 * A runner that can skip tests based on the development SDK as defined in [DevSdkIgnoreRule].
 *
 * Generally [DevSdkIgnoreRule] should be used for that purpose (using rules is preferable over
 * replacing the test runner), however JUnit runners inspect all methods in the test class before
 * processing test rules. This may cause issues if the test methods are referencing classes that do
 * not exist on the SDK of the device the test is run on.
 *
 * This runner inspects [IgnoreAfter] and [IgnoreUpTo] annotations on the test class, and will skip
 * the whole class if they do not match the development SDK as defined in [DevSdkIgnoreRule].
 * Otherwise, it will delegate to [AndroidJUnit4] to run the test as usual.
 *
 * Example usage:
 *
 *     @RunWith(DevSdkIgnoreRunner::class)
 *     @IgnoreUpTo(Build.VERSION_CODES.Q)
 *     class MyTestClass { ... }
 */
class DevSdkIgnoreRunner(private val klass: Class<*>) : Runner() {
    private val baseRunner = klass.let {
        val ignoreAfter = it.getAnnotation(IgnoreAfter::class.java)
        val ignoreUpTo = it.getAnnotation(IgnoreUpTo::class.java)

        if (isDevSdkInRange(ignoreUpTo?.value, ignoreAfter?.value)) AndroidJUnit4(klass) else null
    }

    override fun run(notifier: RunNotifier) {
        if (baseRunner != null) {
            baseRunner.run(notifier)
            return
        }

        // Report a single, skipped placeholder test for this class, so that the class is still
        // visible as skipped in test results.
        notifier.fireTestIgnored(
                Description.createTestDescription(klass, "skippedClassForDevSdkMismatch"))
    }

    override fun getDescription(): Description {
        return baseRunner?.description ?: Description.createSuiteDescription(klass)
    }

    override fun testCount(): Int {
        // When ignoring the tests, a skipped placeholder test is reported, so test count is 1.
        return baseRunner?.testCount() ?: 1
    }
}
 No newline at end of file