Kotlin: Unresolved reference: use, - kotlin

I am trying to integrate a Dialogflow Agent with Pepper: https://developer.softbankrobotics.com/pepper-qisdk/lessons/integrating-chatbot-dialogflow
I followed all the steps until the Testing your agent in standalone section, where I have to add the following Kotlin code to the DialogflowSource class:
import com.google.auth.oauth2.ServiceAccountCredentials
import com.google.cloud.dialogflow.v2.*
import java.io.InputStream
class DialogflowDataSource constructor(credentialsStream : InputStream) {
private val credentials : ServiceAccountCredentials
= ServiceAccountCredentials.fromStream(credentialsStream)
fun detectIntentTexts(
text: String,
sessionId: String,
languageCode: String
): String? {
val sessionsSettings = SessionsSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
SessionsClient.create(sessionsSettings).use { sessionsClient -> //Error: Unresolved reference for .use
val session = SessionName.of(credentials.projectId, sessionId)
val textInput = TextInput.newBuilder()
.setText(text).setLanguageCode(languageCode)
val queryInput = QueryInput
.newBuilder().setText(textInput).build()
val response = sessionsClient.detectIntent(session, queryInput)
return response.queryResult.fulfillmentText
}
} //Error: A 'return' expression required in a function with a block body ('{...}')
}
I'm new to Kotlin, so I don't really know how to fix this. Any help would be appreciated!

First, why would you use use? It seems you meant to call apply instead. But in fact you could just write:
fun detectIntentTexts(
text: String,
sessionId: String,
languageCode: String
): String? {
val sessionsSettings = SessionsSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
val sessionClient = SessionsClient.create(sessionsSettings)
val session = SessionName.of(credentials.projectId, sessionId)
val textInput =
TextInput.newBuilder().setText(text).setLanguageCode(languageCode)
val queryInput = QueryInput.newBuilder().setText(textInput).build()
val response = sessionsClient.detectIntent(session, queryInput)
return response.queryResult.fulfillmentText
}
But if you care using use (or apply), the lambda you provide to it should not directly make the outer function detectIntentTexts return. Instead, let your lambda return its result locally, and let detectIntentTexts return it:
fun detectIntentTexts(
text: String,
sessionId: String,
languageCode: String
): String? {
val sessionsSettings = SessionsSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credentials))
.build()
return SessionsClient.create(sessionsSettings).apply { sessionsClient ->
val session = SessionName.of(credentials.projectId, sessionId)
val textInput = TextInput.newBuilder()
.setText(text).setLanguageCode(languageCode)
val queryInput = QueryInput
.newBuilder().setText(textInput).build()
val response = sessionsClient.detectIntent(session, queryInput)
response.queryResult.fulfillmentText
}
}
}

Related

How to mock a CompletableFuture in Kotlin

We have some code to read data from DynamoDB:
suspend fun getKeys(owner: String): Set<String> {
...
val query = ...
query.subscribe { page -> foo(page) }.await()
return ...
}
The subscribe{} above is defined in AWS SDK:
default CompletableFuture<Void> subscribe(Consumer<T> consumer)
I'd like to unit test the logic in this function, for subscribe I don't care about it, hopefully just mock and do nothing.
I tried mock a callback in my unit test (irrelevant code removed):
class BucketRepoTest(
#Mock private val query: SdkPublisher<Page<DbBucket>>
) {
#Test
fun `get keys should be working`() {
val callback = mock<(Page<DbBucket>) -> Unit>()
val result = mock<CompletableFuture<Void>>()
whenever(query.subscribe(callback)).thenReturn(result)
runBlocking {
val keys = data.getKeys("Charlie")
assert(keys.isEmpty())
}
}
}
But when I run the test I got NPE:
query.subscribe { page -> foo(page) } must not be null
java.lang.NullPointerException: query.subscribe { page -> foo(page) } must not be null
at com.myApp.getKeys(myfile.kt:75)
at ...
Any idea how to fix it?
The result cannot be void.
val result = mock<CompletableFuture>()
try to create a mock data and pass as result
val result = the object or data type you want to more
Example
data Result( Charlie = "john", age = "23")
then
class BucketRepoTest(
#Mock private val query: SdkPublisher<Page<DbBucket>> ) {
#Test
fun `get keys should be working`() {
val callback = mock<(Page<DbBucket>) -> Unit>()
val result = Result()
whenever(query.subscribe(callback)).thenReturn(result)
runBlocking {
val keys = data.getKeys("Charlie")
assert(keys.isEmpty())
}
}
}

How we can mock a CoroutineDatabase in ktor?

