diff --git a/bugsnag-android-core/api/bugsnag-android-core.api b/bugsnag-android-core/api/bugsnag-android-core.api index 3509b235bd..71a252c2c2 100644 --- a/bugsnag-android-core/api/bugsnag-android-core.api +++ b/bugsnag-android-core/api/bugsnag-android-core.api @@ -347,7 +347,10 @@ public final class com/bugsnag/android/ErrorTypes { public final fun setUnhandledRejections (Z)V } -public class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, com/bugsnag/android/JsonStream$Streamable, com/bugsnag/android/MetadataAware, com/bugsnag/android/UserAware { +public final class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, com/bugsnag/android/JsonStream$Streamable, com/bugsnag/android/MetadataAware, com/bugsnag/android/UserAware { + public field app Lcom/bugsnag/android/AppWithState; + public field device Lcom/bugsnag/android/DeviceWithState; + public fun (Ljava/lang/Throwable;Lcom/bugsnag/android/internal/ImmutableConfig;Ljava/lang/String;Lcom/bugsnag/android/Logger;)V public fun addFeatureFlag (Ljava/lang/String;)V public fun addFeatureFlag (Ljava/lang/String;Ljava/lang/String;)V public fun addFeatureFlags (Ljava/lang/Iterable;)V @@ -357,31 +360,48 @@ public class com/bugsnag/android/Event : com/bugsnag/android/FeatureFlagAware, c public fun clearFeatureFlags ()V public fun clearMetadata (Ljava/lang/String;)V public fun clearMetadata (Ljava/lang/String;Ljava/lang/String;)V - public fun getApiKey ()Ljava/lang/String; - public fun getApp ()Lcom/bugsnag/android/AppWithState; - public fun getBreadcrumbs ()Ljava/util/List; - public fun getContext ()Ljava/lang/String; - public fun getDevice ()Lcom/bugsnag/android/DeviceWithState; - public fun getErrors ()Ljava/util/List; - public fun getFeatureFlags ()Ljava/util/List; - public fun getGroupingHash ()Ljava/lang/String; + public final fun getApiKey ()Ljava/lang/String; + public final fun getApp ()Lcom/bugsnag/android/AppWithState; + public final fun getBreadcrumbs ()Ljava/util/List; + public final fun getContext ()Ljava/lang/String; + public final fun getDevice ()Lcom/bugsnag/android/DeviceWithState; + public final fun getErrors ()Ljava/util/List; + public final fun getFeatureFlags ()Ljava/util/List; + public final fun getGroupingHash ()Ljava/lang/String; + public final fun getInternalMetrics ()Lcom/bugsnag/android/internal/InternalMetrics; + public final fun getLogger ()Lcom/bugsnag/android/Logger; public fun getMetadata (Ljava/lang/String;)Ljava/util/Map; public fun getMetadata (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object; - public fun getOriginalError ()Ljava/lang/Throwable; - public fun getSeverity ()Lcom/bugsnag/android/Severity; - public fun getThreads ()Ljava/util/List; + public final fun getOriginalError ()Ljava/lang/Throwable; + public final fun getOriginalUnhandled ()Z + public final fun getRedactedKeys ()Ljava/util/Collection; + public final fun getSession ()Lcom/bugsnag/android/Session; + public final fun getSeverity ()Lcom/bugsnag/android/Severity; + public final fun getSeverityReasonType ()Ljava/lang/String; + public final fun getThreads ()Ljava/util/List; + public final fun getUnhandledOverridden ()Z public fun getUser ()Lcom/bugsnag/android/User; - public fun isUnhandled ()Z - public fun setApiKey (Ljava/lang/String;)V - public fun setContext (Ljava/lang/String;)V - public fun setGroupingHash (Ljava/lang/String;)V - public fun setSeverity (Lcom/bugsnag/android/Severity;)V - public fun setUnhandled (Z)V + public final fun getUserImpl ()Lcom/bugsnag/android/User; + public final fun isUnhandled ()Z + public final fun setApiKey (Ljava/lang/String;)V + public final fun setApp (Lcom/bugsnag/android/AppWithState;)V + public final fun setBreadcrumbs (Ljava/util/List;)V + public final fun setContext (Ljava/lang/String;)V + public final fun setDevice (Lcom/bugsnag/android/DeviceWithState;)V + public final fun setErrors (Ljava/util/List;)V + public final fun setGroupingHash (Ljava/lang/String;)V + public final fun setInternalMetrics (Lcom/bugsnag/android/internal/InternalMetrics;)V + public final fun setRedactedKeys (Ljava/util/Collection;)V + public final fun setSession (Lcom/bugsnag/android/Session;)V + public final fun setSeverity (Lcom/bugsnag/android/Severity;)V + public final fun setThreads (Ljava/util/List;)V + public final fun setUnhandled (Z)V public fun setUser (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V - protected fun shouldDiscardClass ()Z + public final fun setUserImpl (Lcom/bugsnag/android/User;)V + public final fun shouldDiscardClass ()Z public fun toStream (Lcom/bugsnag/android/JsonStream;)V - protected fun updateSeverityInternal (Lcom/bugsnag/android/Severity;)V - protected fun updateSeverityReason (Ljava/lang/String;)V + public final fun updateSeverityInternal (Lcom/bugsnag/android/Severity;)V + public final fun updateSeverityReason (Ljava/lang/String;)V } public final class com/bugsnag/android/EventPayload : com/bugsnag/android/JsonStream$Streamable { diff --git a/bugsnag-android-core/detekt-baseline.xml b/bugsnag-android-core/detekt-baseline.xml index bccf015f28..9f40db82ff 100644 --- a/bugsnag-android-core/detekt-baseline.xml +++ b/bugsnag-android-core/detekt-baseline.xml @@ -14,8 +14,8 @@ LongParameterList:DeviceDataCollector.kt$DeviceDataCollector$( private val connectivity: Connectivity, private val appContext: Context, resources: Resources, private val deviceId: String?, private val internalDeviceId: String?, private val buildInfo: DeviceBuildInfo, private val dataDirectory: File, rootDetector: RootDetector, private val bgTaskService: BackgroundTaskService, private val logger: Logger ) LongParameterList:DeviceIdStore.kt$DeviceIdStore$( context: Context, deviceIdfile: File = File(context.filesDir, "device-id"), deviceIdGenerator: () -> UUID = { UUID.randomUUID() }, internalDeviceIdfile: File = File(context.filesDir, "internal-device-id"), internalDeviceIdGenerator: () -> UUID = { UUID.randomUUID() }, private val sharedPrefMigrator: SharedPrefMigrator, logger: Logger ) LongParameterList:DeviceWithState.kt$DeviceWithState$( buildInfo: DeviceBuildInfo, jailbroken: Boolean?, id: String?, locale: String?, totalMemory: Long?, runtimeVersions: MutableMap<String, Any>, /** * The number of free bytes of storage available on the device */ var freeDisk: Long?, /** * The number of free bytes of memory available on the device */ var freeMemory: Long?, /** * The orientation of the device when the event occurred: either portrait or landscape */ var orientation: String?, /** * The timestamp on the device when the event occurred */ var time: Date? ) + LongParameterList:Event.kt$Event$( apiKey: String, logger: Logger, breadcrumbs: MutableList<Breadcrumb> = mutableListOf(), discardClasses: Set<Pattern> = setOf(), errors: MutableList<Error> = mutableListOf(), metadata: Metadata = Metadata(), featureFlags: FeatureFlags = FeatureFlags(), originalError: Throwable? = null, projectPackages: Collection<String> = setOf(), severityReason: SeverityReason = SeverityReason.newInstance(SeverityReason.REASON_HANDLED_EXCEPTION), threads: MutableList<Thread> = mutableListOf(), user: User = User(), redactionKeys: Set<Pattern>? = null ) LongParameterList:EventFilenameInfo.kt$EventFilenameInfo.Companion$( obj: Any, uuid: String = UUID.randomUUID().toString(), apiKey: String?, timestamp: Long = System.currentTimeMillis(), config: ImmutableConfig, isLaunching: Boolean? = null ) - LongParameterList:EventInternal.kt$EventInternal$( apiKey: String, logger: Logger, breadcrumbs: MutableList<Breadcrumb> = mutableListOf(), discardClasses: Set<Pattern> = setOf(), errors: MutableList<Error> = mutableListOf(), metadata: Metadata = Metadata(), featureFlags: FeatureFlags = FeatureFlags(), originalError: Throwable? = null, projectPackages: Collection<String> = setOf(), severityReason: SeverityReason = SeverityReason.newInstance(SeverityReason.REASON_HANDLED_EXCEPTION), threads: MutableList<Thread> = mutableListOf(), user: User = User(), redactionKeys: Set<Pattern>? = null ) LongParameterList:EventStorageModule.kt$EventStorageModule$( contextModule: ContextModule, configModule: ConfigModule, dataCollectionModule: DataCollectionModule, bgTaskService: BackgroundTaskService, trackerModule: TrackerModule, systemServiceModule: SystemServiceModule, notifier: Notifier, callbackState: CallbackState ) LongParameterList:NativeStackframe.kt$NativeStackframe$( /** * The name of the method that was being executed */ var method: String?, /** * The location of the source file */ var file: String?, /** * The line number within the source file this stackframe refers to */ var lineNumber: Number?, /** * The address of the instruction where the event occurred. */ var frameAddress: Long?, /** * The address of the function where the event occurred. */ var symbolAddress: Long?, /** * The address of the library where the event occurred. */ var loadAddress: Long?, /** * Whether this frame identifies the program counter */ var isPC: Boolean?, /** * The type of the error */ var type: ErrorType? = null, /** * Identifies the exact build this frame originates from. */ var codeIdentifier: String? = null, ) LongParameterList:StateEvent.kt$StateEvent.Install$( @JvmField val apiKey: String, @JvmField val autoDetectNdkCrashes: Boolean, @JvmField val appVersion: String?, @JvmField val buildUuid: String?, @JvmField val releaseStage: String?, @JvmField val lastRunInfoPath: String, @JvmField val consecutiveLaunchCrashes: Int, @JvmField val sendThreads: ThreadSendPolicy ) @@ -40,10 +40,7 @@ NestedBlockDepth:FileStore.kt$FileStore$fun findStoredFiles(): MutableList<File> NestedBlockDepth:JsonHelper.kt$JsonHelper$fun jsonToLong(value: Any?): Long? ProtectedMemberInFinalClass:ConfigInternal.kt$ConfigInternal$protected val plugins = HashSet<Plugin>() - ProtectedMemberInFinalClass:EventInternal.kt$EventInternal$protected fun isAnr(event: Event): Boolean - ProtectedMemberInFinalClass:EventInternal.kt$EventInternal$protected fun shouldDiscardClass(): Boolean - ProtectedMemberInFinalClass:EventInternal.kt$EventInternal$protected fun updateSeverityInternal(severity: Severity) - ProtectedMemberInFinalClass:EventInternal.kt$EventInternal$protected fun updateSeverityReason(@SeverityReason.SeverityReasonType reason: String) + ProtectedMemberInFinalClass:Event.kt$Event$protected fun isAnr(event: Event): Boolean ReturnCount:DefaultDelivery.kt$DefaultDelivery$fun deliver( urlString: String, json: ByteArray, headers: Map<String, String?> ): DeliveryStatus SpreadOperator:FileStore.kt$FileStore$(*listFiles) SwallowedException:AppDataCollector.kt$AppDataCollector$e: Exception @@ -64,7 +61,7 @@ ThrowsCount:JsonHelper.kt$JsonHelper$fun jsonToLong(value: Any?): Long? TooManyFunctions:ConfigInternal.kt$ConfigInternal : CallbackAwareMetadataAwareUserAwareFeatureFlagAware TooManyFunctions:DeviceDataCollector.kt$DeviceDataCollector - TooManyFunctions:EventInternal.kt$EventInternal : FeatureFlagAwareStreamableMetadataAwareUserAware + TooManyFunctions:Event.kt$Event : StreamableMetadataAwareUserAwareFeatureFlagAware UnusedPrivateProperty:ManifestConfigLoader.kt$ManifestConfigLoader.Companion$private const val LAUNCH_CRASH_THRESHOLD_MS = "$BUGSNAG_NS.LAUNCH_CRASH_THRESHOLD_MS" UnusedPrivateProperty:ThreadStateTest.kt$ThreadStateTest$private val configuration = generateImmutableConfig() UseCheckOrError:BackgroundTaskServiceTest.kt$BackgroundTaskServiceTest$throw IllegalStateException() diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/BugsnagEventMapper.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/BugsnagEventMapper.kt index c8a7763932..4de2fed9ae 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/BugsnagEventMapper.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/BugsnagEventMapper.kt @@ -13,12 +13,12 @@ internal class BugsnagEventMapper( ) { internal fun convertToEvent(map: Map, apiKey: String): Event { - return Event(convertToEventImpl(map, apiKey), logger) + return convertToEventImpl(map, apiKey) } @Suppress("UNCHECKED_CAST") - internal fun convertToEventImpl(map: Map, apiKey: String): EventInternal { - val event = EventInternal(apiKey, logger) + internal fun convertToEventImpl(map: Map, apiKey: String): Event { + val event = Event(apiKey, logger) // populate exceptions. check this early to avoid unnecessary serialization if // no stacktrace was gathered. diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/DefaultDelivery.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/DefaultDelivery.kt index 72c8a9200f..3006e58a69 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/DefaultDelivery.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/DefaultDelivery.kt @@ -44,8 +44,8 @@ internal class DefaultDelivery( payload.apiKey = apiKey } - val (itemsTrimmed, dataTrimmed) = event.impl.trimMetadataStringsTo(maxStringValueLength) - event.impl.internalMetrics.setMetadataTrimMetrics( + val (itemsTrimmed, dataTrimmed) = event.trimMetadataStringsTo(maxStringValueLength) + event.internalMetrics.setMetadataTrimMetrics( itemsTrimmed, dataTrimmed ) @@ -56,8 +56,8 @@ internal class DefaultDelivery( } val breadcrumbAndBytesRemovedCounts = - event.impl.trimBreadcrumbsBy(json.size - maxPayloadSize) - event.impl.internalMetrics.setBreadcrumbTrimMetrics( + event.trimBreadcrumbsBy(json.size - maxPayloadSize) + event.internalMetrics.setBreadcrumbTrimMetrics( breadcrumbAndBytesRemovedCounts.itemsTrimmed, breadcrumbAndBytesRemovedCounts.dataTrimmed ) diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/DeliveryDelegate.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/DeliveryDelegate.java index 5c4ef01616..f79911b8f3 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/DeliveryDelegate.java +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/DeliveryDelegate.java @@ -53,11 +53,11 @@ void deliver(@NonNull Event event) { } } - if (event.getImpl().getOriginalUnhandled()) { + if (event.getOriginalUnhandled()) { // should only send unhandled errors if they don't terminate the process (i.e. ANRs) - String severityReasonType = event.getImpl().getSeverityReasonType(); + String severityReasonType = event.getSeverityReasonType(); boolean promiseRejection = REASON_PROMISE_REJECTION.equals(severityReasonType); - boolean anr = event.getImpl().isAnr(event); + boolean anr = event.isAnr(event); if (anr || promiseRejection) { cacheEvent(event, true); } else if (immutableConfig.getAttemptDeliveryOnCrash()) { diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.java deleted file mode 100644 index ac498bb174..0000000000 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.java +++ /dev/null @@ -1,429 +0,0 @@ -package com.bugsnag.android; - -import com.bugsnag.android.internal.ImmutableConfig; -import com.bugsnag.android.internal.InternalMetrics; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -/** - * An Event object represents a Throwable captured by Bugsnag and is available as a parameter on - * an {@link OnErrorCallback}, where individual properties can be mutated before an error report is - * sent to Bugsnag's API. - */ -@SuppressWarnings("ConstantConditions") -public class Event implements JsonStream.Streamable, MetadataAware, UserAware, FeatureFlagAware { - - private final EventInternal impl; - private final Logger logger; - - Event(@Nullable Throwable originalError, - @NonNull ImmutableConfig config, - @NonNull SeverityReason severityReason, - @NonNull Logger logger) { - this(originalError, config, severityReason, new Metadata(), new FeatureFlags(), logger); - } - - Event(@Nullable Throwable originalError, - @NonNull ImmutableConfig config, - @NonNull SeverityReason severityReason, - @NonNull Metadata metadata, - @NonNull FeatureFlags featureFlags, - @NonNull Logger logger) { - this(new EventInternal(originalError, config, severityReason, metadata, featureFlags), - logger); - } - - Event(@NonNull EventInternal impl, @NonNull Logger logger) { - this.impl = impl; - this.logger = logger; - } - - private void logNull(String property) { - logger.e("Invalid null value supplied to config." + property + ", ignoring"); - } - - /** - * The Throwable object that caused the event in your application. - * - * Manipulating this field does not affect the error information reported to the - * Bugsnag dashboard. Use {@link Event#getErrors()} to access and amend the representation of - * the error that will be sent. - */ - @Nullable - public Throwable getOriginalError() { - return impl.getOriginalError(); - } - - /** - * Information extracted from the {@link Throwable} that caused the event can be found in this - * field. The list contains at least one {@link Error} that represents the thrown object - * with subsequent elements in the list populated from {@link Throwable#getCause()}. - * - * A reference to the actual {@link Throwable} object that caused the event is available - * through {@link Event#getOriginalError()} ()}. - */ - @NonNull - public List getErrors() { - return impl.getErrors(); - } - - /** - * If thread state is being captured along with the event, this field will contain a - * list of {@link Thread} objects. - */ - @NonNull - public List getThreads() { - return impl.getThreads(); - } - - /** - * A list of breadcrumbs leading up to the event. These values can be accessed and amended - * if necessary. See {@link Breadcrumb} for details of the data available. - */ - @NonNull - public List getBreadcrumbs() { - return impl.getBreadcrumbs(); - } - - /** - * A list of feature flags active at the time of the event. - * See {@link FeatureFlag} for details of the data available. - */ - @NonNull - public List getFeatureFlags() { - return impl.getFeatureFlags().toList(); - } - - /** - * Information set by the notifier about your app can be found in this field. These values - * can be accessed and amended if necessary. - */ - @NonNull - public AppWithState getApp() { - return impl.getApp(); - } - - /** - * Information set by the notifier about your device can be found in this field. These values - * can be accessed and amended if necessary. - */ - @NonNull - public DeviceWithState getDevice() { - return impl.getDevice(); - } - - /** - * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag - * is initialized, you may choose to send certain events to a different Bugsnag project. - */ - public void setApiKey(@NonNull String apiKey) { - if (apiKey != null) { - impl.setApiKey(apiKey); - } else { - logNull("apiKey"); - } - } - - /** - * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag - * is initialized, you may choose to send certain events to a different Bugsnag project. - */ - @NonNull - public String getApiKey() { - return impl.getApiKey(); - } - - /** - * The severity of the event. By default, unhandled exceptions will be {@link Severity#ERROR} - * and handled exceptions sent with {@link Bugsnag#notify} {@link Severity#WARNING}. - */ - public void setSeverity(@NonNull Severity severity) { - if (severity != null) { - impl.setSeverity(severity); - } else { - logNull("severity"); - } - } - - /** - * The severity of the event. By default, unhandled exceptions will be {@link Severity#ERROR} - * and handled exceptions sent with {@link Bugsnag#notify} {@link Severity#WARNING}. - */ - @NonNull - public Severity getSeverity() { - return impl.getSeverity(); - } - - /** - * Set the grouping hash of the event to override the default grouping on the dashboard. - * All events with the same grouping hash will be grouped together into one error. This is an - * advanced usage of the library and mis-using it will cause your events not to group properly - * in your dashboard. - * - * As the name implies, this option accepts a hash of sorts. - */ - public void setGroupingHash(@Nullable String groupingHash) { - impl.setGroupingHash(groupingHash); - } - - /** - * Set the grouping hash of the event to override the default grouping on the dashboard. - * All events with the same grouping hash will be grouped together into one error. This is an - * advanced usage of the library and mis-using it will cause your events not to group properly - * in your dashboard. - * - * As the name implies, this option accepts a hash of sorts. - */ - @Nullable - public String getGroupingHash() { - return impl.getGroupingHash(); - } - - /** - * Sets the context of the error. The context is a summary what what was occurring in the - * application at the time of the crash, if available, such as the visible activity. - */ - public void setContext(@Nullable String context) { - impl.setContext(context); - } - - /** - * Returns the context of the error. The context is a summary what what was occurring in the - * application at the time of the crash, if available, such as the visible activity. - */ - @Nullable - public String getContext() { - return impl.getContext(); - } - - /** - * Sets the user associated with the event. - */ - @Override - public void setUser(@Nullable String id, @Nullable String email, @Nullable String name) { - impl.setUser(id, email, name); - } - - /** - * Returns the currently set User information. - */ - @Override - @NonNull - public User getUser() { - return impl.getUser(); - } - - /** - * Adds a map of multiple metadata key-value pairs to the specified section. - */ - @Override - public void addMetadata(@NonNull String section, @NonNull Map value) { - if (section != null && value != null) { - impl.addMetadata(section, value); - } else { - logNull("addMetadata"); - } - } - - /** - * Adds the specified key and value in the specified section. The value can be of - * any primitive type or a collection such as a map, set or array. - */ - @Override - public void addMetadata(@NonNull String section, @NonNull String key, @Nullable Object value) { - if (section != null && key != null) { - impl.addMetadata(section, key, value); - } else { - logNull("addMetadata"); - } - } - - /** - * Removes all the data from the specified section. - */ - @Override - public void clearMetadata(@NonNull String section) { - if (section != null) { - impl.clearMetadata(section); - } else { - logNull("clearMetadata"); - } - } - - /** - * Removes data with the specified key from the specified section. - */ - @Override - public void clearMetadata(@NonNull String section, @NonNull String key) { - if (section != null && key != null) { - impl.clearMetadata(section, key); - } else { - logNull("clearMetadata"); - } - } - - /** - * Returns a map of data in the specified section. - */ - @Override - @Nullable - public Map getMetadata(@NonNull String section) { - if (section != null) { - return impl.getMetadata(section); - } else { - logNull("getMetadata"); - return null; - } - } - - /** - * Returns the value of the specified key in the specified section. - */ - @Override - @Nullable - public Object getMetadata(@NonNull String section, @NonNull String key) { - if (section != null && key != null) { - return impl.getMetadata(section, key); - } else { - logNull("getMetadata"); - return null; - } - } - - /** - * {@inheritDoc} - */ - @Override - public void addFeatureFlag(@NonNull String name) { - if (name != null) { - impl.addFeatureFlag(name); - } else { - logNull("addFeatureFlag"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void addFeatureFlag(@NonNull String name, @Nullable String variant) { - if (name != null) { - impl.addFeatureFlag(name, variant); - } else { - logNull("addFeatureFlag"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void addFeatureFlags(@NonNull Iterable featureFlags) { - if (featureFlags != null) { - impl.addFeatureFlags(featureFlags); - } else { - logNull("addFeatureFlags"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void clearFeatureFlag(@NonNull String name) { - if (name != null) { - impl.clearFeatureFlag(name); - } else { - logNull("clearFeatureFlag"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void clearFeatureFlags() { - impl.clearFeatureFlags(); - } - - @Override - public void toStream(@NonNull JsonStream stream) throws IOException { - impl.toStream(stream); - } - - /** - * Whether the event was a crash (i.e. unhandled) or handled error in which the system - * continued running. - * - * Unhandled errors count towards your stability score. If you don't want certain errors - * to count towards your stability score, you can alter this property through an - * {@link OnErrorCallback}. - */ - public boolean isUnhandled() { - return impl.getUnhandled(); - } - - /** - * Whether the event was a crash (i.e. unhandled) or handled error in which the system - * continued running. - * - * Unhandled errors count towards your stability score. If you don't want certain errors - * to count towards your stability score, you can alter this property through an - * {@link OnErrorCallback}. - */ - public void setUnhandled(boolean unhandled) { - impl.setUnhandled(unhandled); - } - - protected boolean shouldDiscardClass() { - return impl.shouldDiscardClass(); - } - - protected void updateSeverityInternal(@NonNull Severity severity) { - impl.updateSeverityInternal(severity); - } - - protected void updateSeverityReason(@NonNull @SeverityReason.SeverityReasonType String reason) { - impl.updateSeverityReason(reason); - } - - void setApp(@NonNull AppWithState app) { - impl.setApp(app); - } - - void setDevice(@NonNull DeviceWithState device) { - impl.setDevice(device); - } - - void setBreadcrumbs(@NonNull List breadcrumbs) { - impl.setBreadcrumbs(breadcrumbs); - } - - @Nullable - Session getSession() { - return impl.session; - } - - void setSession(@Nullable Session session) { - impl.session = session; - } - - EventInternal getImpl() { - return impl; - } - - void setRedactedKeys(Collection redactedKeys) { - impl.setRedactedKeys(redactedKeys); - } - - void setInternalMetrics(InternalMetrics metrics) { - impl.setInternalMetrics(metrics); - } -} diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.kt new file mode 100644 index 0000000000..c85b5c7f68 --- /dev/null +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/Event.kt @@ -0,0 +1,577 @@ +package com.bugsnag.android + +import androidx.annotation.RestrictTo +import com.bugsnag.android.JsonStream.Streamable +import com.bugsnag.android.SeverityReason.SeverityReasonType +import com.bugsnag.android.internal.ImmutableConfig +import com.bugsnag.android.internal.InternalMetrics +import com.bugsnag.android.internal.InternalMetricsNoop +import com.bugsnag.android.internal.JsonHelper +import com.bugsnag.android.internal.TrimMetrics +import java.io.IOException +import java.util.regex.Pattern + +/** + * An Event object represents a Throwable captured by Bugsnag and is available as a parameter on + * an [OnErrorCallback], where individual properties can be mutated before an error report is + * sent to Bugsnag's API. + */ +class Event : Streamable, MetadataAware, UserAware, FeatureFlagAware { + + internal var severityReason: SeverityReason + val logger: Logger + internal val metadata: Metadata + + private val jsonStreamer: ObjectJsonStreamer = ObjectJsonStreamer().apply { + redactedKeys = redactedKeys.toSet() + } + + lateinit var app: AppWithState + lateinit var device: DeviceWithState + + var redactedKeys: Collection + get() = jsonStreamer.redactedKeys + set(value) { + jsonStreamer.redactedKeys = value.toSet() + metadata.redactedKeys = value.toSet() + } + var internalMetrics: InternalMetrics = InternalMetricsNoop() + + /** + * @return user information associated with this Event + */ + var userImpl: User + + internal constructor( + originalError: Throwable?, + config: ImmutableConfig, + severityReason: SeverityReason, + data: Metadata = Metadata(), + featureFlags: FeatureFlags = FeatureFlags(), + logger: Logger = config.logger + ) : this( + config.apiKey, + logger, + mutableListOf(), + config.discardClasses.toSet(), + when (originalError) { + null -> mutableListOf() + else -> Error.createError(originalError, config.projectPackages, config.logger) + }, + data.copy(), + featureFlags.copy(), + originalError, + config.projectPackages, + severityReason, + ThreadState(originalError, severityReason.unhandled, config).threads, + User(), + config.redactedKeys.toSet() + ) + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) + constructor( + originalError: Throwable?, + config: ImmutableConfig, + severityReason: String, + logger: Logger + ) : this( + originalError, + config, + SeverityReason.newInstance(severityReason), + Metadata(), + FeatureFlags(), + logger + ) + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) + internal constructor( + originalError: Throwable?, + config: ImmutableConfig, + severityReason: SeverityReason, + logger: Logger + ) : this( + originalError, + config, + severityReason, + Metadata(), + FeatureFlags(), + logger + ) + + internal constructor( + apiKey: String, + logger: Logger, + breadcrumbs: MutableList = mutableListOf(), + discardClasses: Set = setOf(), + errors: MutableList = mutableListOf(), + metadata: Metadata = Metadata(), + featureFlags: FeatureFlags = FeatureFlags(), + originalError: Throwable? = null, + projectPackages: Collection = setOf(), + severityReason: SeverityReason = SeverityReason.newInstance(SeverityReason.REASON_HANDLED_EXCEPTION), + threads: MutableList = mutableListOf(), + user: User = User(), + redactionKeys: Set? = null + ) { + this.logger = logger + this.apiKey = apiKey + this.breadcrumbs = breadcrumbs + this.discardClasses = discardClasses + this.errors = errors + this.metadata = metadata + this._featureFlags = featureFlags + this.originalError = originalError + this.projectPackages = projectPackages + this.severityReason = severityReason + this.threads = threads + this.userImpl = user + + redactionKeys?.let { + this.redactedKeys = it + } + } + + private fun logNull(property: String) { + logger.e("Invalid null value supplied to config.$property, ignoring") + } + + /** + * The Throwable object that caused the event in your application. + * + * Manipulating this field does not affect the error information reported to the + * Bugsnag dashboard. Use [Event.getErrors] to access and amend the representation of + * the error that will be sent. + */ + val originalError: Throwable? + + /** + * Information extracted from the [Throwable] that caused the event can be found in this + * field. The list contains at least one [Error] that represents the thrown object + * with subsequent elements in the list populated from [Throwable.getCause]. + * + * A reference to the actual [Throwable] object that caused the event is available + * through [Event.getOriginalError] ()}. + */ + var errors: MutableList + + /** + * If thread state is being captured along with the event, this field will contain a + * list of [Thread] objects. + */ + var threads: MutableList + + /** + * A list of breadcrumbs leading up to the event. These values can be accessed and amended + * if necessary. See [Breadcrumb] for details of the data available. + */ + var breadcrumbs: MutableList + set(breadcrumbs) { + field = breadcrumbs.toMutableList() + } + + /** + * A list of feature flags active at the time of the event. + * See [FeatureFlag] for details of the data available. + */ + val featureFlags: List + get() = _featureFlags.toList() + + private val _featureFlags: FeatureFlags + + /** + * Information set by the notifier about your app can be found in this field. These values + * can be accessed and amended if necessary. + */ + private val discardClasses: Set + + /** + * Information set by the notifier about your device can be found in this field. These values + * can be accessed and amended if necessary. + */ + internal var projectPackages: Collection + + /** + * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag + * is initialized, you may choose to send certain events to a different Bugsnag project. + */ + /** + * The API key used for events sent to Bugsnag. Even though the API key is set when Bugsnag + * is initialized, you may choose to send certain events to a different Bugsnag project. + */ + var apiKey: String + set(apiKey) = + @Suppress("SENSELESS_COMPARISON") + if (apiKey != null) { + field = apiKey + } else { + logNull("apiKey") + } + /** + * The severity of the event. By default, unhandled exceptions will be [Severity.ERROR] + * and handled exceptions sent with [Bugsnag.notify] [Severity.WARNING]. + */ + /** + * The severity of the event. By default, unhandled exceptions will be [Severity.ERROR] + * and handled exceptions sent with [Bugsnag.notify] [Severity.WARNING]. + */ + var severity: Severity + get() = severityReason.currentSeverity + set(value) { + @Suppress("SENSELESS_COMPARISON") + if (value != null) { + severityReason.currentSeverity = value + } else { + logNull("severity") + } + } + + /** + * Set the grouping hash of the event to override the default grouping on the dashboard. + * All events with the same grouping hash will be grouped together into one error. This is an + * advanced usage of the library and mis-using it will cause your events not to group properly + * in your dashboard. + * + * As the name implies, this option accepts a hash of sorts. + */ + /** + * Set the grouping hash of the event to override the default grouping on the dashboard. + * All events with the same grouping hash will be grouped together into one error. This is an + * advanced usage of the library and mis-using it will cause your events not to group properly + * in your dashboard. + * + * As the name implies, this option accepts a hash of sorts. + */ + var groupingHash: String? = null + /** + * Returns the context of the error. The context is a summary what what was occurring in the + * application at the time of the crash, if available, such as the visible activity. + */ + /** + * Sets the context of the error. The context is a summary what what was occurring in the + * application at the time of the crash, if available, such as the visible activity. + */ + var context: String? = null + + /** + * Sets the user associated with the event. + */ + override fun setUser(id: String?, email: String?, name: String?) { + userImpl = User(id, email, name) + } + + /** + * Returns the currently set User information. + */ + override fun getUser(): User { + return userImpl + } + + /** + * Adds a map of multiple metadata key-value pairs to the specified section. + */ + override fun addMetadata(section: String, value: Map) { + @Suppress("SENSELESS_COMPARISON") + if (section != null && value != null) { + metadata.addMetadata(section, value) + } else { + logNull("addMetadata") + } + } + + /** + * Adds the specified key and value in the specified section. The value can be of + * any primitive type or a collection such as a map, set or array. + */ + override fun addMetadata(section: String, key: String, value: Any?) { + @Suppress("SENSELESS_COMPARISON") + if (section != null && key != null) { + metadata.addMetadata(section, key, value) + } else { + logNull("addMetadata") + } + } + + /** + * Removes all the data from the specified section. + */ + override fun clearMetadata(section: String) { + @Suppress("SENSELESS_COMPARISON") + if (section != null) { + metadata.clearMetadata(section) + } else { + logNull("clearMetadata") + } + } + + /** + * Removes data with the specified key from the specified section. + */ + override fun clearMetadata(section: String, key: String) { + @Suppress("SENSELESS_COMPARISON") + if (section != null && key != null) { + metadata.clearMetadata(section, key) + } else { + logNull("clearMetadata") + } + } + + /** + * Returns a map of data in the specified section. + */ + override fun getMetadata(section: String): Map? { + @Suppress("SENSELESS_COMPARISON") + return if (section != null) { + metadata.getMetadata(section) + } else { + logNull("getMetadata") + null + } + } + + /** + * Returns the value of the specified key in the specified section. + */ + override fun getMetadata(section: String, key: String): Any? { + @Suppress("SENSELESS_COMPARISON") + return if (section != null && key != null) { + metadata.getMetadata(section, key) + } else { + logNull("getMetadata") + null + } + } + + /** + * {@inheritDoc} + */ + override fun addFeatureFlag(name: String) { + @Suppress("SENSELESS_COMPARISON") + if (name != null) { + _featureFlags.addFeatureFlag(name) + } else { + logNull("addFeatureFlag") + } + } + + /** + * {@inheritDoc} + */ + override fun addFeatureFlag(name: String, variant: String?) { + @Suppress("SENSELESS_COMPARISON") + if (name != null) { + _featureFlags.addFeatureFlag(name, variant) + } else { + logNull("addFeatureFlag") + } + } + + /** + * {@inheritDoc} + */ + override fun addFeatureFlags(featureFlags: Iterable) { + @Suppress("SENSELESS_COMPARISON") + if (featureFlags != null) { + this._featureFlags.addFeatureFlags(featureFlags) + } else { + logNull("addFeatureFlags") + } + } + + /** + * {@inheritDoc} + */ + override fun clearFeatureFlag(name: String) { + @Suppress("SENSELESS_COMPARISON") + if (name != null) { + _featureFlags.clearFeatureFlag(name) + } else { + logNull("clearFeatureFlag") + } + } + + /** + * {@inheritDoc} + */ + override fun clearFeatureFlags() { + _featureFlags.clearFeatureFlags() + } + + @Throws(IOException::class) + override fun toStream(parentWriter: JsonStream) { + val writer = JsonStream(parentWriter, jsonStreamer) + // Write error basics + writer.beginObject() + writer.name("context").value(context) + writer.name("metaData").value(metadata) + + writer.name("severity").value(severity) + writer.name("severityReason").value(severityReason) + writer.name("unhandled").value(severityReason.unhandled) + + // Write exception info + writer.name("exceptions") + writer.beginArray() + errors.forEach { writer.value(it) } + writer.endArray() + + // Write project packages + writer.name("projectPackages") + writer.beginArray() + projectPackages.forEach { writer.value(it) } + writer.endArray() + + // Write user info + writer.name("user").value(userImpl) + + // Write diagnostics + writer.name("app").value(app) + writer.name("device").value(device) + writer.name("breadcrumbs").value(breadcrumbs) + writer.name("groupingHash").value(groupingHash) + val usage = internalMetrics.toJsonableMap() + if (usage.isNotEmpty()) { + writer.name("usage") + writer.beginObject() + usage.forEach { entry -> + writer.name(entry.key).value(entry.value) + } + writer.endObject() + } + + writer.name("threads") + writer.beginArray() + threads.forEach { writer.value(it) } + writer.endArray() + + writer.name("featureFlags").value(_featureFlags) + + if (session != null) { + val copy = Session.copySession(session) + writer.name("session").beginObject() + writer.name("id").value(copy.id) + writer.name("startedAt").value(copy.startedAt) + writer.name("events").beginObject() + writer.name("handled").value(copy.handledCount.toLong()) + writer.name("unhandled").value(copy.unhandledCount.toLong()) + writer.endObject() + writer.endObject() + } + + writer.endObject() + } + + var isUnhandled: Boolean + @JvmName("setUnhandled") set(unhandled) { + severityReason.unhandled = unhandled + } + @JvmName("isUnhandled") get() = severityReason.unhandled + + fun shouldDiscardClass(): Boolean { + return when { + errors.isEmpty() -> true + else -> errors.any { error -> + discardClasses.any { pattern -> + pattern.matcher(error.errorClass).matches() + } + } + } + } + + internal fun trimMetadataStringsTo(maxLength: Int): TrimMetrics { + var stringCount = 0 + var charCount = 0 + + var stringAndCharCounts = metadata.trimMetadataStringsTo(maxLength) + stringCount += stringAndCharCounts.itemsTrimmed + charCount += stringAndCharCounts.dataTrimmed + for (breadcrumb in breadcrumbs) { + stringAndCharCounts = breadcrumb.impl.trimMetadataStringsTo(maxLength) + stringCount += stringAndCharCounts.itemsTrimmed + charCount += stringAndCharCounts.dataTrimmed + } + return TrimMetrics(stringCount, charCount) + } + + internal fun trimBreadcrumbsBy(byteCount: Int): TrimMetrics { + var removedBreadcrumbCount = 0 + var removedByteCount = 0 + while (removedByteCount < byteCount && breadcrumbs.isNotEmpty()) { + val breadcrumb = breadcrumbs.removeAt(0) + removedByteCount += JsonHelper.serialize(breadcrumb).size + removedBreadcrumbCount++ + } + when (removedBreadcrumbCount) { + 1 -> breadcrumbs.add(Breadcrumb("Removed to reduce payload size", logger)) + else -> breadcrumbs.add( + Breadcrumb( + "Removed, along with ${removedBreadcrumbCount - 1} older breadcrumbs, to reduce payload size", + logger + ) + ) + } + return TrimMetrics(removedBreadcrumbCount, removedByteCount) + } + + protected fun isAnr(event: Event): Boolean { + val errors = event.errors + var errorClass: String? = null + if (errors.isNotEmpty()) { + val error = errors[0] + errorClass = error.errorClass + } + return "ANR" == errorClass + } + + fun getUnhandledOverridden(): Boolean = severityReason.unhandledOverridden + + fun getOriginalUnhandled(): Boolean = severityReason.originalUnhandled + + fun getSeverityReasonType(): String = severityReason.severityReasonType + + internal fun getErrorTypesFromStackframes(): Set { + val errorTypes = errors.mapNotNull(Error::getType).toSet() + val frameOverrideTypes = errors + .map { it.stacktrace } + .flatMap { it.mapNotNull(Stackframe::type) } + return errorTypes.plus(frameOverrideTypes) + } + + internal fun normalizeStackframeErrorTypes() { + if (getErrorTypesFromStackframes().size == 1) { + errors.flatMap { it.stacktrace }.forEach { + it.type = null + } + } + } + + internal fun updateSeverityReasonInternal(severityReason: SeverityReason) { + this.severityReason = severityReason + } + + fun updateSeverityInternal(severity: Severity) { + severityReason = SeverityReason( + severityReason.severityReasonType, + severity, + severityReason.unhandled, + severityReason.unhandledOverridden, + severityReason.attributeValue, + severityReason.attributeKey + ) + } + + fun updateSeverityReason(@SeverityReasonType reason: String) { + severityReason = SeverityReason( + reason, + severityReason.currentSeverity, + severityReason.unhandled, + severityReason.unhandledOverridden, + severityReason.attributeValue, + severityReason.attributeKey + ) + } + + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) + var session: Session? = null + @JvmName("setSession") set + @JvmName("getSession") get +} diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventFilenameInfo.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventFilenameInfo.kt index f7cfd5f9af..594372604b 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventFilenameInfo.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventFilenameInfo.kt @@ -146,7 +146,7 @@ internal data class EventFilenameInfo( */ internal fun findErrorTypesForEvent(obj: Any): Set { return when (obj) { - is Event -> obj.impl.getErrorTypesFromStackframes() + is Event -> obj.getErrorTypesFromStackframes() else -> setOf(ErrorType.C) } } diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventInternal.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventInternal.kt index 4a1881f71d..2e280b336c 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventInternal.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventInternal.kt @@ -1,321 +1,321 @@ -package com.bugsnag.android - -import com.bugsnag.android.internal.ImmutableConfig -import com.bugsnag.android.internal.InternalMetrics -import com.bugsnag.android.internal.InternalMetricsNoop -import com.bugsnag.android.internal.JsonHelper -import com.bugsnag.android.internal.TrimMetrics -import java.io.IOException -import java.util.regex.Pattern - -internal class EventInternal : FeatureFlagAware, JsonStream.Streamable, MetadataAware, UserAware { - - @JvmOverloads - internal constructor( - originalError: Throwable? = null, - config: ImmutableConfig, - severityReason: SeverityReason, - data: Metadata = Metadata(), - featureFlags: FeatureFlags = FeatureFlags() - ) : this( - config.apiKey, - config.logger, - mutableListOf(), - config.discardClasses.toSet(), - when (originalError) { - null -> mutableListOf() - else -> Error.createError(originalError, config.projectPackages, config.logger) - }, - data.copy(), - featureFlags.copy(), - originalError, - config.projectPackages, - severityReason, - ThreadState(originalError, severityReason.unhandled, config).threads, - User(), - config.redactedKeys.toSet() - ) - - internal constructor( - apiKey: String, - logger: Logger, - breadcrumbs: MutableList = mutableListOf(), - discardClasses: Set = setOf(), - errors: MutableList = mutableListOf(), - metadata: Metadata = Metadata(), - featureFlags: FeatureFlags = FeatureFlags(), - originalError: Throwable? = null, - projectPackages: Collection = setOf(), - severityReason: SeverityReason = SeverityReason.newInstance(SeverityReason.REASON_HANDLED_EXCEPTION), - threads: MutableList = mutableListOf(), - user: User = User(), - redactionKeys: Set? = null - ) { - this.logger = logger - this.apiKey = apiKey - this.breadcrumbs = breadcrumbs - this.discardClasses = discardClasses - this.errors = errors - this.metadata = metadata - this.featureFlags = featureFlags - this.originalError = originalError - this.projectPackages = projectPackages - this.severityReason = severityReason - this.threads = threads - this.userImpl = user - - redactionKeys?.let { - this.redactedKeys = it - } - } - - val originalError: Throwable? - internal var severityReason: SeverityReason - - val logger: Logger - val metadata: Metadata - val featureFlags: FeatureFlags - private val discardClasses: Set - internal var projectPackages: Collection - - private val jsonStreamer: ObjectJsonStreamer = ObjectJsonStreamer().apply { - redactedKeys = redactedKeys.toSet() - } - - @JvmField - internal var session: Session? = null - - var severity: Severity - get() = severityReason.currentSeverity - set(value) { - severityReason.currentSeverity = value - } - - var apiKey: String - lateinit var app: AppWithState - lateinit var device: DeviceWithState - var unhandled: Boolean - get() = severityReason.unhandled - set(value) { - severityReason.unhandled = value - } - - var breadcrumbs: MutableList - var errors: MutableList - var threads: MutableList - var groupingHash: String? = null - var context: String? = null - - var redactedKeys: Collection - get() = jsonStreamer.redactedKeys - set(value) { - jsonStreamer.redactedKeys = value.toSet() - metadata.redactedKeys = value.toSet() - } - var internalMetrics: InternalMetrics = InternalMetricsNoop() - - /** - * @return user information associated with this Event - */ - internal var userImpl: User - - fun getUnhandledOverridden(): Boolean = severityReason.unhandledOverridden - - fun getOriginalUnhandled(): Boolean = severityReason.originalUnhandled - - protected fun shouldDiscardClass(): Boolean { - return when { - errors.isEmpty() -> true - else -> errors.any { error -> - discardClasses.any { pattern -> - pattern.matcher(error.errorClass).matches() - } - } - } - } - - protected fun isAnr(event: Event): Boolean { - val errors = event.errors - var errorClass: String? = null - if (errors.isNotEmpty()) { - val error = errors[0] - errorClass = error.errorClass - } - return "ANR" == errorClass - } - - @Throws(IOException::class) - override fun toStream(parentWriter: JsonStream) { - val writer = JsonStream(parentWriter, jsonStreamer) - // Write error basics - writer.beginObject() - writer.name("context").value(context) - writer.name("metaData").value(metadata) - - writer.name("severity").value(severity) - writer.name("severityReason").value(severityReason) - writer.name("unhandled").value(severityReason.unhandled) - - // Write exception info - writer.name("exceptions") - writer.beginArray() - errors.forEach { writer.value(it) } - writer.endArray() - - // Write project packages - writer.name("projectPackages") - writer.beginArray() - projectPackages.forEach { writer.value(it) } - writer.endArray() - - // Write user info - writer.name("user").value(userImpl) - - // Write diagnostics - writer.name("app").value(app) - writer.name("device").value(device) - writer.name("breadcrumbs").value(breadcrumbs) - writer.name("groupingHash").value(groupingHash) - val usage = internalMetrics.toJsonableMap() - if (usage.isNotEmpty()) { - writer.name("usage") - writer.beginObject() - usage.forEach { entry -> - writer.name(entry.key).value(entry.value) - } - writer.endObject() - } - - writer.name("threads") - writer.beginArray() - threads.forEach { writer.value(it) } - writer.endArray() - - writer.name("featureFlags").value(featureFlags) - - if (session != null) { - val copy = Session.copySession(session) - writer.name("session").beginObject() - writer.name("id").value(copy.id) - writer.name("startedAt").value(copy.startedAt) - writer.name("events").beginObject() - writer.name("handled").value(copy.handledCount.toLong()) - writer.name("unhandled").value(copy.unhandledCount.toLong()) - writer.endObject() - writer.endObject() - } - - writer.endObject() - } - - internal fun getErrorTypesFromStackframes(): Set { - val errorTypes = errors.mapNotNull(Error::getType).toSet() - val frameOverrideTypes = errors - .map { it.stacktrace } - .flatMap { it.mapNotNull(Stackframe::type) } - return errorTypes.plus(frameOverrideTypes) - } - - internal fun normalizeStackframeErrorTypes() { - if (getErrorTypesFromStackframes().size == 1) { - errors.flatMap { it.stacktrace }.forEach { - it.type = null - } - } - } - - internal fun updateSeverityReasonInternal(severityReason: SeverityReason) { - this.severityReason = severityReason - } - - protected fun updateSeverityInternal(severity: Severity) { - severityReason = SeverityReason( - severityReason.severityReasonType, - severity, - severityReason.unhandled, - severityReason.unhandledOverridden, - severityReason.attributeValue, - severityReason.attributeKey - ) - } - - protected fun updateSeverityReason(@SeverityReason.SeverityReasonType reason: String) { - severityReason = SeverityReason( - reason, - severityReason.currentSeverity, - severityReason.unhandled, - severityReason.unhandledOverridden, - severityReason.attributeValue, - severityReason.attributeKey - ) - } - - fun getSeverityReasonType(): String = severityReason.severityReasonType - - fun trimMetadataStringsTo(maxLength: Int): TrimMetrics { - var stringCount = 0 - var charCount = 0 - - var stringAndCharCounts = metadata.trimMetadataStringsTo(maxLength) - stringCount += stringAndCharCounts.itemsTrimmed - charCount += stringAndCharCounts.dataTrimmed - for (breadcrumb in breadcrumbs) { - stringAndCharCounts = breadcrumb.impl.trimMetadataStringsTo(maxLength) - stringCount += stringAndCharCounts.itemsTrimmed - charCount += stringAndCharCounts.dataTrimmed - } - return TrimMetrics(stringCount, charCount) - } - - fun trimBreadcrumbsBy(byteCount: Int): TrimMetrics { - var removedBreadcrumbCount = 0 - var removedByteCount = 0 - while (removedByteCount < byteCount && breadcrumbs.isNotEmpty()) { - val breadcrumb = breadcrumbs.removeAt(0) - removedByteCount += JsonHelper.serialize(breadcrumb).size - removedBreadcrumbCount++ - } - when (removedBreadcrumbCount) { - 1 -> breadcrumbs.add(Breadcrumb("Removed to reduce payload size", logger)) - else -> breadcrumbs.add( - Breadcrumb( - "Removed, along with ${removedBreadcrumbCount - 1} older breadcrumbs, to reduce payload size", - logger - ) - ) - } - return TrimMetrics(removedBreadcrumbCount, removedByteCount) - } - - override fun setUser(id: String?, email: String?, name: String?) { - userImpl = User(id, email, name) - } - - override fun getUser() = userImpl - - override fun addMetadata(section: String, value: Map) = - metadata.addMetadata(section, value) - - override fun addMetadata(section: String, key: String, value: Any?) = - metadata.addMetadata(section, key, value) - - override fun clearMetadata(section: String) = metadata.clearMetadata(section) - - override fun clearMetadata(section: String, key: String) = metadata.clearMetadata(section, key) - - override fun getMetadata(section: String) = metadata.getMetadata(section) - - override fun getMetadata(section: String, key: String) = metadata.getMetadata(section, key) - - override fun addFeatureFlag(name: String) = featureFlags.addFeatureFlag(name) - - override fun addFeatureFlag(name: String, variant: String?) = - featureFlags.addFeatureFlag(name, variant) - - override fun addFeatureFlags(featureFlags: Iterable) = - this.featureFlags.addFeatureFlags(featureFlags) - - override fun clearFeatureFlag(name: String) = featureFlags.clearFeatureFlag(name) - - override fun clearFeatureFlags() = featureFlags.clearFeatureFlags() -} +// package com.bugsnag.android +// +// import com.bugsnag.android.internal.ImmutableConfig +// import com.bugsnag.android.internal.InternalMetrics +// import com.bugsnag.android.internal.InternalMetricsNoop +// import com.bugsnag.android.internal.JsonHelper +// import com.bugsnag.android.internal.TrimMetrics +// import java.io.IOException +// import java.util.regex.Pattern +// +// class EventInternal : FeatureFlagAware, JsonStream.Streamable, MetadataAware, UserAware { +// +// @JvmOverloads +// internal constructor( +// originalError: Throwable? = null, +// config: ImmutableConfig, +// severityReason: SeverityReason, +// data: Metadata = Metadata(), +// featureFlags: FeatureFlags = FeatureFlags() +// ) : this( +// config.apiKey, +// config.logger, +// mutableListOf(), +// config.discardClasses.toSet(), +// when (originalError) { +// null -> mutableListOf() +// else -> Error.createError(originalError, config.projectPackages, config.logger) +// }, +// data.copy(), +// featureFlags.copy(), +// originalError, +// config.projectPackages, +// severityReason, +// ThreadState(originalError, severityReason.unhandled, config).threads, +// User(), +// config.redactedKeys.toSet() +// ) +// +// internal constructor( +// apiKey: String, +// logger: Logger, +// breadcrumbs: MutableList = mutableListOf(), +// discardClasses: Set = setOf(), +// errors: MutableList = mutableListOf(), +// metadata: Metadata = Metadata(), +// featureFlags: FeatureFlags = FeatureFlags(), +// originalError: Throwable? = null, +// projectPackages: Collection = setOf(), +// severityReason: SeverityReason = SeverityReason.newInstance(SeverityReason.REASON_HANDLED_EXCEPTION), +// threads: MutableList = mutableListOf(), +// user: User = User(), +// redactionKeys: Set? = null +// ) { +// this.logger = logger +// this.apiKey = apiKey +// this.breadcrumbs = breadcrumbs +// this.discardClasses = discardClasses +// this.errors = errors +// this.metadata = metadata +// this.featureFlags = featureFlags +// this.originalError = originalError +// this.projectPackages = projectPackages +// this.severityReason = severityReason +// this.threads = threads +// this.userImpl = user +// +// redactionKeys?.let { +// this.redactedKeys = it +// } +// } +// +// val originalError: Throwable? +// internal var severityReason: SeverityReason +// +// val logger: Logger +// internal val metadata: Metadata +// internal val featureFlags: FeatureFlags +// private val discardClasses: Set +// internal var projectPackages: Collection +// +// private val jsonStreamer: ObjectJsonStreamer = ObjectJsonStreamer().apply { +// redactedKeys = redactedKeys.toSet() +// } +// +// @JvmField +// internal var session: Session? = null +// +// var severity: Severity +// get() = severityReason.currentSeverity +// set(value) { +// severityReason.currentSeverity = value +// } +// +// var apiKey: String +// lateinit var app: AppWithState +// lateinit var device: DeviceWithState +// var unhandled: Boolean +// get() = severityReason.unhandled +// set(value) { +// severityReason.unhandled = value +// } +// +// var breadcrumbs: MutableList +// var errors: MutableList +// var threads: MutableList +// var groupingHash: String? = null +// var context: String? = null +// +// var redactedKeys: Collection +// get() = jsonStreamer.redactedKeys +// set(value) { +// jsonStreamer.redactedKeys = value.toSet() +// metadata.redactedKeys = value.toSet() +// } +// var internalMetrics: InternalMetrics = InternalMetricsNoop() +// +// /** +// * @return user information associated with this Event +// */ +// internal var userImpl: User +// +// fun getUnhandledOverridden(): Boolean = severityReason.unhandledOverridden +// +// fun getOriginalUnhandled(): Boolean = severityReason.originalUnhandled +// +// public fun shouldDiscardClass(): Boolean { +// return when { +// errors.isEmpty() -> true +// else -> errors.any { error -> +// discardClasses.any { pattern -> +// pattern.matcher(error.errorClass).matches() +// } +// } +// } +// } +// +// protected fun isAnr(event: Event): Boolean { +// val errors = event.errors +// var errorClass: String? = null +// if (errors.isNotEmpty()) { +// val error = errors[0] +// errorClass = error.errorClass +// } +// return "ANR" == errorClass +// } +// +// @Throws(IOException::class) +// override fun toStream(parentWriter: JsonStream) { +// val writer = JsonStream(parentWriter, jsonStreamer) +// // Write error basics +// writer.beginObject() +// writer.name("context").value(context) +// writer.name("metaData").value(metadata) +// +// writer.name("severity").value(severity) +// writer.name("severityReason").value(severityReason) +// writer.name("unhandled").value(severityReason.unhandled) +// +// // Write exception info +// writer.name("exceptions") +// writer.beginArray() +// errors.forEach { writer.value(it) } +// writer.endArray() +// +// // Write project packages +// writer.name("projectPackages") +// writer.beginArray() +// projectPackages.forEach { writer.value(it) } +// writer.endArray() +// +// // Write user info +// writer.name("user").value(userImpl) +// +// // Write diagnostics +// writer.name("app").value(app) +// writer.name("device").value(device) +// writer.name("breadcrumbs").value(breadcrumbs) +// writer.name("groupingHash").value(groupingHash) +// val usage = internalMetrics.toJsonableMap() +// if (usage.isNotEmpty()) { +// writer.name("usage") +// writer.beginObject() +// usage.forEach { entry -> +// writer.name(entry.key).value(entry.value) +// } +// writer.endObject() +// } +// +// writer.name("threads") +// writer.beginArray() +// threads.forEach { writer.value(it) } +// writer.endArray() +// +// writer.name("featureFlags").value(featureFlags) +// +// if (session != null) { +// val copy = Session.copySession(session) +// writer.name("session").beginObject() +// writer.name("id").value(copy.id) +// writer.name("startedAt").value(copy.startedAt) +// writer.name("events").beginObject() +// writer.name("handled").value(copy.handledCount.toLong()) +// writer.name("unhandled").value(copy.unhandledCount.toLong()) +// writer.endObject() +// writer.endObject() +// } +// +// writer.endObject() +// } +// +// internal fun getErrorTypesFromStackframes(): Set { +// val errorTypes = errors.mapNotNull(Error::getType).toSet() +// val frameOverrideTypes = errors +// .map { it.stacktrace } +// .flatMap { it.mapNotNull(Stackframe::type) } +// return errorTypes.plus(frameOverrideTypes) +// } +// +// internal fun normalizeStackframeErrorTypes() { +// if (getErrorTypesFromStackframes().size == 1) { +// errors.flatMap { it.stacktrace }.forEach { +// it.type = null +// } +// } +// } +// +// internal fun updateSeverityReasonInternal(severityReason: SeverityReason) { +// this.severityReason = severityReason +// } +// +// public fun updateSeverityInternal(severity: Severity) { +// severityReason = SeverityReason( +// severityReason.severityReasonType, +// severity, +// severityReason.unhandled, +// severityReason.unhandledOverridden, +// severityReason.attributeValue, +// severityReason.attributeKey +// ) +// } +// +// public fun updateSeverityReason(@SeverityReason.SeverityReasonType reason: String) { +// severityReason = SeverityReason( +// reason, +// severityReason.currentSeverity, +// severityReason.unhandled, +// severityReason.unhandledOverridden, +// severityReason.attributeValue, +// severityReason.attributeKey +// ) +// } +// +// fun getSeverityReasonType(): String = severityReason.severityReasonType +// +// internal fun trimMetadataStringsTo(maxLength: Int): TrimMetrics { +// var stringCount = 0 +// var charCount = 0 +// +// var stringAndCharCounts = metadata.trimMetadataStringsTo(maxLength) +// stringCount += stringAndCharCounts.itemsTrimmed +// charCount += stringAndCharCounts.dataTrimmed +// for (breadcrumb in breadcrumbs) { +// stringAndCharCounts = breadcrumb.impl.trimMetadataStringsTo(maxLength) +// stringCount += stringAndCharCounts.itemsTrimmed +// charCount += stringAndCharCounts.dataTrimmed +// } +// return TrimMetrics(stringCount, charCount) +// } +// +// internal fun trimBreadcrumbsBy(byteCount: Int): TrimMetrics { +// var removedBreadcrumbCount = 0 +// var removedByteCount = 0 +// while (removedByteCount < byteCount && breadcrumbs.isNotEmpty()) { +// val breadcrumb = breadcrumbs.removeAt(0) +// removedByteCount += JsonHelper.serialize(breadcrumb).size +// removedBreadcrumbCount++ +// } +// when (removedBreadcrumbCount) { +// 1 -> breadcrumbs.add(Breadcrumb("Removed to reduce payload size", logger)) +// else -> breadcrumbs.add( +// Breadcrumb( +// "Removed, along with ${removedBreadcrumbCount - 1} older breadcrumbs, to reduce payload size", +// logger +// ) +// ) +// } +// return TrimMetrics(removedBreadcrumbCount, removedByteCount) +// } +// +// override fun setUser(id: String?, email: String?, name: String?) { +// userImpl = User(id, email, name) +// } +// +// override fun getUser() = userImpl +// +// override fun addMetadata(section: String, value: Map) = +// metadata.addMetadata(section, value) +// +// override fun addMetadata(section: String, key: String, value: Any?) = +// metadata.addMetadata(section, key, value) +// +// override fun clearMetadata(section: String) = metadata.clearMetadata(section) +// +// override fun clearMetadata(section: String, key: String) = metadata.clearMetadata(section, key) +// +// override fun getMetadata(section: String) = metadata.getMetadata(section) +// +// override fun getMetadata(section: String, key: String) = metadata.getMetadata(section, key) +// +// override fun addFeatureFlag(name: String) = featureFlags.addFeatureFlag(name) +// +// override fun addFeatureFlag(name: String, variant: String?) = +// featureFlags.addFeatureFlag(name, variant) +// +// override fun addFeatureFlags(featureFlags: Iterable) = +// this.featureFlags.addFeatureFlags(featureFlags) +// +// override fun clearFeatureFlag(name: String) = featureFlags.clearFeatureFlag(name) +// +// override fun clearFeatureFlags() = featureFlags.clearFeatureFlags() +// } diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventPayload.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventPayload.kt index 51f213016d..5b84fda8c1 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/EventPayload.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/EventPayload.kt @@ -28,7 +28,7 @@ class EventPayload @JvmOverloads internal constructor( internal fun getErrorTypes(): Set { val event = this.event return when { - event != null -> event.impl.getErrorTypesFromStackframes() + event != null -> event.getErrorTypesFromStackframes() eventFile != null -> EventFilenameInfo.fromFile(eventFile, config).errorTypes else -> emptySet() } diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/MarshalledEventSource.kt b/bugsnag-android-core/src/main/java/com/bugsnag/android/MarshalledEventSource.kt index cd5fbf69e0..534f337ccd 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/MarshalledEventSource.kt +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/MarshalledEventSource.kt @@ -34,9 +34,6 @@ internal class MarshalledEventSource( private fun unmarshall(): Event { val eventMapper = BugsnagEventMapper(logger) val jsonMap = JsonHelper.deserialize(eventFile) - return Event( - eventMapper.convertToEventImpl(jsonMap, apiKey), - logger - ) + return eventMapper.convertToEventImpl(jsonMap, apiKey) } } diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/NativeInterface.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/NativeInterface.java index 6f622fdf27..dbabe4d213 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/NativeInterface.java +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/NativeInterface.java @@ -54,12 +54,11 @@ private static Event createEmptyEvent() { Client client = getClient(); return new Event( - new EventInternal( - (Throwable) null, - client.getConfig(), - SeverityReason.newInstance(SeverityReason.REASON_HANDLED_EXCEPTION), - client.getMetadataState().getMetadata().copy() - ), + (Throwable) null, + client.getConfig(), + SeverityReason.newInstance(SeverityReason.REASON_HANDLED_EXCEPTION), + client.getMetadataState().getMetadata().copy(), + client.getFeatureFlagState().getFeatureFlags(), client.getLogger() ); } diff --git a/bugsnag-android-core/src/main/java/com/bugsnag/android/SeverityReason.java b/bugsnag-android-core/src/main/java/com/bugsnag/android/SeverityReason.java index e759bd6d59..054d12d873 100644 --- a/bugsnag-android-core/src/main/java/com/bugsnag/android/SeverityReason.java +++ b/bugsnag-android-core/src/main/java/com/bugsnag/android/SeverityReason.java @@ -5,6 +5,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RestrictTo; import androidx.annotation.StringDef; import java.io.IOException; diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventApiTest.kt b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventApiTest.kt index 91e4ba9e4a..a9b1318eb8 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventApiTest.kt +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventApiTest.kt @@ -30,39 +30,39 @@ internal class EventApiTest { @Test fun getUser() { - assertEquals(event.impl.userImpl, event.getUser()) + assertEquals(event.userImpl, event.getUser()) } @Test fun setUser() { event.setUser("99", "boo@example.com", "Boo") - assertEquals(User("99", "boo@example.com", "Boo"), event.impl.userImpl) + assertEquals(User("99", "boo@example.com", "Boo"), event.userImpl) } @Test fun addMetadataTopLevel() { event.addMetadata("foo", mapOf(Pair("wham", "bar"))) - assertEquals(mapOf(Pair("wham", "bar")), event.impl.metadata.getMetadata("foo")) + assertEquals(mapOf(Pair("wham", "bar")), event.metadata.getMetadata("foo")) } @Test fun addMetadata() { event.addMetadata("foo", "wham", "bar") - assertEquals("bar", event.impl.metadata.getMetadata("foo", "wham")) + assertEquals("bar", event.metadata.getMetadata("foo", "wham")) } @Test fun clearMetadataTopLevel() { event.addMetadata("foo", mapOf(Pair("wham", "bar"))) event.clearMetadata("foo") - assertNull(event.impl.metadata.getMetadata("foo")) + assertNull(event.metadata.getMetadata("foo")) } @Test fun clearMetadata() { event.addMetadata("foo", "wham", "bar") event.clearMetadata("foo", "wham") - assertNull(event.impl.metadata.getMetadata("foo", "wham")) + assertNull(event.metadata.getMetadata("foo", "wham")) } @Test @@ -70,7 +70,7 @@ internal class EventApiTest { event.addFeatureFlag("demo_mode") assertEquals( listOf(FeatureFlag("demo_mode")), - event.impl.featureFlags.toList() + event.featureFlags.toList() ) } @@ -79,7 +79,7 @@ internal class EventApiTest { event.addFeatureFlag("sample_group", "a") assertEquals( listOf(FeatureFlag("sample_group", "a")), - event.impl.featureFlags.toList() + event.featureFlags.toList() ) } @@ -90,7 +90,7 @@ internal class EventApiTest { event.clearFeatureFlag("demo_group") assertEquals( listOf(FeatureFlag("sample_group", "a")), - event.impl.featureFlags.toList() + event.featureFlags.toList() ) } @@ -99,6 +99,6 @@ internal class EventApiTest { event.addFeatureFlag("demo_group") event.addFeatureFlag("sample_group", "a") event.clearFeatureFlags() - assertEquals(emptyList(), event.impl.featureFlags.toList()) + assertEquals(emptyList(), event.featureFlags.toList()) } } diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventErrorTypeTest.kt b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventErrorTypeTest.kt index a743f279be..9831aa95bd 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventErrorTypeTest.kt +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventErrorTypeTest.kt @@ -49,7 +49,7 @@ class EventErrorTypeTest { assertEquals(setOf(ANDROID), payload.getErrorTypes()) // confirm single type is stripped from individual stackframes - event.impl.normalizeStackframeErrorTypes() + event.normalizeStackframeErrorTypes() assertEquals(ANDROID, error.type) assertEquals(setOf(ANDROID), payload.getErrorTypes()) error.stacktrace.forEach { assertNull(it.type) } @@ -80,7 +80,7 @@ class EventErrorTypeTest { assertEquals(setOf(ANDROID, C), payload.getErrorTypes()) // confirm single type is stripped from individual stackframes - event.impl.normalizeStackframeErrorTypes() + event.normalizeStackframeErrorTypes() assertEquals(ANDROID, error.type) assertEquals(setOf(ANDROID, C), payload.getErrorTypes()) diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventFeatureFlagsCloneTest.kt b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventFeatureFlagsCloneTest.kt index 1092c45db7..a7834b2d90 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventFeatureFlagsCloneTest.kt +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventFeatureFlagsCloneTest.kt @@ -27,7 +27,7 @@ class EventFeatureFlagsCloneTest { event.addFeatureFlag("demo_mode") // featureFlags objects should be deep copied - assertNotSame(featureFlags, event.impl.featureFlags) + assertNotSame(featureFlags, event.featureFlags) // validate origin featureFlags val origExpected = listOf(FeatureFlag("sample_group", "123")) @@ -38,6 +38,6 @@ class EventFeatureFlagsCloneTest { FeatureFlag("sample_group", "123"), FeatureFlag("demo_mode") ) - assertEquals(eventExpected, event.impl.featureFlags.toList()) + assertEquals(eventExpected, event.featureFlags.toList()) } } diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventMetadataCloneTest.kt b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventMetadataCloneTest.kt index 2dd94a0163..9520541e73 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventMetadataCloneTest.kt +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventMetadataCloneTest.kt @@ -27,7 +27,7 @@ class EventMetadataCloneTest { event.addMetadata("test_section", "second", "another value") // metadata object should be deep copied - assertNotSame(data, event.impl.metadata) + assertNotSame(data, event.metadata) // validate event metadata val origExpected = mapOf(Pair("foo", "bar")) @@ -35,6 +35,6 @@ class EventMetadataCloneTest { // validate event metadata val eventExpected = mapOf(Pair("foo", "bar"), Pair("second", "another value")) - assertEquals(eventExpected, event.impl.metadata.getMetadata("test_section")) + assertEquals(eventExpected, event.metadata.getMetadata("test_section")) } } diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventRedactionTest.kt b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventRedactionTest.kt index 24c41ccf75..b2f9e253b3 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventRedactionTest.kt +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventRedactionTest.kt @@ -41,9 +41,9 @@ internal class EventRedactionTest { event.addMetadata("app", "password", "foo") event.addMetadata("device", "password", "bar") - event.impl.metadata.addMetadata("baz", "password", "hunter2") + event.metadata.addMetadata("baz", "password", "hunter2") val metadata = mutableMapOf(Pair("changeme", "whoops")) - event.breadcrumbs = listOf(Breadcrumb("Whoops", BreadcrumbType.LOG, metadata, Date(0), NoopLogger)) + event.breadcrumbs = mutableListOf(Breadcrumb("Whoops", BreadcrumbType.LOG, metadata, Date(0), NoopLogger)) event.threads.clear() event.device.cpuAbi = emptyArray() diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventSerializationTest.kt b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventSerializationTest.kt index f930fe313c..aaf4c5f146 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventSerializationTest.kt +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventSerializationTest.kt @@ -35,7 +35,8 @@ internal class EventSerializationTest { createEvent { val user = User("123", "foo@example.com", "Joe") val apiKey = "BUGSNAG_API_KEY" - it.session = Session("123", Date(0), user, false, Notifier(), NoopLogger, apiKey) + it.session = + Session("123", Date(0), user, false, Notifier(), NoopLogger, apiKey) }, // threads included @@ -69,7 +70,7 @@ internal class EventSerializationTest { Date(0), NoopLogger ) - it.breadcrumbs = listOf(crumb) + it.breadcrumbs = mutableListOf(crumb) val stacktrace = Stacktrace(arrayOf(), emptySet(), NoopLogger) val err = @@ -113,10 +114,7 @@ internal class EventSerializationTest { @Test fun testJsonDeserializion() { verifyJsonParser(testCase.first, testCase.second) { - Event( - eventMapper.convertToEventImpl(it, "5d1ec5bd39a74caa1267142706a7fb21"), - NoopLogger - ) + eventMapper.convertToEventImpl(it, "5d1ec5bd39a74caa1267142706a7fb21") } } } diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventTest.java b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventTest.java index c7dca05b62..aaa519baae 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/EventTest.java +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/EventTest.java @@ -166,22 +166,22 @@ public void testGetSetErrors() { public void testIsAnr() { RuntimeException exc = new RuntimeException("Something went wrong"); Event event = new Event(exc, config, severityReason, NoopLogger.INSTANCE); - assertFalse(event.getImpl().isAnr(event)); + assertFalse(event.isAnr(event)); // simulate ANR event.getErrors().get(0).setErrorClass("ANR"); - assertTrue(event.getImpl().isAnr(event)); + assertTrue(event.isAnr(event)); // clear all errors event.getErrors().clear(); - assertFalse(event.getImpl().isAnr(event)); + assertFalse(event.isAnr(event)); } @Test public void testSeverityReasonType() { RuntimeException exc = new RuntimeException("Something went wrong"); Event event = new Event(exc, config, severityReason, NoopLogger.INSTANCE); - String severityReasonType = event.getImpl().getSeverityReasonType(); + String severityReasonType = event.getSeverityReasonType(); assertEquals(SeverityReason.REASON_HANDLED_EXCEPTION, severityReasonType); } @@ -190,13 +190,13 @@ public void testSeverityReasonInternalOverload() { RuntimeException exc = new RuntimeException("Something went wrong"); Event event = new Event(exc, config, severityReason, NoopLogger.INSTANCE); - String severityReasonType = event.getImpl().getSeverityReasonType(); + String severityReasonType = event.getSeverityReasonType(); assertEquals(SeverityReason.REASON_HANDLED_EXCEPTION, severityReasonType); assertEquals(Severity.WARNING, event.getSeverity()); event.updateSeverityInternal(Severity.INFO); event.updateSeverityReason(SeverityReason.REASON_STRICT_MODE); - severityReasonType = event.getImpl().getSeverityReasonType(); + severityReasonType = event.getSeverityReasonType(); assertEquals(SeverityReason.REASON_STRICT_MODE, severityReasonType); assertEquals(Severity.INFO, event.getSeverity()); } diff --git a/bugsnag-android-core/src/test/java/com/bugsnag/android/NativeInterfaceApiTest.kt b/bugsnag-android-core/src/test/java/com/bugsnag/android/NativeInterfaceApiTest.kt index dce80a6b79..befae79cdb 100644 --- a/bugsnag-android-core/src/test/java/com/bugsnag/android/NativeInterfaceApiTest.kt +++ b/bugsnag-android-core/src/test/java/com/bugsnag/android/NativeInterfaceApiTest.kt @@ -76,6 +76,7 @@ internal class NativeInterfaceApiTest { `when`(client.getDeviceDataCollector()).thenReturn(deviceDataCollector) `when`(client.getUser()).thenReturn(User("123", "tod@example.com", "Tod")) `when`(client.getMetadataState()).thenReturn(MetadataState()) + `when`(client.getFeatureFlagState()).thenReturn(FeatureFlagState()) } @Test diff --git a/bugsnag-plugin-android-exitinfo/src/test/java/com/bugsnag/android/TombstoneEventEnhancerTest.kt b/bugsnag-plugin-android-exitinfo/src/test/java/com/bugsnag/android/TombstoneEventEnhancerTest.kt index b2507c3b88..95bf46bb41 100644 --- a/bugsnag-plugin-android-exitinfo/src/test/java/com/bugsnag/android/TombstoneEventEnhancerTest.kt +++ b/bugsnag-plugin-android-exitinfo/src/test/java/com/bugsnag/android/TombstoneEventEnhancerTest.kt @@ -26,7 +26,7 @@ internal class TombstoneEventEnhancerTest { val event = Event( RuntimeException("error"), mock(ImmutableConfig::class.java), - SeverityReason.newInstance(SeverityReason.REASON_SIGNAL), + SeverityReason.REASON_SIGNAL, logger ) val oldThread = BugsnagThread( diff --git a/bugsnag-plugin-android-exitinfo/src/test/java/com/bugsnag/android/TraceEventEnhancerTest.kt b/bugsnag-plugin-android-exitinfo/src/test/java/com/bugsnag/android/TraceEventEnhancerTest.kt index 176d093775..4fbda69380 100644 --- a/bugsnag-plugin-android-exitinfo/src/test/java/com/bugsnag/android/TraceEventEnhancerTest.kt +++ b/bugsnag-plugin-android-exitinfo/src/test/java/com/bugsnag/android/TraceEventEnhancerTest.kt @@ -17,7 +17,7 @@ class TraceEventEnhancerTest { val event = Event( RuntimeException("error"), mock(ImmutableConfig::class.java), - SeverityReason.newInstance(SeverityReason.REASON_ANR), + SeverityReason.REASON_ANR, mockLogger ) diff --git a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/TestHooks.java b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/TestHooks.java index e9b628b612..e29d697aa1 100644 --- a/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/TestHooks.java +++ b/bugsnag-plugin-react-native/src/test/java/com/bugsnag/android/TestHooks.java @@ -2,7 +2,7 @@ class TestHooks { static boolean getUnhandledOverridden(Event event) { - return event.getImpl().getUnhandledOverridden(); + return event.getUnhandledOverridden(); } static MetadataState generateMetadataState() {