Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions OneSignalSDK/onesignal/location/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,5 @@ dependencies {
testImplementation("io.mockk:mockk:1.13.2")
testImplementation("org.json:json:20180813")
testImplementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
testImplementation("com.google.android.gms:play-services-location:18.0.0")
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ internal interface ILocationPermissionChangedHandler {
}

internal class LocationPermissionController(
private val _application: IApplicationService,
private val _requestPermission: IRequestPermissionService,
private val _applicationService: IApplicationService
) : IRequestPermissionService.PermissionCallback,
Expand Down Expand Up @@ -95,7 +94,7 @@ internal class LocationPermissionController(
}

private fun showFallbackAlertDialog(): Boolean {
val activity = _application.current ?: return false
val activity = _applicationService.current ?: return false
AlertDialogPrepromptForAndroidSettings.show(
activity,
activity.getString(R.string.location_permission_name_for_title),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Code taken from https://github.com/kotest/kotest-extensions-robolectric with no changes.
*
* LICENSE: https://github.com/kotest/kotest-extensions-robolectric/blob/master/LICENSE
*/
package com.onesignal.notifications.extensions

import org.junit.runners.model.FrameworkMethod
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.internal.bytecode.InstrumentationConfiguration
import org.robolectric.pluginapi.config.ConfigurationStrategy
import org.robolectric.plugins.ConfigConfigurer
import java.lang.reflect.Method

internal class ContainedRobolectricRunner(
private val config: Config?
) : RobolectricTestRunner(PlaceholderTest::class.java, injector) {
private val placeHolderMethod: FrameworkMethod = children[0]
val sdkEnvironment = getSandbox(placeHolderMethod).also {
configureSandbox(it, placeHolderMethod)
}
private val bootStrapMethod = sdkEnvironment.bootstrappedClass<Any>(testClass.javaClass)
.getMethod(PlaceholderTest::bootStrapMethod.name)

fun containedBefore() {
Thread.currentThread().contextClassLoader = sdkEnvironment.robolectricClassLoader
super.beforeTest(sdkEnvironment, placeHolderMethod, bootStrapMethod)
}

fun containedAfter() {
super.afterTest(placeHolderMethod, bootStrapMethod)
super.finallyAfterTest(placeHolderMethod)
Thread.currentThread().contextClassLoader = ContainedRobolectricRunner::class.java.classLoader
}

override fun createClassLoaderConfig(method: FrameworkMethod?): InstrumentationConfiguration {
return InstrumentationConfiguration.Builder(super.createClassLoaderConfig(method))
.doNotAcquirePackage("io.kotest")
.build()
}

override fun getConfig(method: Method?): Config {
val defaultConfiguration = injector.getInstance(ConfigurationStrategy::class.java)
.getConfig(testClass.javaClass, method)

if (config != null) {
val configConfigurer = injector.getInstance(ConfigConfigurer::class.java)
return configConfigurer.merge(defaultConfiguration[Config::class.java], config)
}

return super.getConfig(method)
}

class PlaceholderTest {
@org.junit.Test
fun testPlaceholder() {
}

fun bootStrapMethod() {
}
}

companion object {
private val injector = defaultInjector().build()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* Code taken from https://github.com/kotest/kotest-extensions-robolectric with a
* fix in the intercept method.
*
* LICENSE: https://github.com/kotest/kotest-extensions-robolectric/blob/master/LICENSE
*/
package com.onesignal.notifications.extensions

import android.app.Application
import io.kotest.core.extensions.ConstructorExtension
import io.kotest.core.extensions.TestCaseExtension
import io.kotest.core.spec.AutoScan
import io.kotest.core.spec.Spec
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import org.robolectric.annotation.Config
import kotlin.reflect.KClass
import kotlin.reflect.full.findAnnotation

/**
* We override TestCaseExtension to configure the Robolectric environment because TestCase intercept
* occurs on the same thread the test is run. This is unfortunate because it is run for every test,
* rather than every spec. But the SpecExtension intercept is run on a different thread.
*/
@AutoScan
internal class RobolectricExtension : ConstructorExtension, TestCaseExtension {
private fun Class<*>.getParentClass(): List<Class<*>> {
if (superclass == null) return listOf()
return listOf(superclass) + superclass.getParentClass()
}

private fun KClass<*>.getConfig(): Config {
val configAnnotations = listOf(this.java).plus(this.java.getParentClass())
.mapNotNull { it.kotlin.findAnnotation<Config>() }
.asSequence()

val configAnnotation = configAnnotations.firstOrNull()

if (configAnnotation != null) {
return Config.Builder(configAnnotation).build()
}

val robolectricTestAnnotations = listOf(this.java).plus(this.java.getParentClass())
.mapNotNull { it.kotlin.findAnnotation<RobolectricTest>() }
.asSequence()

val application: KClass<out Application>? = robolectricTestAnnotations
.firstOrNull { it.application != KotestDefaultApplication::class }?.application
val sdk: Int? = robolectricTestAnnotations.firstOrNull { it.sdk != -1 }?.takeUnless { it.sdk == -1 }?.sdk

return Config.Builder()
.also { builder ->
if (application != null) {
builder.setApplication(application.java)
}

if (sdk != null) {
builder.setSdk(sdk)
}
}.build()
}

override fun <T : Spec> instantiate(clazz: KClass<T>): Spec? {
clazz.findAnnotation<RobolectricTest>() ?: return null

return ContainedRobolectricRunner(clazz.getConfig())
.sdkEnvironment.bootstrappedClass<Spec>(clazz.java).newInstance()
}

override suspend fun intercept(
testCase: TestCase,
execute: suspend (TestCase) -> TestResult
): TestResult {
// FIXED: Updated code based on https://github.com/kotest/kotest/issues/2717
val hasRobolectricAnnotation = testCase.spec::class.annotations.any { annotation ->
annotation.annotationClass.qualifiedName == RobolectricTest::class.qualifiedName
}

if (!hasRobolectricAnnotation) {
return execute(testCase)
}

val containedRobolectricRunner = ContainedRobolectricRunner(testCase.spec::class.getConfig())
containedRobolectricRunner.containedBefore()
val result = execute(testCase)
containedRobolectricRunner.containedAfter()
return result
}
}

internal class KotestDefaultApplication : Application()

annotation class RobolectricTest(
val application: KClass<out Application> = KotestDefaultApplication::class,
val sdk: Int = -1
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.onesignal.location.internal.background

import android.Manifest
import android.app.Application
import androidx.test.core.app.ApplicationProvider
import com.onesignal.debug.LogLevel
import com.onesignal.debug.internal.logging.Logging
import com.onesignal.location.ILocationManager
import com.onesignal.location.internal.capture.ILocationCapturer
import com.onesignal.location.internal.common.LocationConstants
import com.onesignal.location.internal.preferences.ILocationPreferencesService
import com.onesignal.mocks.AndroidMockHelper
import com.onesignal.mocks.MockHelper
import com.onesignal.notifications.extensions.RobolectricTest
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.runner.junit4.KotestTestRunner
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.runs
import io.mockk.verify
import org.junit.runner.RunWith
import org.robolectric.Shadows

@RobolectricTest
@RunWith(KotestTestRunner::class)
class LocationBackgroundServiceTests : FunSpec({
beforeAny {
Logging.logLevel = LogLevel.NONE
}

test("backgroundRun will capture current location") {
/* Given */
val mockLocationManager = mockk<ILocationManager>()
val mockLocationPreferencesService = mockk<ILocationPreferencesService>()
val mockLocationCapturer = mockk<ILocationCapturer>()
every { mockLocationCapturer.captureLastLocation() } just runs

val locationBackgroundService = LocationBackgroundService(
AndroidMockHelper.applicationService(),
mockLocationManager,
mockLocationPreferencesService,
mockLocationCapturer,
MockHelper.time(1111)
)

/* When */
locationBackgroundService.backgroundRun()

/* Then */
verify(exactly = 1) { mockLocationCapturer.captureLastLocation() }
}

test("scheduleBackgroundRunIn will return null when location services are disabled in SDK") {
/* Given */
val mockLocationManager = mockk<ILocationManager>()
every { mockLocationManager.isLocationShared } returns false

val mockLocationPreferencesService = mockk<ILocationPreferencesService>()
val mockLocationCapturer = mockk<ILocationCapturer>()

val locationBackgroundService = LocationBackgroundService(
AndroidMockHelper.applicationService(),
mockLocationManager,
mockLocationPreferencesService,
mockLocationCapturer,
MockHelper.time(1111)
)

/* When */
val result = locationBackgroundService.scheduleBackgroundRunIn

/* Then */
result shouldBe null
verify(exactly = 1) { mockLocationManager.isLocationShared }
}

test("scheduleBackgroundRunIn will return null when no android permissions") {
/* Given */
val mockLocationManager = mockk<ILocationManager>()
every { mockLocationManager.isLocationShared } returns true

val mockLocationPreferencesService = mockk<ILocationPreferencesService>()
every { mockLocationPreferencesService.lastLocationTime } returns 1111

val mockLocationCapturer = mockk<ILocationCapturer>()

val application: Application = ApplicationProvider.getApplicationContext()
val app = Shadows.shadowOf(application)
app.grantPermissions(Manifest.permission.ACCESS_FINE_LOCATION)

val locationBackgroundService = LocationBackgroundService(
AndroidMockHelper.applicationService(),
mockLocationManager,
mockLocationPreferencesService,
mockLocationCapturer,
MockHelper.time(2222)
)

/* When */
val result = locationBackgroundService.scheduleBackgroundRunIn

/* Then */
result shouldBe (1000 * LocationConstants.TIME_BACKGROUND_SEC) - (2222 - 1111)
}
})
Loading