I use the KMongo tool
How we can mock a Coroutine Database?
How can we mock our database in a koin module?
Is there a way to do this?
Thanks for guiding me
Methods I have tried and it has not worked:
The first method:
single<CoroutineDatabase> {
val client = Mockito.mock(CoroutineClient::class.java)
client.getDatabase(CoreConstants.DATABASE_NAME)
}
The second method:
single<CoroutineDatabase> {
val client = declareMock<CoroutineClient> { }
client.getDatabase(CoreConstants.DATABASE_NAME)
}
I've managed to get this working with MockK with the following approach.
TLDR
Just use a mock of MongoDatabase/MongoCollection<T> and make their coroutine extension property return a mocked CoroutineDatabase/CoroutineCollection<T>. Also need to mock the actual MongoDatabase::getCollection to return the respective MongoCollection<T>.
Suppose we have this scenario.
data class User(val id: Int, val name: String)
class Service(private val myDatabase: CoroutineDatabase) {
private val userCollection: CoroutineCollection<User> = myDatabase.getCollection("users")
suspend fun getById(id: Int): User? = userCollection.findOneById(id)
}
Since userCollection is acquired by calling the inline method CoroutineDatabase::getCollection we need to mock all the code inside that inline because inline methods cannot be mocked with MockK (at the time of writing). Looking at the method code
inline fun <reified TDocument : Any> getCollection(
collectionName: String = KMongoUtil.defaultCollectionName(TDocument::class)
): CoroutineCollection<TDocument> =
database.getCollection(collectionName, TDocument::class.java).coroutine
It just calls com.mongodb.reactivestreams.client.MongoDatabase::getCollection and then uses this extension property to map it to a CoroutineCollection. Notice it uses the field database from CoroutineDatabase which is a MongoDatabase (The CoroutineDatabase was previously obtain via a similar extension property for MongoDatabase).
val <T : Any> MongoCollection<T>.coroutine: CoroutineCollection<T> get() = CoroutineCollection(this)
val MongoDatabase.coroutine: CoroutineDatabase get() = CoroutineDatabase(this)
Having all of this we need to mock:
Both coroutine extension properties on MongoDatabase and MongoCollection<T> (see mocking extension properties with MockK)
The actual MongoDatabase::getCollection because CoroutineDatabase::getCollection is an inline function
// Arrange
val mockedMongoDd: MongoDatabase = mockk<MongoDatabase> {
mockkStatic(MongoDatabase::coroutine)
val that = this
every { coroutine } returns mockk {
every { database } returns that
}
}
val mockedMongoCol: MongoCollection<User> = mockk<MongoCollection<User>> {
mockkStatic(MongoCollection<T>::coroutine)
val that = this
every { ofType<MongoCollection<T>>().coroutine } returns mockk {
every { collection } returns that
}
}
every {
mockedMongoDb.getCollection("users", User::class.java)
} returns mockedMongoCol
val mockedCoroutineDb = mockedMongoDb.coroutine
val mockedCoroutineCol = mockedMongoCol.coroutine
val service = Service(mockedCoroutineDb)
val expectedUser = User(2, "Joe")
coEvery {
mockedCoroutineCol.findOneById(2)
} returns expectedUser
// Act
val actualUser = service.getById(2)
// Assert
assertEquals(expectedUser, actualUser)
Finally, one could make some methods like the following to hide this details from the test.
inline fun <reified T : Any> mockkCoroutineCollection(
name: String? = null,
relaxed: Boolean = false,
vararg moreInterfaces: KClass<*>,
relaxUnitFun: Boolean = false,
block: MongoCollection<T>.() -> Unit = {}
): MongoCollection<T> = mockk(name, relaxed, *moreInterfaces, relaxUnitFun = relaxUnitFun) {
mockkStatic(MongoCollection<*>::coroutine)
val that = this
every { coroutine } returns mockk(name, relaxed, *moreInterfaces, relaxUnitFun = relaxUnitFun) {
every { collection } returns that
}
block()
}
inline fun mockkCoroutineDatabase(
name: String? = null,
relaxed: Boolean = false,
vararg moreInterfaces: KClass<*>,
relaxUnitFun: Boolean = false,
block: MongoDatabase.() -> Unit = {}
): MongoDatabase = mockk(name, relaxed, *moreInterfaces, relaxUnitFun = relaxUnitFun) {
mockkStatic(MongoDatabase::coroutine)
val that = this
every { coroutine } returns mockk(name, relaxed, *moreInterfaces, relaxUnitFun = relaxUnitFun) {
every { database } returns that
}
block()
}
This would reduce the first lines to
val mockedMongoDb: MongoDatabase = mockkCoroutineDatabase()
val mockedMongoCol: MongoCollection<User> = mockkCoroutineCollection<User>()
// ...

Passing Lamda function to Generic function not working

