Add controlled host fixtures for Android network listeners
This commit is contained in:
1 parent
799a71d361
commit
8a22afc42d
3 files changed
+62
-5
No files matched your search
@@ -1,14 +1,21 @@
|
||||
package android.content
|
||||
|
||||
import android.media.AudioManager
|
||||
import android.net.ConnectivityManager
|
||||
|
||||
/** Только host-тест: один управляемый AudioManager, без устройств/разрешений ОС. */
|
||||
/** Только host-тест: управляемые AudioManager/ConnectivityManager, без устройств/разрешений ОС. */
|
||||
class Context {
|
||||
companion object { const val AUDIO_SERVICE = "audio" }
|
||||
var permissionGranted = true
|
||||
var connectivityManager: ConnectivityManager? = ConnectivityManager()
|
||||
val applicationContext: Context get() = this
|
||||
fun getSystemService(name: String): Any {
|
||||
check(name == AUDIO_SERVICE)
|
||||
return AudioManager.shared
|
||||
}
|
||||
fun <T> getSystemService(type: Class<T>): T? {
|
||||
check(type == ConnectivityManager::class.java)
|
||||
return type.cast(connectivityManager)
|
||||
}
|
||||
fun checkSelfPermission(name: String): Int = if (permissionGranted) 0 else -1
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package android.net
|
||||
|
||||
/** Только host-тест: listener принадлежит конкретному manager; старые callbacks тест может доставить после удаления. */
|
||||
class ConnectivityManager {
|
||||
fun interface OnNetworkActiveListener { fun onNetworkActive() }
|
||||
val listeners = mutableListOf<OnNetworkActiveListener>()
|
||||
val history = mutableListOf<OnNetworkActiveListener>()
|
||||
var addAttempts = 0
|
||||
var removeAttempts = 0
|
||||
var failAdd = false
|
||||
var failRemove = false
|
||||
var failQuery = false
|
||||
var active = false
|
||||
|
||||
fun addDefaultNetworkActiveListener(listener: OnNetworkActiveListener) {
|
||||
addAttempts++
|
||||
if (failAdd) throw SecurityException("network listener registration denied")
|
||||
check(listener !in listeners)
|
||||
listeners.add(listener)
|
||||
history.add(listener)
|
||||
}
|
||||
|
||||
fun removeDefaultNetworkActiveListener(listener: OnNetworkActiveListener) {
|
||||
removeAttempts++
|
||||
if (failRemove) throw IllegalStateException("network listener removal failed")
|
||||
check(listeners.remove(listener)) { "listener belongs to another manager or was already removed" }
|
||||
}
|
||||
|
||||
val isDefaultNetworkActive: Boolean get() {
|
||||
if (failQuery) throw IllegalStateException("network activity query failed")
|
||||
return active
|
||||
}
|
||||
|
||||
fun deliver(index: Int) { history[index].onNetworkActive() }
|
||||
}
|
||||
@@ -1,7 +1,22 @@
|
||||
package android.os
|
||||
|
||||
/** Host-модель API36; callbacks доставляет тест явно, все времена монотонные. */
|
||||
object Build { object VERSION { const val SDK_INT = 36 }; object VERSION_CODES { const val S = 31 } }
|
||||
class Looper { companion object { fun getMainLooper() = Looper() } }
|
||||
class Handler(val looper: Looper)
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
/** Host-модель SDK/главной очереди: callbacks и их доставку тест контролирует явно, без настоящего Android Looper. */
|
||||
object Build { object VERSION { var SDK_INT = 36 }; object VERSION_CODES { const val P = 28; const val S = 31 } }
|
||||
class Looper private constructor() {
|
||||
private val tasks = ConcurrentLinkedQueue<Runnable>()
|
||||
internal fun post(task: Runnable): Boolean { tasks.add(task); return true }
|
||||
fun dispatchAll() {
|
||||
check(myLooper() === this)
|
||||
while (true) (tasks.poll() ?: return).run()
|
||||
}
|
||||
companion object {
|
||||
private val main = Looper()
|
||||
private val owner = Thread.currentThread()
|
||||
fun getMainLooper() = main
|
||||
fun myLooper(): Looper? = if (Thread.currentThread() === owner) main else null
|
||||
}
|
||||
}
|
||||
class Handler(val looper: Looper) { fun post(task: Runnable): Boolean = looper.post(task) }
|
||||
object SystemClock { fun elapsedRealtime(): Long = System.nanoTime() / 1_000_000 }
|
||||
Reference in new issue
Block a user