/* * Copyright (C) 2014 SCVNGR, Inc. d/b/a LevelUp * * 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. * * The implementation of scrubClass(AndroidTestCase) is based on AOSP source code, which is also * Apache licensed; Copyright (C) 2006 The Android Open Source Project. */ package com.scvngr.levelup.core.test; import android.content.Context; import android.os.SystemClock; import android.support.annotation.NonNull; import android.test.AndroidTestCase; import com.scvngr.levelup.core.util.LogManager; import junit.framework.TestCase; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.concurrent.TimeUnit; /** * Utilities for the support test case classes. * * @see SupportAndroidTestCase * @see SupportApplicationTestCase */ /* package */final class SupportTestCaseUtils { private static final long WAIT_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(4L); private static final long WAIT_SLEEP_MILLIS = 20L; /** * Preserves static fields and avoids scrubby Android bugs. This implementation originates from * AOSP source code. * * @param testCase the test case to scrub * @throws IllegalAccessException from {@link Field#get} * @see <a href="http://goo.gl/YVFAM0">Update scrubClass() to match CoreTestRunner.</a> */ @SuppressWarnings("unused") public static void scrubClass(@NonNull final TestCase testCase) throws IllegalAccessException { final Field[] fields = testCase.getClass().getDeclaredFields(); for (final Field field : fields) { if (!field.getType().isPrimitive() && !Modifier.isStatic(field.getModifiers())) { try { field.setAccessible(true); field.set(testCase, null); } catch (final Exception e) { LogManager.d("Could not nullify field!"); } if (null != field.get(testCase)) { LogManager.d("Could not nullify field!"); } } } } /** * Workaround for a race condition affecting {@link android.test.AndroidTestCase} classes which * causes {@link android.content.Context#getApplicationContext} to return null for a short * period of time. * * @param context the target Context. * @see <a href="http://goo.gl/V5xbNd">Stack Overflow</a> */ public static void waitForApplicationContext(@NonNull final Context context) { final long endTime = SystemClock.elapsedRealtime() + WAIT_TIMEOUT_MILLIS; while (null == context.getApplicationContext()) { if (SystemClock.elapsedRealtime() >= endTime) { AndroidTestCase.fail("Application context is null."); } SystemClock.sleep(WAIT_SLEEP_MILLIS); } } /** * Private constructor prevents instantiation. * * @throws UnsupportedOperationException because this class cannot be instantiated. */ private SupportTestCaseUtils() { throw new UnsupportedOperationException("This class is non-instantiable"); } }