I am playing with Kotlin and I am trying to convert a working Scala code to Kotlin. Everything seems to go pretty well but the compiler gives me this error and I dont know how to handle it.
Type mismatch: inferred type is Any but ExQuestion was expected for this line: return makeMap(questions, add2)
I am using a generic function because I need to access members of type A when building the map and the members would be visible through the lambda function provided.
Here's the code which you can copy into the Kotlin sandbox:
data class ExQuestion(val area: String, val rId: String, val text: String, val rIdAnswer: String, val line: Long)
fun main() {
fun <A> makeMap(list: List<A>, addValue: (A, MutableMap<String, A>) -> Unit): Map<String, A> {
val map = mutableMapOf<String, A>()
for( item in list) {
addValue(item, map)
}
return map
}
val add2: (ExQuestion, MutableMap<String, ExQuestion>) -> Unit =
{ question: ExQuestion, map: MutableMap<String, ExQuestion> ->
val key = question.rId
if (map[key] == null) {
map[key] = question
} else {
println("Id Frage mehrfach vorhanden - " + key)
}
}
val questions = listOf(ExQuestion("Area", "Q01", "text", "A01",1))
return makeMap(questions, add2)
}
Working code:
data class ExQuestion(val area: String, val rId: String, val text: String, val rIdAnswer: String, val line: Long)
fun main() {
fun <A> makeMap(list: List<A>, addValue: (A, MutableMap<String, A>) -> Unit): Map<String, A> {
val map = mutableMapOf<String, A>()
for( item in list) {
addValue(item, map)
}
return map
}
val add2: (ExQuestion, MutableMap<String, ExQuestion>) -> Unit =
{ question: ExQuestion, map: MutableMap<String, ExQuestion> ->
val key = question.rId
if (map[key] == null) {
map[key] = question
} else {
println("Id Frage mehrfach vorhanden - " + key)
}
}
val questions = listOf(ExQuestion("Area", "Q01", "text", "A01",1))
val map = makeMap(questions, add2)
println(map.values)
}
I'm not sure what your question is, but you can convert your list of questions to a map keyed on rId by doing:
val map = questions.map { it.rId to it }.toMap()
println(map)
Result:
{Q01=ExQuestion(area=Area, rId=Q01, text=text, rIdAnswer=A01, line=1)}
Update in response to comments.
You can achieve that without a mutable map by doing something like this:
val map = questions
.groupBy { it.rId }
.mapValues { (key, values) ->
if (values.size > 1) println("Id Frage mehrfach vorhanden - $key")
values.first()
}
However, I think your mutable map solution is fine and arguably clearer, so this is just for demonstration.

How to print multiple attrributes from a hashMap that is a property inside a toString override

I am learning Kotlin and writing code to check my understanding. I'm trying to use a toString override to print the values of a hashMap that is a property of a class. I can't get it to work. Instead I get output like "kotlin.Unit() -> kotlin.Unit". Also, I don't understand why the values of the hashMap ARE printing out before the toString output. I don't know where that output is coming from. Please help me. Thanks. Below is my code and the output I'm getting.
Code:
package ch07.ExpandoObject
import java.beans.PropertyChangeListener
import java.beans.PropertyChangeSupport
import kotlin.properties.Delegates
import kotlin.reflect.KProperty
class Person(
val name: String = "",
age: Int? = null,
var isMarried: Boolean? = null ,_attributes: kotlin.collections.HashMap<String,String>? = hashMapOf<String, String>()
)
:PropertyChangeAware()
{
var _attributes : kotlin.collections.HashMap<String,String>? = hashMapOf<String, String>()
fun setAttribute(attrName: String, value: String) {
_attributes!!.set(attrName, value)
_attributes!!.set("name", this.name)
}
override fun toString() = "Person(name=\"${name?:""}\", age=${age?:99999}, isMarried=$isMarried) " +
"${_attributes?.get("name")} " + "$name " +
this._attributes!!.forEach { (attrName, value) -> println("$attrName = $value") } +
{
for ((attrName, value) in this._attributes!!) {
println("attribute $attrName = ${this._attributes!![attrName]}")
}
}
val _age = ObservableProperty(propName = "age", propValue = age, changeSupport = changeSupport)
private val observer = {
prop: KProperty<*>, oldValue: Int, newValue: Int ->
changeSupport.firePropertyChange(prop.name, oldValue, newValue)
}
var age: Int by Delegates.observable(initialValue = age?:99999,onChange = observer)
}
class ObservableProperty(val propName: String,
var propValue: Int?, val changeSupport: PropertyChangeSupport
) {
fun getValue(): Int? = propValue
fun setValue( newValue: Int) {
val oldValue = propValue
propValue = newValue
changeSupport.firePropertyChange(propName, oldValue, newValue)
}
}
open class PropertyChangeAware {
val changeSupport = PropertyChangeSupport(this)
fun addPropertyChangeListener(listener: PropertyChangeListener) {
changeSupport.addPropertyChangeListener(listener)
}
fun removePropertyChangeListener(listener: PropertyChangeListener) {
changeSupport.removePropertyChangeListener(listener)
}
}
fun main(args: Array<String>) {
val p = Person("Bob", 89, isMarried = false)
val data = mapOf("lastname" to "Jones", "company" to "JetBrains")
for ((attrName, value) in data)
p.setAttribute(attrName, value)
println(p)
}
Here is the current output:
name = Bob
company = JetBrains
lastname = Jones
Person(name="Bob", age=89, isMarried=false) Bob Bob kotlin.Unit() -> kotlin.Unit
Thanks, again, for any help.
You should not use print() or println() functions inside toString() because they output their arguments to the standard output immediately instead of appending them to the string returned to the caller.
Let's examine the output kotlin.Unit() -> kotlin.Unit you're getting. It consists of two parts:
kotlin.Unit is the string representation of attributes!!.forEach { ... } expression. forEach function returns without value, and in Kotlin it's expressed by returning the Unit object value. Its string representation is appended to the string you're returning.
the second part, () -> kotlin.Unit, is also the string representation of the lambda function expression { for((attrName, value) in ...) }. This function takes no parameters, and returns without value, which means that its type is () -> Unit. Note that in Kotlin the block { ... } declares a local lambda function. If you instead want to run the code inside of that block, use the run function: run { ... }
The goal of toString function is to build the string representation of an object. And for that you can use buildString function:
override fun toString() = buildString {
append("Person(name=\"${name?:""}\", age=${age?:99999}, isMarried=$isMarried) ")
append("${_attributes?.get("name")} ").append("$name ")
this._attributes!!.forEach { (attrName, value) -> append("$attrName = $value") }
for ((attrName, value) in this._attributes!!) {
append("attribute $attrName = ${this._attributes!![attrName]}")
}
}
This function creates a StringBuilder and passes it as a receiver to its functional argument, where you call append or appendln on that receiver. Then buildString converts that string builder to a string and returns it.

