Skip to content

Commit

Permalink
fix: avoid crash when initializing bugsnag in attachBaseContext
Browse files Browse the repository at this point in the history
  • Loading branch information
fractalwrench committed Oct 15, 2020
1 parent 4f0c828 commit 9d1d8f6
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ public Client(@NonNull Context androidContext, @NonNull String apiKey) {
* @param configuration a configuration for the Client
*/
public Client(@NonNull Context androidContext, @NonNull final Configuration configuration) {
appContext = androidContext.getApplicationContext();
Context ctx = androidContext.getApplicationContext();
appContext = ctx != null ? ctx : androidContext;

connectivity = new ConnectivityCompat(appContext, new Function2<Boolean, String, Unit>() {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.bugsnag.android;

import static org.mockito.Mockito.when;

import android.app.Application;
import android.content.Context;

import kotlin.TypeCastException;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;


/**
* Verifies that the {@link Client} can be initialized with different subtypes
* of {@link Context} without crashing. The recommended usage is to initialize Bugsnag in
* {@link Application#onCreate()} which uses the application context, as this object remains
* available for the entire process lifecycle.
*
* It is also possible to initialize with a short-lived {@link android.app.Activity} context,
* from which the application context can be accessed via {@link Context#getApplicationContext()}.
* Neglecting to do this is a memory leak as the Activity object would otherwise be garbage
* collected.
*
* Finally, it is possible to initialize with the context passed as a parameter to
* {@link Application#attachBaseContext(Context)}. Initializing here is preferable as it will
* capture any crashes that occur before {@link Application#onCreate()} are called - for instance,
* crashes within a {@link android.content.ContentProvider}.
*
* Because this method is called before {@link Application#onCreate()} the application context will
* be null. This test verifies that initializing with all these context subtypes
* does not throw an {@link IllegalArgumentException} due to the context being null. As the Client
* relies on other Android framework classes that aren't accessible in a unit test that runs on
* the JVM, we assert that another exception further into the Client constructor is thrown instead.
*/
@RunWith(MockitoJUnitRunner.class)
public class ClientContextInitTest {

@Mock
Context appContext;

@Mock
Context anotherContext;

/**
* Verifies that if the application context is null the base context is used
*/
@Test(expected = TypeCastException.class)
public void testClientBaseContext() {
new Client(appContext, new Configuration("api-key"));
}

/**
* Verifies that the application context is always used if it is not null
*/
@Test(expected = TypeCastException.class)
public void testClientAppContext() {
when(appContext.getApplicationContext()).thenReturn(anotherContext);
new Client(appContext, new Configuration("api-key"));
}
}

0 comments on commit 9d1d8f6

Please sign in to comment.