I use MockK library for unit testing.
Tested method contains strings that don't have meaning for a result. I want to check other variables, but have to define a behaviour of strings because they are used in tested methods.
For instance,
every {
resources.getQuantityString(R.plurals.age, 10, 10)
} returns "10 years"
every {
resources.getString(
R.string.surname,
"surname"
)
} returns "surname"
How can I omit parameters in these methods? So that I could pass any integer instead of 10, any string instead of "surname"? In this case a result of resources.getString won't have matter. I don't want to calculate a value of each parameter for a test. Just mock a behaviour.
You can use answers instead of returns and have a plethora of options to return something depending on the input, e.g.
every {
resources.getQuantityString(any(), any(), any())
} answers { "${arg<Int>(1)} years" }
every {
resources.getString(any(), any())
} answers { secondArg() }
Check out this table for the different parameters you can use in an answer.
Related
I have an API that has method which takes vararg of some object (fox example Param).
I need to filter null params and not put it to vararg. Is it possible ?
I know there is a method in kotlin listOfNotNull but api accepts vararg(
This is example of calling API method (apiMethod(vararg params: Param)):
someFun() {
apiMethod(
Param("first"),
Param("second"),
null // need to filter it
)
}
P.S. I can't change apiMethod()
If I understand your question correctly, you need to filter your arguments before passing them to the function since you cannot modify the function. To do this, you can filter to a List, and then convert that list to a typed array and pass it using the * spread operator:
fun someFun() {
apiMethod(
*listOfNotNull(
Param("first"),
Param("second"),
null // need to filter it
).toTypedArray()
)
}
It's a shame you have to use toTypedArray(). IMO, it should be supported for all Iterables, since Lists are far more common than Arrays. This feature request has not had a lot of attention from JetBrains.
Try mapNotNull method
val notNullArgs = args.mapNotNull { it }
If there will be any null it it will be filtered
Your apiMethod() should fail either filter out nulls or just fail if provided list that contains null
fun apiMethod(a : Int, b : String, vararg params : List<Any?>){
require(params.size == params.mapNotNull { it }.size) {
"Params must not contain null values"
}
// or
val filtered = params.mapNotNull { it }
}
Kotlin has these 2 features and I think there're no significant differences between these two
regardless of :
syntax
// lambda
val toUpper = { value: String ->
if (value.isEmpty()) "empty value"
else value.toUpperCase()
}
// anonymous func
val toUpper = fun(value: String): String {
if (value.isEmpty()) return "empty value"
else return value.toUpperCase()
}
flexibility to use return statement on anonymous function
I'm still digesting these features and hope you guys can help me pass through it.
Thanks.
Two differences according to Kotlin Reference:
(I think the more significant one out of the two) An anonymous function is still a function, so returning from it behaves the same as returning from any function. Returning from a lambda, however, actually returns from the function enclosing the lambda.
The return type of a lambda is inferred, while you can explicitly specify a return type for an anonymous function.
This website states: "Lambdas Expressions are essentially anonymous functions that we can treat as values – we can, for example, pass them as arguments to methods, return them, or do any other thing we could do with a normal object." (link)
So the answer is no, there isn't a difference between the two, they are interchangeable. Both of the codes you show above, will in the end return the same value to that variable
Besides the differences pointed by #jingx, you can not local return from a lambda that is not inlined.
So, the next snippet will not compile unless you add inline to the extension() function, thus, instructing the compiler to copy the function's content whenever it is referenced:
fun doSomethingWithLambda(){
10.extension{
if(it == 10)
return//compiler error
}
println("hello")
}
fun Int.extension(f: (Int)->Unit){
f(this)
}
I have read many articles, but there are still things I am having difficulty understanding. Where's the point I can't understand? My questions are in the code. I hope I asked right.
fun main() {
/*
1- Is it argument or parameter in numbers{} block?
where is it sent to the argument? why do we send "4" if it is parameter?
Are all the functions I will write in (eg println) sent to the numbers function? But this HOF can
only take one parameter.
*/
numbers {
/*
2-How does this know that he will work 3 times?
According to the following 3 functions? Is there a for loop logic??
*/
println(it)
"4" // 3- Which one does this represent? f:(String) or ->String?
}
}
fun numbers(f: (String) -> String) {
f("one")
f("two")
f("three")
println(f(" - "))
}
There is no argument or parameter defined in your lambda block above. It's just the content of your lambda function. You've used the implicit single parameter name of it. "4" is the return value of your lambda.
The lambda itself isn't "aware" of how many times it will be called. In this case, it is called four times, because your numbers function invokes the parameter f four times.
A lambda's return value is whatever its last expression evaluates to. In this case, it returns the String "4".
Maybe this will help. Lambda syntax is a convenience. But we can take away each piece of syntactic sugar one at a time to see what it actually means.
All of the code blocks below have the exact same meaning.
Here is your original statement:
numbers {
println(it)
"4"
}
First, when a lambda omits the single parameter, it gets the implicit parameter name it. If we avoid using this sugar, it would look like this:
numbers { inputString ->
println(inputString)
"4"
}
The evaluated value of the last expression in a lambda is what it returns. You can also explicitly write a return statement, but you must specify that you are returning from the lambda, so you have to put its name. So if we put this in, it looks like this:
numbers { inputString ->
println(inputString)
return#numbers "4"
}
When a lambda is the last argument you pass to a function, you can put it outside the parentheses. This is called "trailing lambda". And if the function is the only argument, you don't need parentheses at all. If we skip this convenience, it looks like this:
numbers({ inputString ->
println(inputString)
return#numbers "4"
})
A lambda is just a very compact way of defining a function. If we define the function directly, it looks like this:
numbers(fun(inputString: String): String {
println(inputString)
return "4"
})
The function you are passing is the argument of the numbers() function. You can also define it separately and then pass the function reference like this:
fun myFunction(inputString: String): String {
println(inputString)
return "4"
}
numbers(::myFunction)
I'm a novice of Kotlin.
I found that I can use another function without parameters even if it has.
Let me know when I can use it.
Q1) Why can I use 2 types? (with parameters & without parameters) Is it Kotlin's feature?
Q2) What does it mean? ((Result!) -> Unit)!
It seems you are confused, you can never use a function without arguments. If the function has arguments then you have to fill the slot somehow.
The closest thing that could relate to what you are referring to is default values for arguments.
fun example(boolean: Boolean = true) {}
example()
example(true)
example(false)
You can omit the argument because it has defaulted in the function signature.
The documentation
What you are showing in the image file is a lambda.
In the first example:
signIn(listener: Session...)
That seems to be a callback. So it is gonna be an interface or maybe an abstract class called when some async operation is finished.
The second example, it is the callback implemented as a lambda
signIn() { result ->
//do something
}
In Kotlin the last argument if it is a lambda or something that can be implemented as a lambda can be moved out of the parenthesis for syntactic sugar. A lambda is like an anonymous function, it is a literal of a function.
By example you can declare a lambda:
val lambda = {text: String -> text.lenght % 2 == 0}
fun setRuleForText(rule: (String)-> Boolean) {...}
setRuleForText(lambda)
setRuleForText() { text: String
text.isNotEmpty()
}
In this case, the argument is a kotlin function. The argument rule is a function that receives a String as an argument and returns Boolean. Something to point out is that expressions return the last written value without the need for the reserved return word.
This is the documentation. And here you can see from a good source more about functions (the author is a Kotlin certified trained by Jetbrains)
In your case (Result) -> Unit means the lambda should receive a Result type as argument and then return Unit (unit is like void in Java but is more than that), no explicit return type.
signIn() { result ->
//do something
}
Most of the types, the argument on lambdas is inferred automatically, but if not, then
signIn() { result: Result ->
//do something
}
Both of the listed functions take a parameter.
The first is:
signIn(listener: Session.SignInListener!)
That takes a single parameter, of type Session.SignInListener. (The ! means that Kotlin doesn't know whether it's nullable or not, because it's from Java and isn't annotated.)
The other is:
signIn {...} (listener: ((Result!) -> Unit)!)
That's the IDE's representation of the function with this signature:
signIn(listener: ((Result!) -> Unit)!)
That takes a single parameter, which is a function type (see below).
The reason the IDE shows it with braces is that in Kotlin, if the last parameter to a function is a lambda, you can move it outside the parentheses. So a call like this:
signIn({ println(it) })
could equally well be written like this:
signIn() { println(it) }
The two forms mean exactly the same. And, further, if the lambda is the only parameter, you can omit the parens entirely:
signIn { println(it) }
Again, it means exactly the same thing.
That syntax allows you to write functions that look like new language syntax. For example:
repeat (10) {
// ...
}
looks like a new form of loop construct, but it's really just a function called repeat, which takes two parameter (an integer, and a lambda).
OK, let's look at that function type: ((Result!) -> Unit)!
That's the type of a function which takes one parameter of type Result, and returns Unit (i.e. nothing useful; think of it as the equivalent of void). Again, it's complicated because Kotlin doesn't know about the nullability; both the Result parameter and the parameter holding this function have !s to indicate this. (Without them, it would just be (Result) -> Unit.)
I am trying to interface with TeamCity using Kotlin-DSL
In this section of the TC Kotlin guide there is a rather odd looking part where it seems like it causes statements to become concatenated on the fly.
It first defines these:
val linux = Requirements() {
contains("os.name", "linux")
}
val oracle = Requirements() {
equals("db.name", "oracle")
}
val java6 = Requirements() {
contains("env.JAVA_HOME", "1.6")
}
Then does this with those definitions:
buildType {
...
requirements(linux + oracle + java6)
...
}
I know that the above section of code is equivalent to
buildType {
...
requirements {
contains("os.name", "linux")
equals("db.name", "oracle")
contains("env.JAVA_HOME", "1.6")
}
...
}
So I suppose what my question boils down to is what is the return type of the 'Requirements' function that can just be concatenated together? My guess is it is some sort of statement/ function wrapper and Kotlin lets you concatenate these as you go, and the function signature looks like this:
fun Requirements(init: (a: String, b: String) -> UnknownTypeA) : UnknownTypeB
EDIT:
For anyone who is confused when reading this in the future, the calls to Requirements are actually an object initialisation via the Requirements constructor. I do inevitably feel embarrassed for not picking up on this (The casing of the name should have been hint enough!) but I'm making this edit to make it clear to people that it is not a function. Thank you to Hotkey for pointing that out.
First, note that Requirements accepts a function into its constructor. Without knowing what is the type of that function, let's assume it's Context.() -> Unit (a function with receiver of Context, accepting no arguments and returning Unit).
Now, we can naturally overload the plus operator for the Requirements type, so that it returns another Requirements instance that has a function that applies both functions from the operands.
You could do that in your own code in the following way:
class Requirements(val check: Context.() -> Unit)
operator fun Requirements.plus(other: Requirements) =
Requirements { check(); other.check() }