combineLatest method in Kotlin with more than 3 Observables: getting error in implementing the method

I am using RxJava combineLatest method in Kotlin with more than 3 Observables .I am getting error in implementing the method
val userNameObservable = RxHelper.getTextWatcherObservable(username)
val passwordObservable = RxHelper.getTextWatcherObservable(password)
var submitButtonObservable: Observable<String> ?=null
button.setOnClickListener { submitButtonObservable = RxHelper.getButtonClickable() }
observable = Observable.combineLatest(userNameObservable, passwordObservable, submitButtonObservable,Triple(userNameObservable,passwordObservable,submitButtonObservable))
observable?.debounce(800, TimeUnit.MILLISECONDS)?.observeOn(AndroidSchedulers.mainThread())?.subscribe {
if (username.text.isEmpty() || password.text.isEmpty())
button.isEnabled = false
else
button.isEnabled = true
}
}
the error i am getting is:
None of the following functions can be called with the arguments supplied:
#CheckReturnValue #SchedulerSupport public final fun combineLatest(p0: ((Observer) -> Unit)!, p1: ((Observer) -> Unit)!, p2: ((Observer) -> Unit)!, p3: ((???, ???, ???) -> Unit)!): Observable! defined in io.reactivex.Observable
#CheckReturnValue #SchedulerSupport public open fun combineLatest(p0: ObservableSource!, p1: ObservableSource!, p2: ObservableSource!, p3: io.reactivex.functions.Function3!): Observable! defined in io.reactivex.Observable
#CheckReturnValue #SchedulerSupport public open fun combineLatest(p0: Function!, out Unit!>!, p1: Int, vararg p2: ObservableSource!): Observable! defined in io.reactivex.Observable
There are three options:
Use Function3:
Observable.combineLatest(userNameObservable, passwordObservable, submitButtonObservable, Function3 { username: String, password: String, submitBtn: Any ->
if (username.text.isEmpty() || password.text.isEmpty())
button.isEnabled = false
else
button.isEnabled = true
})
Use Observables.combineLatest:
observable = Observables.combineLatest(userNameObservable, passwordObservable, submitButtonObservable)
observable?.debounce(800, TimeUnit.MILLISECONDS)?.observeOn(AndroidSchedulers.mainThread())?.subscribe {
//Access data from observables with it.first, it.second and it.third
}
Use the Observable.combineLatest in its list form. Example:
Observable.combineLatest(listOf(TextViewObs.create(tietPassword), TextViewObs.create(tietPasswordRepeat))) {
return#combineLatest it[0]==it[1]
}.subscribe {
if(it){
//Passwords match
tietPasswordRepeat?.error = null
}else{
//Passwords do not match
tietPasswordRepeat?.error = getString(R.string.Passwords_must_match)
}
}