blob: e64ed8aa1ed7cf682f0342a2ff146ab91d3557d3 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.base.test;
import androidx.test.core.app.ApplicationProvider;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.BundleUtils;
import org.chromium.base.ContextUtils;
import org.chromium.base.Flag;
import org.chromium.base.LifetimeAssert;
import org.chromium.base.PathUtils;
import org.chromium.base.ResettersForTesting;
import org.chromium.base.ThreadUtils;
import org.chromium.base.library_loader.LibraryLoader;
import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.base.metrics.UmaRecorderHolder;
import org.chromium.base.task.PostTask;
import org.chromium.base.test.BaseRobolectricTestRunner.HelperTestRunner;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.build.NativeLibraries;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.TimeZone;
/**
* The default Rule used by BaseRobolectricTestRunner. Include this directly when using
* ParameterizedRobolectricTestRunner.
* Use @Rule(order=-2) to ensure it runs before other rules.
*/
public class BaseRobolectricTestRule implements TestRule {
private static final Locale ORIG_LOCALE = Locale.getDefault();
private static final TimeZone ORIG_TIMEZONE = TimeZone.getDefault();
// Removes the API Level suffix. E.g. "testSomething[28]" -> "testSomething".
private static String stripBrackets(String methodName) {
int idx = methodName.indexOf('[');
if (idx != -1) {
methodName = methodName.substring(0, idx);
}
return methodName;
}
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
setUp(
description
.getTestClass()
.getMethod(stripBrackets(description.getMethodName())));
boolean testFailed = true;
try {
base.evaluate();
testFailed = false;
} finally {
tearDown(testFailed);
// We cannot guarantee that this Rule will be evaluated first, so never
// call setMethodMode(), and reset class resetters after each method.
ResettersForTesting.onAfterClass();
}
}
};
}
static void setUp(Method method) {
UmaRecorderHolder.setUpNativeUmaRecorder(false);
ContextUtils.initApplicationContextForTests(ApplicationProvider.getApplicationContext());
LibraryLoader.getInstance().setLibraryProcessType(LibraryProcessType.PROCESS_BROWSER);
// Whether or not native is loaded is a global one-way switch, so do it automatically so
// that it is always in the same state.
if (NativeLibraries.LIBRARIES.length > 0) {
LibraryLoader.getInstance().ensureMainDexInitialized();
}
ApplicationStatus.initialize(ApplicationProvider.getApplicationContext());
UmaRecorderHolder.resetForTesting();
CommandLineFlags.setUpClass(method.getDeclaringClass());
CommandLineFlags.setUpMethod(method);
BundleUtils.resetForTesting();
Flag.resetAllInMemoryCachedValuesForTesting();
}
static void tearDown(boolean testFailed) {
try {
// https://crbug.com/1392817 for context as to why we do this.
PostTask.flushJobsAndResetForTesting();
} catch (InterruptedException e) {
HelperTestRunner.sTestFailed = true;
throw new RuntimeException(e);
} finally {
CommandLineFlags.tearDownMethod();
CommandLineFlags.tearDownClass();
ResettersForTesting.onAfterMethod();
ApplicationStatus.destroyForJUnitTests();
ContextUtils.clearApplicationContextForTests();
PathUtils.resetForTesting();
ThreadUtils.clearUiThreadForTesting();
Locale.setDefault(ORIG_LOCALE);
TimeZone.setDefault(ORIG_TIMEZONE);
// Run assertions only when the test has not already failed so as to not mask
// failures. https://crbug.com/1466313
if (testFailed) {
LifetimeAssert.resetForTesting();
} else {
LifetimeAssert.assertAllInstancesDestroyedForTesting();
}
}
}
}