Loading packages/SystemUI/tests/utils/src/com/android/systemui/util/NoUiThreadTestRule.kt 0 → 100644 +41 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.systemui.util import android.testing.UiThreadTest import org.junit.Assert.fail import org.junit.rules.MethodRule import org.junit.runners.model.FrameworkMethod import org.junit.runners.model.Statement /** * A Test rule which prevents us from using the UiThreadTest annotation. See * go/android_junit4_uithreadtest (b/352170965) */ public class NoUiThreadTestRule : MethodRule { override fun apply(base: Statement, method: FrameworkMethod, target: Any): Statement? { if (hasUiThreadAnnotation(method, target)) { fail("UiThreadTest doesn't actually run on the UiThread") } return base } private fun hasUiThreadAnnotation(method: FrameworkMethod, target: Any): Boolean { if (method.getAnnotation(UiThreadTest::class.java) != null) { return true } else { return target.javaClass.getAnnotation(UiThreadTest::class.java) != null } } } packages/SystemUI/tests/utils/src/com/android/systemui/util/NoUiThreadTestRuleTest.kt 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.systemui.util import android.testing.UiThreadTest import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import java.lang.AssertionError import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.model.FrameworkMethod import org.junit.runners.model.Statement /** * Test that NoUiThreadTestRule asserts when it finds a framework method with a UiThreadTest * annotation. */ @RunWith(AndroidJUnit4::class) @SmallTest public class NoUiThreadTestRuleTest : SysuiTestCase() { class TestStatement : Statement() { override fun evaluate() {} } inner class TestInner { @Test @UiThreadTest fun simpleUiTest() {} @Test fun simpleTest() {} } /** * Test that NoUiThreadTestRule throws an asserts false if a test is annotated * with @UiThreadTest */ @Test(expected = AssertionError::class) fun testNoUiThreadFail() { val method = TestInner::class.java.getDeclaredMethod("simpleUiTest") val frameworkMethod = FrameworkMethod(method) val noUiThreadTestRule = NoUiThreadTestRule() val testStatement = TestStatement() // target needs to be non-null val obj = Object() noUiThreadTestRule.apply(testStatement, frameworkMethod, obj) } /** * Test that NoUiThreadTestRule throws an asserts false if a test is annotated * with @UiThreadTest */ fun testNoUiThreadOK() { val method = TestInner::class.java.getDeclaredMethod("simpleUiTest") val frameworkMethod = FrameworkMethod(method) val noUiThreadTestRule = NoUiThreadTestRule() val testStatement = TestStatement() // because target needs to be non-null val obj = Object() val newStatement = noUiThreadTestRule.apply(testStatement, frameworkMethod, obj) Assert.assertEquals(newStatement, testStatement) } } packages/SystemUI/tests/utils/src/com/android/systemui/util/UiThread.java 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.util; import android.os.Looper; import android.util.Log; import androidx.test.platform.app.InstrumentationRegistry; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * A class to launch runnables on the UI thread explicitly. */ public class UiThread { private static final String TAG = "UiThread"; /** * Run a runnable on the UI thread using instrumentation.runOnMainSync. * * @param runnable code to run on the UI thread. * @throws Throwable if the code threw an exception, so it can be reported * to the test. */ public static void runOnUiThread(final Runnable runnable) throws Throwable { if (Looper.myLooper() == Looper.getMainLooper()) { Log.w( TAG, "UiThread.runOnUiThread() should not be called from the " + "main application thread"); runnable.run(); } else { FutureTask<Void> task = new FutureTask<>(runnable, null); InstrumentationRegistry.getInstrumentation().runOnMainSync(task); try { task.get(); } catch (ExecutionException e) { // Expose the original exception throw e.getCause(); } } } } packages/SystemUI/tests/utils/src/com/android/systemui/util/UiThreadRunTest.java 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.util; import android.os.Looper; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; /** * Test that UiThread.runOnUiThread() actually runs on the UI Thread. */ @RunWith(AndroidJUnit4.class) @SmallTest public class UiThreadRunTest extends SysuiTestCase { @Test public void testUiThread() throws Throwable { UiThread.runOnUiThread(() -> { Assert.assertEquals(Looper.getMainLooper().getThread(), Thread.currentThread()); }); } } Loading
packages/SystemUI/tests/utils/src/com/android/systemui/util/NoUiThreadTestRule.kt 0 → 100644 +41 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.systemui.util import android.testing.UiThreadTest import org.junit.Assert.fail import org.junit.rules.MethodRule import org.junit.runners.model.FrameworkMethod import org.junit.runners.model.Statement /** * A Test rule which prevents us from using the UiThreadTest annotation. See * go/android_junit4_uithreadtest (b/352170965) */ public class NoUiThreadTestRule : MethodRule { override fun apply(base: Statement, method: FrameworkMethod, target: Any): Statement? { if (hasUiThreadAnnotation(method, target)) { fail("UiThreadTest doesn't actually run on the UiThread") } return base } private fun hasUiThreadAnnotation(method: FrameworkMethod, target: Any): Boolean { if (method.getAnnotation(UiThreadTest::class.java) != null) { return true } else { return target.javaClass.getAnnotation(UiThreadTest::class.java) != null } } }
packages/SystemUI/tests/utils/src/com/android/systemui/util/NoUiThreadTestRuleTest.kt 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 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.systemui.util import android.testing.UiThreadTest import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import java.lang.AssertionError import org.junit.Assert import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.model.FrameworkMethod import org.junit.runners.model.Statement /** * Test that NoUiThreadTestRule asserts when it finds a framework method with a UiThreadTest * annotation. */ @RunWith(AndroidJUnit4::class) @SmallTest public class NoUiThreadTestRuleTest : SysuiTestCase() { class TestStatement : Statement() { override fun evaluate() {} } inner class TestInner { @Test @UiThreadTest fun simpleUiTest() {} @Test fun simpleTest() {} } /** * Test that NoUiThreadTestRule throws an asserts false if a test is annotated * with @UiThreadTest */ @Test(expected = AssertionError::class) fun testNoUiThreadFail() { val method = TestInner::class.java.getDeclaredMethod("simpleUiTest") val frameworkMethod = FrameworkMethod(method) val noUiThreadTestRule = NoUiThreadTestRule() val testStatement = TestStatement() // target needs to be non-null val obj = Object() noUiThreadTestRule.apply(testStatement, frameworkMethod, obj) } /** * Test that NoUiThreadTestRule throws an asserts false if a test is annotated * with @UiThreadTest */ fun testNoUiThreadOK() { val method = TestInner::class.java.getDeclaredMethod("simpleUiTest") val frameworkMethod = FrameworkMethod(method) val noUiThreadTestRule = NoUiThreadTestRule() val testStatement = TestStatement() // because target needs to be non-null val obj = Object() val newStatement = noUiThreadTestRule.apply(testStatement, frameworkMethod, obj) Assert.assertEquals(newStatement, testStatement) } }
packages/SystemUI/tests/utils/src/com/android/systemui/util/UiThread.java 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.util; import android.os.Looper; import android.util.Log; import androidx.test.platform.app.InstrumentationRegistry; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /** * A class to launch runnables on the UI thread explicitly. */ public class UiThread { private static final String TAG = "UiThread"; /** * Run a runnable on the UI thread using instrumentation.runOnMainSync. * * @param runnable code to run on the UI thread. * @throws Throwable if the code threw an exception, so it can be reported * to the test. */ public static void runOnUiThread(final Runnable runnable) throws Throwable { if (Looper.myLooper() == Looper.getMainLooper()) { Log.w( TAG, "UiThread.runOnUiThread() should not be called from the " + "main application thread"); runnable.run(); } else { FutureTask<Void> task = new FutureTask<>(runnable, null); InstrumentationRegistry.getInstrumentation().runOnMainSync(task); try { task.get(); } catch (ExecutionException e) { // Expose the original exception throw e.getCause(); } } } }
packages/SystemUI/tests/utils/src/com/android/systemui/util/UiThreadRunTest.java 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.systemui.util; import android.os.Looper; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; /** * Test that UiThread.runOnUiThread() actually runs on the UI Thread. */ @RunWith(AndroidJUnit4.class) @SmallTest public class UiThreadRunTest extends SysuiTestCase { @Test public void testUiThread() throws Throwable { UiThread.runOnUiThread(() -> { Assert.assertEquals(Looper.getMainLooper().getThread(), Thread.currentThread()); }); } }