Skip to content
Snippets Groups Projects
Select Git revision
  • b62c52d0b04a0425a3e269815f1e1686e3ccf606
  • main default protected
  • libquassel-migration
  • wip
  • ChenZhangg-Modify_GRADLE_1
  • jetpack-compose-rewrite
  • demo-jump-in-history
  • attachments
  • 1.7.0 protected
  • 1.6.2 protected
  • 1.6.1 protected
  • 1.6.0 protected
  • 1.5.3 protected
  • 1.5.2 protected
  • 1.5.1 protected
  • 1.5.0 protected
  • 1.4.4 protected
  • 1.4.3 protected
  • 1.4.2 protected
  • 1.4.1 protected
  • 1.4.0 protected
  • v1.3.3 protected
  • v1.3.2 protected
  • v1.3.1 protected
  • v1.3.0 protected
  • v1.2.28 protected
  • v1.2.27 protected
  • v1.2.26 protected
28 results

TestSession.kt

Blame
  • TestSession.kt 11.73 KiB
    /*
     * Quasseldroid - Quassel client for Android
     *
     * Copyright (c) 2019 Janne Koschinski
     * Copyright (c) 2019 The Quassel Project
     *
     * This program is free software: you can redistribute it and/or modify it
     * under the terms of the GNU General Public License version 3 as published
     * by the Free Software Foundation.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License along
     * with this program. If not, see <http://www.gnu.org/licenses/>.
     */
    
    package de.kuschku.libquassel.util
    
    import de.kuschku.libquassel.connection.ConnectionState
    import de.kuschku.libquassel.connection.Features
    import de.kuschku.libquassel.protocol.*
    import de.kuschku.libquassel.protocol.message.HandshakeMessage
    import de.kuschku.libquassel.protocol.message.SignalProxyMessage
    import de.kuschku.libquassel.quassel.BufferInfo
    import de.kuschku.libquassel.quassel.syncables.*
    import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager
    import de.kuschku.libquassel.quassel.syncables.interfaces.ISyncableObject
    import de.kuschku.libquassel.session.Error
    import de.kuschku.libquassel.session.ISession
    import de.kuschku.libquassel.session.ObjectStorage
    import de.kuschku.libquassel.session.ProtocolHandler
    import io.reactivex.Observable
    import io.reactivex.subjects.BehaviorSubject
    import io.reactivex.subjects.PublishSubject
    import org.junit.Assert.assertTrue
    import javax.net.ssl.SSLSession
    
    class TestSession : ProtocolHandler({ throw it }), ISession {
      private val submissionCallbacks = mutableListOf<SubmissionCallback>()
    
      interface SubmissionCallback {
        fun callSubmitted(message: SignalProxyMessage)
      }
    
      class EnsuranceEnvironment(submittedCalls: List<SignalProxyMessage>) {
        private val sync = submittedCalls.mapNotNull { it as? SignalProxyMessage.SyncMessage }
        private val rpc = submittedCalls.mapNotNull { it as? SignalProxyMessage.RpcCall }
        private val initRequest = submittedCalls.mapNotNull { it as? SignalProxyMessage.InitRequest }
        private val initData = submittedCalls.mapNotNull { it as? SignalProxyMessage.InitData }
        private val heartbeat = submittedCalls.mapNotNull { it as? SignalProxyMessage.HeartBeat }
        private val heartbeatReply = submittedCalls.mapNotNull { it as? SignalProxyMessage.HeartBeatReply }
    
        fun callSync(target: ISyncableObject, slotName: String, params: QVariantList?) {
          val matchingTargetTypes = sync.filter {
            it.className == target.className
          }
          assertTrue(
            "SYNC No calls were made on objects of type ${target.className}",
            matchingTargetTypes.isNotEmpty()
          )
          val matchingTargets = matchingTargetTypes.filter {
            it.objectName == target.objectName
          }
          assertTrue(
            if (matchingTargetTypes.isNotEmpty()) {
              "SYNC No calls were made on ${target.className}:${target.objectName}, instead only on:\n  ${matchingTargetTypes.map { "${it.className}:${it.objectName}" }.joinToString(
                "\n  ")}"
            } else {
              "SYNC No calls were made on ${target.className}:${target.objectName}"
            },
            matchingTargets.isNotEmpty()
          )
    
          val matchingNames = matchingTargets.filter {
            it.slotName == slotName
          }
          assertTrue(
            "SYNC ${target.className}:${target.objectName}:$slotName() was never called",
            matchingNames.isNotEmpty()
          )
          if (!params.isNullOrEmpty()) {
            val calledParams = matchingNames.map(SignalProxyMessage.SyncMessage::params)
            assertTrue(
              "SYNC ${target.className}:${target.objectName}:$slotName was called with the wrong parameters:\nExpected:\n  $params\nActual:\n  ${calledParams.joinToString(
                "\n  ")}",
              calledParams.contains(params)
            )
          }
        }
    
        fun callRpc(slotName: String, params: QVariantList?) {
          val matchingNames = rpc.filter {
            it.slotName == slotName
          }
          assertTrue(
            "RPC $slotName() was not called",
            matchingNames.isNotEmpty()
          )
          if (!params.isNullOrEmpty()) {
            val calledParams = matchingNames.map(SignalProxyMessage.RpcCall::params)
            assertTrue(
              "RPC $slotName was called with the wrong parameters:\nExpected:\n  $params\nActual:\n  ${calledParams.joinToString(
                "\n  ")}",
              calledParams.contains(params)
            )
          }
        }
    
        fun requestInit(className: String, objectName: String) {
          val matchingType = initRequest.filter {
            it.className == className
          }
          assertTrue(
            "InitRequest No data was requested for objects of type $className",
            matchingType.isNotEmpty()
          )
          val matchingCalls = matchingType.filter {
            it.objectName == objectName
          }
          assertTrue(
            "InitRequest No data was requested for object $className:$objectName, instead only for:\n  ${matchingType.map { "${it.className}:${it.objectName}" }.joinToString(
              "\n  ")}",
            matchingCalls.isNotEmpty()
          )
        }
      }
    
      class TestEnvironment(private val session: TestSession) :
        SubmissionCallback {
        private val submittedCalls = mutableListOf<SignalProxyMessage>()
    
        fun run(f: ISession.() -> Unit): TestEnvironment {
          session.submissionCallbacks.add(this)
          f.invoke(session)
          session.submissionCallbacks.remove(this)
          return this
        }
    
        fun does(f: EnsuranceEnvironment.() -> Unit) {
          f.invoke(EnsuranceEnvironment(submittedCalls))
        }
    
        override fun callSubmitted(message: SignalProxyMessage) {
          submittedCalls.add(message)
        }
      }
    
      fun ensure(f: ISession.() -> Unit) = TestEnvironment(this).run(f)
    
      override val proxy = this
      override val objectStorage = ObjectStorage(this)
    
      override val error: Observable<Error> = Observable.empty()
      override val connectionError: Observable<Throwable> = Observable.empty()
    
      override val state = BehaviorSubject.createDefault(ConnectionState.CONNECTED)
      override val features = Features.all()
      override val sslSession = BehaviorSubject.createDefault(Optional.empty<SSLSession>())
    
      override val aliasManager = AliasManager(proxy)
      override val backlogManager = BacklogManager(this)
      override val bufferViewManager = BufferViewManager(this)
      override val bufferSyncer = BufferSyncer(this)
      override val certManagers = mutableMapOf<IdentityId, CertManager>()
      override val coreInfo = CoreInfo(this)
      override val dccConfig = DccConfig(this)
    
      override val identities = mutableMapOf<IdentityId, Identity>()
      private val live_identities = BehaviorSubject.createDefault(Unit)
      override fun liveIdentities(): Observable<Map<IdentityId, Identity>> = live_identities.map { identities.toMap() }
      override fun identity(id: IdentityId) = identities[id]
      override fun addIdentity(initData: QVariantMap) {
        val identity = Identity(this)
        identity.fromVariantMap(initData)
        identities[identity.id()] = identity
        synchronize(identity)
        live_identities.onNext(Unit)
      }
    
      fun addIdentity(identity: Identity, initialize: Boolean = false) {
        identities[identity.id()] = identity
        if (!initialize)
          identity.initialized = true
        synchronize(identity)
      }
    
      override fun removeIdentity(identityId: IdentityId) {
        val identity = identities.remove(identityId)
        stopSynchronize(identity)
        live_identities.onNext(Unit)
      }
    
      override val ignoreListManager = IgnoreListManager(this)
      override val highlightRuleManager = HighlightRuleManager(this)
      override val ircListHelper = IrcListHelper(this)
    
      override val networks = mutableMapOf<NetworkId, Network>()
      private val live_networks = BehaviorSubject.createDefault(Unit)
      override fun liveNetworks(): Observable<Map<NetworkId, Network>> = live_networks.map { networks.toMap() }
      override fun network(id: NetworkId) = networks[id]
      private val network_added = PublishSubject.create<NetworkId>()
      override fun liveNetworkAdded(): Observable<NetworkId> = network_added
      override fun addNetwork(networkId: NetworkId) {
        val network = Network(networkId, this)
        networks[networkId] = network
        synchronize(network)
        live_networks.onNext(Unit)
        network_added.onNext(networkId)
      }
    
      fun addNetwork(network: Network, initialize: Boolean = false) {
        networks[network.networkId()] = network
        if (!initialize)
          network.initialized = true
        synchronize(network)
      }
    
      override fun removeNetwork(networkId: NetworkId) {
        val network = networks.remove(networkId)
        stopSynchronize(network)
        live_networks.onNext(Unit)
      }
    
      override val networkConfig = NetworkConfig(this)
    
      override val rpcHandler = RpcHandler(this)
    
      override val initStatus = BehaviorSubject.createDefault(0 to 0)
    
      override val lag = BehaviorSubject.createDefault(0L)
    
      fun buildNetwork(networkId: NetworkId, f: (Network.() -> Unit)? = null): Network {
        val network = Network(networkId, proxy)
        f?.invoke(network)
        return network
      }
    
      fun buildIdentity(identityId: IdentityId, f: (Identity.() -> Unit)? = null): Identity {
        val identity = Identity(proxy)
        identity.setId(identityId)
        f?.invoke(identity)
        return identity
      }
    
      data class BufferTestData(
        val bufferInfo: BufferInfo,
        val activity: Message_Types = Message_Type.of(),
        val lastSeenMsg: MsgId = MsgId(-1),
        val markerLine: MsgId = MsgId(-1),
        val highlightCount: Int = 0
      )
    
      data class TestData(
        val session: TestSession,
        var networks: List<Network> = emptyList(),
        var identities: List<Identity> = emptyList(),
        var buffers: List<BufferTestData> = emptyList(),
        var aliases: List<IAliasManager.Alias> = emptyList()
      ) {
        fun buildNetwork(networkId: NetworkId, f: (Network.() -> Unit)? = null): Network {
          return session.buildNetwork(networkId, f)
        }
    
        fun buildIdentity(identityId: IdentityId, f: (Identity.() -> Unit)? = null): Identity {
          return session.buildIdentity(identityId, f)
        }
    
        fun Network.buildIrcChannel(name: String, f: IrcChannel.() -> Unit): IrcChannel {
          val ircChannel = IrcChannel(name, this, session.proxy)
          ircChannel.initialized = true
          f.invoke(ircChannel)
          newIrcChannel(name, ircChannel.toVariantMap())
          return ircChannel(name)!!
        }
    
        fun Network.buildIrcUser(name: String, f: IrcUser.() -> Unit): IrcUser {
          val ircUser = IrcUser(name, this, session.proxy)
          ircUser.initialized = true
          f.invoke(ircUser)
          newIrcUser(name, ircUser.toVariantMap())
          return ircUser(name)!!
        }
      }
    
      fun provideTestData(f: TestData.() -> Unit): TestSession {
        val data = TestData(this)
        f.invoke(data)
        for (network in data.networks) {
          addNetwork(network)
        }
        for (identity in data.identities) {
          addIdentity(identity)
        }
        bufferSyncer.setBufferInfos(data.buffers.map {
          it.bufferInfo
        })
        bufferSyncer.setActivities(data.buffers.map {
          Pair(it.bufferInfo.bufferId, it.activity)
        })
        bufferSyncer.setMarkerLines(data.buffers.map {
          Pair(it.bufferInfo.bufferId, it.markerLine)
        })
        bufferSyncer.setLastSeenMsg(data.buffers.map {
          Pair(it.bufferInfo.bufferId, it.lastSeenMsg)
        })
        bufferSyncer.setHighlightCounts(data.buffers.map {
          Pair(it.bufferInfo.bufferId, it.highlightCount)
        })
        aliasManager.setAliasList(data.aliases)
        return this
      }
    
      override fun onInitDone() = Unit
      override fun dispatch(message: HandshakeMessage) = Unit
      override fun dispatch(message: SignalProxyMessage) {
        for (submissionCallback in submissionCallbacks) {
          submissionCallback.callSubmitted(message)
        }
      }
    
      override fun login(user: String, pass: String) = Unit
    
      override fun setupCore(setupData: HandshakeMessage.CoreSetupData) {
        dispatch(setupData)
      }
    
      override fun disconnectFromCore() {}
    }