• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base.test;
6 
7 import androidx.test.core.app.ApplicationProvider;
8 
9 import org.junit.rules.TestRule;
10 import org.junit.runner.Description;
11 import org.junit.runners.model.Statement;
12 
13 import org.chromium.base.ApplicationStatus;
14 import org.chromium.base.BundleUtils;
15 import org.chromium.base.ContextUtils;
16 import org.chromium.base.Flag;
17 import org.chromium.base.LifetimeAssert;
18 import org.chromium.base.PathUtils;
19 import org.chromium.base.ResettersForTesting;
20 import org.chromium.base.ThreadUtils;
21 import org.chromium.base.library_loader.LibraryLoader;
22 import org.chromium.base.library_loader.LibraryProcessType;
23 import org.chromium.base.metrics.UmaRecorderHolder;
24 import org.chromium.base.task.PostTask;
25 import org.chromium.base.test.BaseRobolectricTestRunner.HelperTestRunner;
26 import org.chromium.base.test.util.CommandLineFlags;
27 import org.chromium.build.NativeLibraries;
28 
29 import java.lang.reflect.Method;
30 import java.util.Locale;
31 import java.util.TimeZone;
32 
33 /**
34  * The default Rule used by BaseRobolectricTestRunner. Include this directly when using
35  * ParameterizedRobolectricTestRunner.
36  * Use @Rule(order=-2) to ensure it runs before other rules.
37  */
38 public class BaseRobolectricTestRule implements TestRule {
39     private static final Locale ORIG_LOCALE = Locale.getDefault();
40     private static final TimeZone ORIG_TIMEZONE = TimeZone.getDefault();
41 
42     // Removes the API Level suffix. E.g. "testSomething[28]" -> "testSomething".
stripBrackets(String methodName)43     private static String stripBrackets(String methodName) {
44         int idx = methodName.indexOf('[');
45         if (idx != -1) {
46             methodName = methodName.substring(0, idx);
47         }
48         return methodName;
49     }
50 
51     @Override
apply(Statement base, Description description)52     public Statement apply(Statement base, Description description) {
53         return new Statement() {
54             @Override
55             public void evaluate() throws Throwable {
56                 setUp(
57                         description
58                                 .getTestClass()
59                                 .getMethod(stripBrackets(description.getMethodName())));
60                 boolean testFailed = true;
61                 try {
62                     base.evaluate();
63                     testFailed = false;
64                 } finally {
65                     tearDown(testFailed);
66                     // We cannot guarantee that this Rule will be evaluated first, so never
67                     // call setMethodMode(), and reset class resetters after each method.
68                     ResettersForTesting.onAfterClass();
69                 }
70             }
71         };
72     }
73 
74     static void setUp(Method method) {
75         UmaRecorderHolder.setUpNativeUmaRecorder(false);
76         ContextUtils.initApplicationContextForTests(ApplicationProvider.getApplicationContext());
77         LibraryLoader.getInstance().setLibraryProcessType(LibraryProcessType.PROCESS_BROWSER);
78         // Whether or not native is loaded is a global one-way switch, so do it automatically so
79         // that it is always in the same state.
80         if (NativeLibraries.LIBRARIES.length > 0) {
81             LibraryLoader.getInstance().ensureMainDexInitialized();
82         }
83         ApplicationStatus.initialize(ApplicationProvider.getApplicationContext());
84         UmaRecorderHolder.resetForTesting();
85         CommandLineFlags.setUpClass(method.getDeclaringClass());
86         CommandLineFlags.setUpMethod(method);
87         BundleUtils.resetForTesting();
88         Flag.resetAllInMemoryCachedValuesForTesting();
89     }
90 
91     static void tearDown(boolean testFailed) {
92         try {
93             // https://crbug.com/1392817 for context as to why we do this.
94             PostTask.flushJobsAndResetForTesting();
95         } catch (InterruptedException e) {
96             HelperTestRunner.sTestFailed = true;
97             throw new RuntimeException(e);
98         } finally {
99             CommandLineFlags.tearDownMethod();
100             CommandLineFlags.tearDownClass();
101             ResettersForTesting.onAfterMethod();
102             ApplicationStatus.destroyForJUnitTests();
103             ContextUtils.clearApplicationContextForTests();
104             PathUtils.resetForTesting();
105             ThreadUtils.clearUiThreadForTesting();
106             Locale.setDefault(ORIG_LOCALE);
107             TimeZone.setDefault(ORIG_TIMEZONE);
108             // Run assertions only when the test has not already failed so as to not mask
109             // failures. https://crbug.com/1466313
110             if (testFailed) {
111                 LifetimeAssert.resetForTesting();
112             } else {
113                 LifetimeAssert.assertAllInstancesDestroyedForTesting();
114             }
115         }
116     }
117 }
118