android, why after covert to kotlin the unit test fail - kotlin

On android app, Having a java function
JSONObject addToJson(#NonNull JSONObject jsonObject, #NonNull String key, boolean value){
try {
jsonObject.put(key, value);
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
test code, it throws when call the mock jsonObject.put(key, value) and works fine:
#Test
public void test_addToJson() throws JSONException {
JSONObject jsonObject = Mockito.spy(new JSONObject());
Mockito.when(jsonObject.put(anyString(), anyBoolean())).thenThrow(new JSONException("!!! test forced exception"));
JSONObject outputObject = addToJson(jsonObject, "null", true);
assertEquals("jsonobject length should match", 0, outputObject.length());
}
after convert to kotlin
fun addToJson(jsonObject: JSONObject, key: String, value: Boolean?): JSONObject {
try {
jsonObject.put(key, value)
} catch (e: JSONException) {
e.printStackTrace()
}
return jsonObject
}
the test is failing that no exception thrown.

The Java code uses the primitive type boolean for value. The Kotlin version is using the nullable type Boolean? which seems unnecessary since the parameter could never be null in the Java version.
The change to a nullable type might cause the anyBoolean matcher to fail. You could try switching to the non-nullable type Boolean, or keep using Boolean? and change the anyBoolean matcher to anyOrNull from mockito-kotlin.

Related

How to print exception message in Kotlin

I have defined an exception in Kotlin but when I do e.message it prints fully qualified exception name followed by message but I want to print only exception message.
public final class AbcException extends Exception {
private static final long serialVersionUID = 1L;
public AbcException() {
}
public AbcException(String message) {
super(message);
}
public AbcException(String message, Throwable cause) {
super(message, cause);
}
public AbcException(Throwable cause) {
super(cause);
}
}
I am matching asserting it in tests and want to do
assertEquals(e.message, "CaseItem delete failed: item token=token1")
But I am doing this because it prints fully qualifies exception name too
assertTrue(e.message?.contains("Case Item tokens=token2 does not exist.")!!)
Expected
"Some message"
Actual
"exceptionClass: Some message"
That's not Kotlin, it's Java.
The equivalent Kotlin exception would look something like this:
class AbcException(
message: String? = null,
cause: Throwable? = null
) : Exception(message, cause) {
// Bit odd to have an exception that wraps a cause with no message, but ok.
constructor(cause: Throwable): this(null, cause)
}
The playground test does as expected, only prints the message, excluding the exception type name:
fun main() {
try {
throw AbcException("Hello")
} catch(e: Exception) {
println(e.message)
}
}
Hello

Gson Type Adapter with both custom and default deserialization logic

I have a gson model class which contains a variable named duration which is an integer. The problem is that when this variable has no value the server instead of returning me null it returns "".
This is also the case with lists, when I am expecting a List<String>? and there is no value in them I get "" instead of null. Unfortunately the server can not change.
I have fixed the problem with a custom double deserializer but I need something more generic because the "" is the default server approach. Here is my progress so far but on the else branch I do not know how to tell it to continue with the default deserializer.
internal class BadDeserializer : JsonDeserializer<Any> {
#Throws(JsonParseException::class)
override fun deserialize(
json: JsonElement,
type: Type,
context: JsonDeserializationContext): Any? {
return try {
val json = json.asString
if (json.isBlank()) {
null
} else {
//Do nothing and call default behavior (?)
}
} catch (e: Exception) {
throw JsonParseException(e)
}
}
}
That's an unfortunate response getting an empty string.
AFAIK you can't register a type adapter for primitive types with GSON, though perhaps its possible to register one for their boxed types (not sure how this may work with Kotlin).
If you can use the boxed types, then you could use something like the following:
public class DoubleAdapter implements JsonDeserializer<Double> {
#Override
public Double deserialize(final JsonElement json,
final Type typeOfT,
final JsonDeserializationContext ctx) throws JsonParseException {
if (!json.isJsonPrimitive()) {
throw new JsonParseException("primitive expected");
}
final JsonPrimitive primitive = json.getAsJsonPrimitive();
if (primitive.isString()) {
final String value = primitive.getAsString();
if ("".equals(value)) return null;
throw new JsonParseException("double expected, not string");
}
if (!primitive.isNumber()) {
throw new JsonParseException("double expected");
}
return primitive.getAsNumber().doubleValue();
}
}
Though it might be cleaner (and I usually do for everything) to write an adapter for whatever structure you have.

Kotlin case of non-intuitive type inference

I found some non-intuitive behavior of type inference. As a result, the semantically equivalent code works differently, depending on what information the compiler infers about function return type. It is more or less clear what is going on when you reproduce this case in a minimum unit test. But I afraid that when writing framework code, such behavior could be dangerous.
The code below illustrates the problem, and my questions are:
Why the puzzler1 call from notok1 unconditionally throws NPE? As far as I understand from the bytecode, ACONST_NULL ATHROW throws NPE right after puzzler1 call, ignoring the returned value.
Is it normal that upper bound (<T : TestData>) is ignored when compiler infers the type?
Is it a bug that NPE becomes ClassCastException if you add suspend modifier to the function? Of course, I understand that runBlocking+suspend call gives us the different bytecode, but shouldn't the "coroutinized" code be as equivalent as possible to conventional code?
Is there a way to rewrite puzzler1 code somehow, eliminating the unclearness?
#Suppress("UnnecessaryVariable", "MemberVisibilityCanBePrivate", "UNCHECKED_CAST", "RedundantSuspendModifier")
class PuzzlerTest {
open class TestData(val value: String)
lateinit var whiteboxResult: TestData
fun <T : TestData> puzzler1(
resultWrapper: (String) -> T
): T {
val result = try {
resultWrapper("hello")
} catch (t: Throwable) {
TestData(t.message!!) as T
}
whiteboxResult = result
return result // will always return TestData type
}
// When the type of `puzzler1` is inferred to TestData, the code works as expected:
#Test
fun ok() {
val a = puzzler1 { TestData("$it world") }
// the same result inside `puzzler1` and outside of it:
assertEquals("hello world", whiteboxResult.value)
assertEquals("hello world", a.value)
}
// But when the type of `puzzler1` is not inferred to TestData, the result is rather unexpected.
// And compiler ignores the upper bound <T : TestData>:
#Test
fun notok1() {
val a = try {
puzzler1 { throw RuntimeException("goodbye") }
} catch (t: Throwable) {
t
}
assertEquals("goodbye", whiteboxResult.value)
assertTrue(a is NullPointerException) // this is strange
}
// The same code as above, but with enough information for the compiler to infer the type:
#Test
fun notok2() {
val a = puzzler1 {
#Suppress("ConstantConditionIf")
if (true)
throw RuntimeException("goodbye")
else {
// the type is inferred from here
TestData("unreachable")
// The same result if we write:
// puzzler1<TestData> { throw RuntimeException("goodbye") }
}
}
assertEquals("goodbye", whiteboxResult.value)
assertEquals("goodbye", (a as? TestData)?.value) // this is stranger
}
// Now create the `puzzler2` which only difference from `puzzler1` is `suspend` modifier:
suspend fun <T : TestData> puzzler2(
resultWrapper: (String) -> T
): T {
val result = try {
resultWrapper("hello")
} catch (t: Throwable) {
TestData(t.message!!) as T
}
whiteboxResult = result
return result
}
// Do exactly the same test as `notok1` and NullPointerException magically becomes ClassCastException:
#Test
fun notok3() = runBlocking {
val a = try {
puzzler2 { throw RuntimeException("goodbye") }
} catch (t: Throwable) {
t
}
assertEquals("goodbye", whiteboxResult.value)
assertTrue(a is ClassCastException) // change to coroutines and NullPointerException becomes ClassCastException
}
// The "fix" is the same as `notok2` by providing the compiler with info to infer `puzzler2` return type:
#Test
fun notok4() = runBlocking {
val a = try {
puzzler2<TestData> { throw RuntimeException("goodbye") }
// The same result if we write:
// puzzler2 {
// #Suppress("ConstantConditionIf")
// if (true)
// throw RuntimeException("goodbye")
// else
// TestData("unreachable")
// }
} catch (t: Throwable) {
t
}
assertEquals("goodbye", whiteboxResult.value)
assertEquals("goodbye", (a as? TestData)?.value)
}
}
What is the type of throw RuntimeException("goodbye")? Well, since it never returns a value, you can use it anywhere you like, no matter what type of object is expected, and it will always typecheck. We say that it has type Nothing. This type has no values, and it is a subtype of every type. Therefore, in notok1, you have a call to puzzler1<Nothing>. The cast from the constructed TestData to T = Nothing inside puzzler1<Nothing> is unsound but unchecked, and puzzler1 ends up returning when its type signature says it shouldn't be able to. notok1 notices that puzzler1 has returned when it said it would not be able to, and immediately throws an exception itself. It's not very descriptive, but I believe the reason it throws an NPE is because something has gone "terribly wrong" if a function that can't return has returned, so the language decides the program should die as fast as possible.
For notok2, you actually do get T = TestData: one branch of the if returns Nothing, the other TestData, and the LUB of those is TestData (since Nothing is a subtype of TestData). notok2 has no reason to believe that puzzler1<TestData> cannot return, so it doesn't set up the trap to die as soon as puzzler1 returns.
notok3 has essentially the same problem as notok1. The return type, Nothing, implies that the only thing the puzzler2<Nothing> will do is throw an exception. The coroutine handling code in notok3 thus expects the coroutine to hold a Throwable and contains code to rethrow it, but does not contain code to handle an actual return value. When puzzler2 actually does return, notok3 tries to cast that TestData into a Throwable and fails. notok4 works for the same reason notok2 does.
The solution to this mess is simply not using an unsound cast. Sometimes puzzler1<T>/puzzler2<T> will be able to return a T, if the passed function in fact returns a T. But, if that function throws, they can only return a TestData, and a TestData is not a T (a T is a TestData, not the other way around). The correct signature for puzzler1 (and similarly for puzzler2) is
fun <T : TestData> puzzler1(resultWrapper: (String) -> T): TestData
Since functions are covariant in the return type, you can just get rid of the type parameter
fun puzzler1(resultWrapper: (String) -> TestData): TestData

Converting Java Parcel creator code to Kotlin

I'm trying to convert my Parcel Creator code from Java to Kotlin. The auto code converter fails at this and I'm not sure how to resolve it. The code I'm converting is:
public static final Creator<Save> CREATOR = new Creator<Save>() {
#Override
public Save[] newArray(int size) {
return new Save[size];
}
#Override
public Save createFromParcel(Parcel incoming) {
return new Save(incoming);
}
};
I end up with this:
val CREATOR: Parcelable.Creator<Save> = object : Parcelable.Creator<Save> {
override fun newArray(size: Int): Array<Save> {
return arrayOfNulls(size)
}
override fun createFromParcel(incoming: Parcel): Save {
return Save(incoming)
}
}
which gives an error saying 'Type inference failed' for arrayOfNulls(size). I have tried changing it to Save(size) but that doesn't work either. Any Ideas?
arrayOfNulls will return an array of nullable elements, Array<Save?> in this case. You should change your function's return type to match that.
override fun newArray(size: Int): Array<Save?> {
return arrayOfNulls(size)
}
You can try this plugin to do Parcelable, just suggestion, I never tried but come across while googling.

Ensuring a val is initialised in Kotlin

I have the following method in Java:
public void doSomething() {
final boolean promote = false;
final String bob;
if (promote) {
try(StringWriter sw = new StringWriter()) {
sw.write("this is a test");
bob = sw.toString();
} catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException();
}
} else {
bob = "anaconda";
}
System.out.println(bob);
}
When I convert this to Kotlin:
val promote = false
val bob: String
if (promote) {
try {
StringWriter().use { sw ->
sw.write("this is a test")
bob = sw.toString()
}
} catch (e: IOException) {
e.printStackTrace()
throw IllegalStateException()
}
} else {
bob = "anaconda"
}
println(bob)
But I get a compiler error on the last line: Variable 'bob' must be initialized.
I can't see how Kotlin could fail to initialise the bob variable when the Java compiler is so sure that the variable has either been initialised or an exception has been thrown.
Is my only option to change bob to a var and initialise it?
Assign the result of use method to the variable like so:
bob = StringWriter().use { sw ->
sw.write("this is a test")
sw.toString()
}
The Java compiler is able to figure out that the variable will be initialised because the try with resources is a language feature. The use method on the other hand is a library feature with behavior dependent on the implementation that is actually imported and used. In other words the Kotlin compiler has no way of knowing if the function passed as an argument to use will be invoked immediately or not.