I've got an interface:
interface DistanceChecker {
fun checkDistance(locationData: LocationData, result: (Boolean) -> Unit)
}
I need to mock this method, but I don't call it explicitly, it's injected into logic.
This construction does not work:
doAnswer {
it.getArgument<(Boolean) -> Unit>(1).invoke(true)
null
}.`when`(distanceChecker).checkDistance(
same(
LocationData(
LatLng(.0, .0),
LatLng(.0, .0),
.0
)
),
any()
)
By this I got a stubbing error:
- this invocation of 'checkDistance' method:
distanceChecker.checkDistance(
LocationData(point=0.0_0.0, location=0.0_0.0, zoneRadius=0.0),
(kotlin.Boolean) -> kotlin.Unit
);
- has following stubbing(s) with different arguments:
1. distanceChecker.checkDistance(
LocationData(point=0.0_0.0, location=0.0_0.0, zoneRadius=0.0),
null
);
Is there any way to mock lambda like that?
Related
This is the main body of my function
val client = ConnectionFactory.createClient() # <- Return lettice.io RedisClusterClient
val conn = client.connect()
val command = conn.sync()
var index: String? = null
index = readDataStructure(command, key)
This is my first try to define my readDataStructure function:
fun readDataStructure(command: RedisCommand, key: String): String {
...
kotlin complaints error: 3 type arguments expected for interface RedisCommand<K : Any!, V : Any!, T : Any!>
I want to be able to NOT specifying K, V and T because I am just writing a throwaway script.
Is there any Kotlin lang syntax and can allow me to just pass the command variable as is?
I suppose you are after:
fun readDataStructure(command: RedisCommand<*,*,*>, key: String): String {
?
From Kotlin docs https://kotlinlang.org/docs/tutorials/kotlin-for-py/generics.html:
If you don't have any idea (or don't care) what the generic type might be, you can use a star-projection:
fun printSize(items: List<*>) = println(items.size)
When using a generic type where you have star-projected one or more of its type parameters, you can:
Use any members that don't mention the star-projected type parameter(s) at all
Use any members that return the star-projected type parameter(s), but the return type will appear to be Any? (unless the type parameter is constrained, in which case you'll get the type mentioned in the constraint)
Not use any members that take a star-projected type as a parameter
I really like how with behaves. Is it possible to extend with so it works with multiple params.
I want to use with like this.
with(foo, bar){
fooFunction()
barFunction()
}
First, I strongly against it.
One can come close to what you want:
data class A(val a: Int)
data class B(val b: Int)
fun<S, T> withPair(a: S, b: T, f: S.() -> T.() -> Unit) {
val g = a.f()
b.g()
}
fun main() {
withPair(A(1), B(2)) {{
print(a)
print(b)
}}
}
So you can have a block function which return a block function. You need nested lambdas though.
I don't think it's possible to write a function which behaves like this, but with the standard with you can write
with(foo) {
with(bar) {
fooFunction()
barFunction()
}
}
(note that if a method is available on both foo and bar, this way the bar method will be called).
Another possibility is to use a Pair, something like:
with( Pair("abc" , listOf(1,2,3)) ) {
println(first.plus("d"))
println(second.reversed())
}
Prints:
abcd
[3, 2, 1]
It's impossible to do this with the standard with function because it cannot have two receiver types of the lambda (accessed by this).
with(foo, bar){
fooFunction() //`this` would have to mean `foo`
barFunction() //`this` would have to mean `bar`
}
Nesting two withs is nasty. It can cause all sort of issues, with this ambiguity...
That said, you can create your own with function that will work similarly to the standard one, but will not use passed extension fun (so no receiver type "hidden" behind this), but a regular lambda with two arguments:
inline fun <T1, T2, R> with(t1: T1, t2: T2, block: (T1, T2) -> R): R {
return block.invoke(t1, t2)
}
//then:
with(foo, bar) { f, b ->
f.fooFunction()
b.barFunction()
}
I'm trying to understand why let is needed. In the example below I have a class Test with a function giveMeFive:
public class Test() {
fun giveMeFive(): Int {
return 5
}
}
Given the following code:
var test: Test? = Test()
var x: Int? = test?.giveMeFive()
test = null
x = test?.giveMeFive()
x = test?.let {it.giveMeFive()}
x gets set to 5, then after test is set to null, calling either of the following statements return null for x. Given that calling a method on a null reference skips the call and sets x to null, why would I ever need to use let? Are some cases where just ?. won't work and let is required?
Further, if the function being called doesn't return anything, then ?. will skip the call and I don't need ?.let there either.
let()
fun <T, R> T.let(f: (T) -> R): R = f(this)
let() is a scoping function: use it whenever you want to define a variable for a specific scope of your code but not beyond. It’s extremely useful to keep your code nicely self-contained so that you don’t have variables “leaking out”: being accessible past the point where they should be.
DbConnection.getConnection().let { connection ->
}
// connection is no longer visible here
let() can also be used as an alternative to testing against null:
val map : Map<String, Config> = ...
val config = map[key]
// config is a "Config?"
config?.let {
// This whole block will not be executed if "config" is null.
// Additionally, "it" has now been cast to a "Config" (no
question mark)
}
You need to use let if you want to chain function calls that aren't defined on the type you are chaining from.
Let's say the definition of your function was this instead:
// Not defined inside the Test class
fun giveMeFive(t: Test) {
return 5
}
Now, if you have a nullable Test and want to call this function in a chain, you have to use let:
val x = test?.let { giveMeFive(it) }
The .let{} extension function in Kotlin:
Takes the object reference as the parameter on which .let{} is called.
Returns value of any non-primitive data-type which has been returned from with let{} function. By default, it returns undefined value of kotlin.Any class.
Declaration in package kotlin:
public inline fun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
Simple practical demonstration to see how .let{} extension function works in Kotlin.
Sample Code 1:-
val builder = StringBuilder("Hello ")
println("Print 0: $builder")
val returnVal = builder.let { arg ->
arg.append("World")
println("Print 1: $arg")
"Done" // Returnning some string
}
println("Print 2: $builder")
println("Print 3: $returnVal")
Sample Code 1 Output:-
Print 0: Hello
Print 1: Hello World
Print 2: Hello World
Print 3: Done
In Sample Code 1:
We created the final object of type StringBuilder with initialization value "Hello ".
In builder.let{}, the builder object reference will be passed to arg.
Here, the output Print 2: Hello World and Print 3: Hello World means that the builder and arg, both are pointing to the same StringBuilder object-reference. That's why they both print the same String value.
In the last line of .let{} function block, we are returning "Done" String value which will be assigned to returnVal.
*Hence, we get Print 3: Done output from returnVal.
Sample Code 2:-
val builder = StringBuilder("Hello ")
println("Print 0: $builder")
val returnVal = builder.let { arg ->
arg.append("World")
println("Print 1: $arg")
arg.length
}
println("Print 2: $builder")
println("Print 3: $returnVal") // Now return val is int = length of string.
Sample Code 2 Output:-
Print 0: Hello
Print 1: Hello World
Print 2: Hello World
Print 3: 11
In Sample Code 2:
What's difference:
In the last line of .let{} function block, we are returning the Int value equals to the length of StringBuilder object arg whose value at this line of code is "Hello World". So length = 11 of type Int will be assigned to returnVal.
*Hence, we get Print 3: 11 as output from returnVal.
Also try these:-
.run() {}
.apply() {}
with(obj) {}
.also() {}
Happy Coding...
fun <T, R> T.let(f: (T) -> R): R = f(this)
.let block does not equal to in multiThreading
val x? = null
if(x == null) {
}
and
x?.let{
}
.let block is thread-safe
I'm trying to have this compiling:
val criteriaList = aList.stream().map { dateRange -> {
Criteria.where("KEY").`is`(dateRange) } }.toList().toTypedArray()
Criteria().orOperator(*criteriaList)
But:
Criteria().orOperator(*criteriaList)
Currently does not compile:
Type mismatch.
Required:
Array<(out) Criteria!>!
Found:
Array<(() → Criteria!)!>
Why?
You are mapping your dateRange to a () -> Criteria.
You do not need to wrap what is following after -> with curly braces. Check also the Kotlin reference regarding Lambda expression syntax:
val sum = { x: Int, y: Int -> x + y }
A lambda expression is always surrounded by curly braces [...], the body goes after an -> sign. If the inferred return type of the lambda is not
Unit, the last (or possibly single) expression inside the lambda body is treated as the return value.
So you could just write the following instead:
.map { dateRange -> Criteria.where("KEY").`is`(dateRange) }
Note also that you do not really need to call stream(), but you can directly call map on it (except it wouldn't be a real List in the first place).
So your code could probably be simplified to something like:
val criteriaList = aList.map { dateRange -> Criteria.where("KEY").`is`(dateRange) }
.toTypedArray()
or
val criteriaList = aList.map { Criteria.where("KEY").`is`(it) }
.toTypedArray()
Is it possible to specify some optional parameter(s) to the 'at' closure on the page like this:
class ManagerDashboardClientsPage extends Page {
static at = { year, geo ->
if (year) {
GebUtil.selectedYear == year
}
title.endsWith('Dashboard: Clients')
}
}
so that I can write both
at ManagerDashboardClientsPage
and
at ManagerDashboardClientsPage(2013, 'North East')
Currently the first one breaks with
No signature of method: page.ManagerDashboardClientsPage$__clinit__closure1.doCall() is applicable for argument types: () values: []
Possible solutions: doCall(java.lang.Object, java.lang.Object), call(), call([Ljava.lang.Object;), call(java.lang.Object), call(java.lang.Object, java.lang.Object), equals(java.lang.Object)
groovy.lang.MissingMethodException: No signature of method: page.ManagerDashboardClientsPage$__clinit__closure1.doCall() is applicable for argument types: () values: []
Possible solutions: doCall(java.lang.Object, java.lang.Object), call(), call([Ljava.lang.Object;), call(java.lang.Object), call(java.lang.Object, java.lang.Object), equals(java.lang.Object)
at geb.Page.verifyThisPageAtOnly(Page.groovy:165)
at geb.Page.verifyAt(Page.groovy:133)
at geb.Browser.doAt(Browser.groovy:358)
at geb.Browser.at(Browser.groovy:289)
at geb.spock.GebSpec.methodMissing(GebSpec.groovy:51)
at spec.ManagerDashboardClientsSpec.login as CEO(ManagerDashboardClientsSpec.groovy:16)
In Groovy you can set default values for optional closure parameters, like so:
static at = { year=null, geo=null ->
...
}
I think that'll clear ya up. :)
update
Ok, I know you don't need it anymore, but I made this for my own use when I was learning Groovy, and I thought someone might find it helpful:
{ -> ... } a closure with exactly zero parameters. Groovy will blow up if you call it with params.
{ ... } a closure with one optional parameter, named "it"
{ foo -> ... } a closure with one parameter named "foo" (foo can be any type)
{ foo, bar, baz -> ... } a closure with 3 parameters named "foo", "bar" and "baz"
{ String foo -> ... } You can specify the type of the parameters if you like