Mocking Interfaces with Kotlin and Mockito - mockito

I don't really understand interface mocking in Kotlin. I'm not sure if this is Kotlin specific or applies to java also. So far I have only tried it in Kotlin.
I have a mocked class with interfaces:
val mockObj = mock(MyClass::class.java, withSettings().extraInterfaces(IMyInterface::class.java)
now, this produces the following problem in IntelliJ:
`when`(mockObj.someMethod()).thenReturn(0.1)
the someMethod() will be red (I assume this depends on the color scheme, but you get the idea - a problem: unresolved reference)
to solve this, I simply include this line before it:
val mockInterface = mockObj as IMyInterface
the mockInterface will be grey squigly underlined because it is never used. I still use mockObj for the when
however, this makes the red disappear
I'm not sure why this works... can someone explain the theory?
to get rid of the grey underline, I then remove val mockInterface =
so my magic line is reduced to mockObj as IMyInterface

The return type of mock(MyClass::class.java) is MyClass. The returned object is also an instance of IMyInterface, since you asked that to Mockito, but the Kotlin compiler can't know that.
mockObj as IMyInterface tells the Kotlin compiler to cast mockObj to IMyInterface. Since the Kotlin compiler supports smart casts, it knows that, if this line doesn't throw any exception, then mockObj is an instance of IMyInterface. And it thus lets you call someMethod(), and inserts the necessary cast for you.
You can replicate this with a simpler example:
val foo: Any = "hello"
val bar = foo as String
println(foo.length) // smart cast added here
You could also use the is operator to make the compiler insert a smart cast
val foo: Any = "hello"
if (foo is String) {
println(foo.length) // smart cast added here
}

Related

Why does the Groovy #TypeChecked annotation catch me putting a String into an int variable but not the other way around?

I'm having trouble understanding Groovy types and type promotion. And the exact promises of Groovy's #TypeChecked annotation.
-- Or maybe I'm having trouble understanding some Groovy design philosophy.
I was playing around with the #TypeChecked annotation and it did not behave as expected. I made two example scripts and I expected both of them to fail because of type mismatches. But only ONE of the scripts fails.
The scripts are very similar. So I thought that they'd also behave in a similar way. The main difference is near the top: I either declare x as int or as String. And then I try to assign a different type to x.
Diff of scripts:
$ diff TypeChecked-fail-int-x.groovy TypeChecked-pass-String-x.groovy -y --width 70
#groovy.transform.TypeChecked #groovy.transform.TypeChecked
void m(){ void m(){
int x | String x
x = 123 | x = "abc"
println(x) println(x)
println(x.getClass()) println(x.getClass())
println() println()
x = "abc" | x = 123
println(x) println(x)
println(x.getClass()) println(x.getClass())
} }
m() m()
When I declare a variable as int but then try to assign a String I will get the expected error:
Script TypeChecked-fail-int-x.groovy: (Groovy web console here.)
#groovy.transform.TypeChecked
void m(){
int x
x = 123
println(x)
println(x.getClass())
println()
x = "abc"
println(x)
println(x.getClass())
}
m()
Output:
$ groovy --version
Groovy Version: 3.0.10 JVM: 11.0.17 Vendor: Ubuntu OS: Linux
$ groovy TypeChecked-fail-int-x.groovy
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/home/myuser/TypeChecked-fail-int-x.groovy: 11: [Static type checking] - Cannot assign value of type java.lang.String to variable of type int
# line 11, column 9.
x = "abc"
^
1 error
However: if I do it THE OTHER WAY AROUND then it runs fine. I would have expected the type checker to ALSO catch this.
Script TypeChecked-pass-String-x.groovy: (Groovy web console here.)
#groovy.transform.TypeChecked
void m(){
String x
x = "abc"
println(x)
println(x.getClass())
println()
x = 123
println(x)
println(x.getClass())
}
m()
Output:
$ groovy TypeChecked-pass-String-x.groovy
abc
class java.lang.String
123
class java.lang.String
And not only does it run but suddenly int 123 has become String "123"!
I expected BOTH scripts to fail.
I also tried the #CompileStatic annotation and the results were the same.
Questions:
Is this expected behavior or a bug? Sources?
Why is 123 a String now? Is there some autoboxing/casting/type-promotion going on? Can I stop this?
Update 2022-12-01: Fails even WITHOUT #TypeChecked
I found out something: The failing #TypeChecked script will fail even if you remove #TypeChecked. -- But now it fails with a different error message and AT RUNTIME (instead of at compile time).
I'm not sure if this all makes more or less sense to me now.
$ cat TypeChecked-fail-int-x.groovy | grep -v TypeChecked > no-typechecked.groovy
$ groovy no-typechecked.groovy
123
class java.lang.Integer
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'abc' with class 'java.lang.String' to class 'int'
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'abc' with class 'java.lang.String' to class 'int'
at no-typechecked.m(no-typechecked.groovy:11)
at no-typechecked.run(no-typechecked.groovy:16)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
$ groovy --version
Groovy Version: 3.0.10 JVM: 11.0.17 Vendor: Ubuntu OS: Linux
But really I wasn't that interested in the cases that #TypeChecked stopped from running. I was more interested in why did NOT stop the other case from running. And this new nugget of knowledge changes nothing about that.
Well... you came across two concepts in Groovy, Static Type Checking (TypeChecked) and Flow typing. Both of them might seem peculiar at first.
TypeChecked
TypeChecked has so-called "Type checking assignments" rules. Here is a snippet from that referred page:
An object o of type A can be assigned to a variable of type T if and
only if:
T equals A
or T is one of String, boolean, Boolean or Class (this one is the most relevant for the question)
...
For example, if you change the initial String type to Boolean you will also be surprised but that will be in line with the Groovy spec and the output will be:
true
class java.lang.Boolean
true
class java.lang.Boolean
If you are curious why the output has two true values you might want to read about The Groovy Truth.
Flow typing
Flow typing is an important concept of Groovy in type checked mode and an extension of type inference. The idea is that the compiler is capable of inferring the type of variables in the flow of the code, not just at initialization.
We are also interested in another statement from that link:
It is important to understand that it is not the fact of declaring a variable with def that triggers type inference. Flow typing works for any variable of any type. Declaring a variable with an explicit type only constrains what you can assign to the variable.
So, if you change the initial variable type from String to def you will see a different result:
abc
class java.lang.String
123
class java.lang.Integer
When the initial type is String it will always be a String variable and you can assign an object of any type to a String variable according to the "Type checking assignments" rules.
Summary
So, answering your questions:
Is this expected behavior or a bug? Sources?
Yes, this is expected. Please refer to the links and explanation above.
Why is 123 a String now? Is there some autoboxing/casting/type-promotion going on? Can I stop this?
Again, please refer to the links and explanation above. If you want the variable to change its type then define that variable through the def keyword. You can't stop this because (stating the doc again):
Flow typing has been introduced to reduce the difference in semantics between classic and static Groovy.

RunTime Error when trying to take String input using readLine in Kotlin

I am a beginner in kotlin and this is the code I tried to execute, but runtime error is being displayed. Please help me resolve this.
import java.util.*
fun main(args: Array<String>)
{
var inp = Scanner(System.`in`);
var t:Int = inp.nextInt();
repeat(t)
{
var n:Int = inp.nextInt();
var s:String = readLine()!!
for (i in s)
{
println(i);
}
println()
}
}
Exception in thread "main" kotlin.KotlinNullPointerException
at ProgKt.main(prog.kt:10) This is the error that is displayed.
Smeki's answer is right, but I just need to point something out since you're a beginner and it might get confusing.
Normally you'd do something like this:
val s = readLine()
Notice you're not specifying the type of s - it's being inferred by whatever you're assigning to it. Because readLine returns a nullable String?, which is a String that could be null (which is what the ? on the end means), then the compiler knows that s is a String?. It's the equivalent of doing this:
val s: String? = readLine()
And you can do that explicitly if you want! You usually don't need to though. And now you have your nullable s, you can do some null-checking to use it safely:
if (s != null) {
// we know it's not null, so now you can do stuff with it
} else {
// if you like, you can handle the null case separately, like breaking out of
// the loop (since null from readLine() means you've reached the end)
}
There's other ways to handle nulls and do null-checking - here's the documentation about it and I'd strongly recommend reading it and getting your head around it - it's a key part of the language! And it makes your life easier and code safer in the long run (avoids problems like this! !! gets around null-safety and it's usually a bad sign)
But remember when I said you can explicitly declare the type for s? Here's what I said it would be, and what you've written:
// correct
val s: String? = readLine()
// something's different!
val s: String = readLine()
See how you're missing the ? that says its a nullable type? Even if you're planning to null-check s after this, it's going to crash at this line because s is declared as a non-null type, and readLine() is gonna to be null at some point. When you assign null to a non-null variable, it'll crash with an error - because as far as the compiler's concerned, something's gone wrong.
(You should also get some warnings in your IDE if you're using one, trying to null-check a variable that you've declared as non-null will give you some "why are you trying to do this? It can't be null, right?" messages that hint that something's wrong somewhere. Also if you didn't add the !! after readLine(), you'd get a warning about that - probably why you added the !! in the first place! It doesn't make the problem go away, just stops the IDE from warning you about it)
Also you might have noticed, I made s a val instead of a var because it's a fixed value you're not going to change - always prefer vals unless you definitely need to change that variable, it's not such a big deal here but it makes some other things easier (you'll get warnings about that too)
Well, NPE is the most probably thrown from
var s:String = readLine()!!
where those !! are part of kotlin null-safety feature.
And from java doc of readLine() we can find out when is null returned.
/**
* Reads a line of input from the standard input stream.
*
* #return the line read or `null` if the input stream is redirected to a file and the end of file has been reached.
*/
fun readLine(): String? = LineReader.readLine(System.`in`, Charset.defaultCharset())

How recognize between function call and class instantiation in IntelliJ or Android Studio?

I learn Kotlin in Android, but many codes are scrap because I have problem recognize when is some code as call function or instantiate class.
Code not work, but for example is good:
class Boo{
val callFromFoo: Int = Foo(1)
val instanceFoo: Foo = Foo(2)
fun Foo(id: Int): Int {
return id
}
}
class Foo(val id: Int)
I'm concerned, because call Foo(1) and instantiating Foo(2) is the same code, without IDE recognizing of differences.
Note: explicit declaration is not standard in Kotlin.
If you have the classes within the same file/package you could use reflection like so:
class Boo {
val callFromFoo: Int = Foo(1)
val instanceFoo: Foo = requireNotNull(Foo::class.primaryConstructor).call(2)
fun Foo(id: Int): Int {
return id
}
}
class Foo(val id: Int)
If you have the classes in different packages, you could instantiate the object specifying that package. Like so:
class Boo {
val callFromFoo: Int = Foo(1)
val instanceFoo: Foo = com.android.example.package2.Foo(2)
fun Foo(id: Int): Int {
return id
}
}
I would not recommend either of those solutions.
Note that classes are generally nouns like Navigator, LoginUseCase, User, Logger etc and functions are generally verbs or atleast use verbs like navigateTo(), login(), processData(), log() etc. I don`t think they should ever have the same name.
Furthermore, I think the coding style you are using does not go well with Kotlin. It will create unnecessary confusion between functions and classes even if they have different names. I suggest you follow the official Kotlin coding style guide. Have function names start with lower case and class names start with upper case to avoid any confusion.
Update
If you would like to stick to your coding convention and differentiate between constructor call and function call, you could choose varying colors for each in Android Studio or IntelliJ.
Android Studio/IntelliJ:
File > Settings > Editor > Color scheme > Kotlin
Result:

How to safely cast the result of readLine() to prevent a Type Mismatch using Kotlin

Many Kotlin tutorials I have watched / read have this line of code:
var number = Integer.valueOf(readLine())
And while it clearly worked before, it is now throwing a compiler error while using Android studio and Kotlin version 1.3.50.
It indicates a type mismatch where the found is String? and the required is String.
Granted, I understand why this is happening, I get that a user could pass null or empty values in via the console and therefore it needs to have the optional null declaration, but I would like to understand how to fix the compiler error and keep similar code without changing too much.
While I can use both of these lines of code:
var number = Integer.valueOf(readLine()!!)
and
var number = Integer.valueOf(readLine() as String)
I believe those can throw different exceptions as outlined here
I know I am able to 'fix' this problem by using this code:
var number : String? = readLine();
if(number == null){
number = "0"
}
val number2 = Integer.valueOf(number);
But it seems horribly inefficient. Is there a shorter way to do this using native Kotlin code?
If we simply call toInt() on the result from readLine(), we will get an exception if the value provided isn't an actual Integer. In order to avoid an exception, we can use toIntOrNull() from the Kotlin Standard Library.
val x= readLine()?.toIntOrNull() ?: 0
In this case, we read the line (as a String?) and if it is non-null, call toIntOrNull() on it. If that is non-null, we have our answer. Otherwise, we use 0 as the default.
Even though I am primarily a Swift developer, this is a very similar concept. In Swift it is called a nil-coalescing operator, but apparently in Kotlin it is called the Elvis Operator (uh-huh).
The docs are here So your code would look like this:
var num : String = readLine() ?: "0";
If the value before the Elvis operator ?: is not null, it uses that, otherwise it uses the second default value you provide.

IntelliJ - is there an option to automatically add extra parameters to a constructor?

I am adding a 3rd parameter to this constructor (the String? memberId), does anyone know how or why IntelliJ doesn't give me the option to insert this new constructor parameter automatically? The best it can do is change the type of the next parameter, or make a second constructor, which I would have thought it should be kind of obvious to IntelliJ these are probably not useful.
The expected feature is supported in Code Completion. memberId argument is supposed in completion list with first priority. Using 'Ctrl+Space' and ',' completes the arguments. This behavior is also the same for other type of functions (not only for constructors).
Note: there is no such quick fix in case of Java:
public class Test {
private String s;
private Integer n;
Test(String s, Integer n) {
this.s = s;
this.n = n;
}
public Test foo() {
return new Test(s); // there is no quick fox to add 'n' argument but it presents in completion
}
}
FYI: There is an opposite situation when argument is added on use-site but parameter is not yet added at declaration site. Here is a ticket for supporting quick fix for that: https://youtrack.jetbrains.com/issue/KT-8478. (edited)

Resources