in kotlin how use #IntDef - kotlin

In Java code the #IntDef works if the int passed in is not from one of the #intDef.
But after convert to kotlin the #IntDef does not work any more.
In kotlin the #IntDef is:
object LogLevels {
const val VERBOSE = Log.VERBOSE
const val DEBUG = Log.DEBUG
const val INFO = Log.INFO
const val WARN = Log.WARN
const val ERROR = Log.ERROR
const val WTF = Log.ASSERT
#IntDef(VERBOSE, DEBUG, INFO, WARN, ERROR, WTF)
#Retention(AnnotationRetention.SOURCE)
annotation class LogLevel
}
Having a function:
fun getTest(#LogLevel `in`: Int): Int {
return 0
}
But after changed the #IntDef in kotlin code, the function call does not complain that the type is not correct:
How to make #IntDef in kotlin?

Related

Attempt to invoke interface method on a null object reference in kotlin

After implementing viewmodels to jetpack compose app when I running the app it's showing a error :-
Attempt to invoke interface method 'boolean java.util.Set.contains(java.lang.Object)' on a null object reference
java.lang.NullPointerException: Attempt to invoke interface method 'boolean java.util.Set.contains(java.lang.Object)' on a null object reference
at com.example.android.ui.GameViewModel.pickRandomWordAndShuffle(GameViewModel.kt:21)
at com.example.android.ui.GameViewModel.(GameViewModel.kt:10)
here is my code:-
import androidx.lifecycle.ViewModel
import com.example.android.unscramble.data.allWords
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
class GameViewModel : ViewModel() {
private val _uiState =
MutableStateFlow(GameUiState(currentScrambledWord = pickRandomWordAndShuffle()))
val uiState: StateFlow<GameUiState> = _uiState.asStateFlow()
private var _count = 0
val count: Int
get() = _count
private lateinit var currentWord: String
private var usedWords: MutableSet<String> = mutableSetOf()
private fun shuffleCurrentWord(word: String): String {
val tempWord = word.toCharArray()
// Scramble the word
tempWord.shuffle()
while (String(tempWord) == word) {
tempWord.shuffle()
}
return String(tempWord)
}
private fun pickRandomWordAndShuffle(): String {
// Continue picking up a new random word until you get one that hasn't been used before
currentWord = allWords.random()
if (usedWords.contains(currentWord)) {
return pickRandomWordAndShuffle()
} else {
usedWords.add(currentWord)
return shuffleCurrentWord(currentWord)
}
}
private fun resetGame() {
usedWords.clear()
_uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle())
}
init {
resetGame()
}
}
It's not showing any compile time errors. I don't konw what should I do.
You're initializing _uiState before you initialize usedWords. This calls pickRandomWordAndShuffle() before usedWords has been initialized, so it's still null in the GameViewModel instance being created.
If you move the declaration of usedWords above _uiState it should work.
HOWEVER: It's generally a bad idea to call member functions before an instance has been fully initialized, for this exact reason.
You could make _uiState and uiState lazy, which would make this safer. For example:
// Copyright 2023 Google LLC.
// SPDX-License-Identifier: Apache-2.0
private val _uiState by lazy {
MutableStateFlow(GameUiState(currentScrambledWord = pickRandomWordAndShuffle()))
}
val uiState: StateFlow<GameUiState> by lazy { _uiState.asStateFlow() }
which will wait until something uses uiState (which looking at your code only happens externally, so you'll be guaranteed that it won't be initialized until the GameViewModel has been fully initialized.

How to find is a lateinit var has been initialized via Reflection?

I want to find out via reflection if lateinit property of an object has been initialized. How do I got about doing that?
Getting the property and checking non-null results in UninitializedPropertyAccessException
fun Any.isAnyEntityInitialized () {
val clazz = this.javaClass.kotlin
val filteredEntities = clazz.declaredMemberProperties.filter {
it.isLateinit && getDelegate(this) != null
}
}
This works for me:
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.jvm.javaField
class Test {
lateinit var s: String
}
fun Any.isAnyEntityInitialized(): Boolean =
this::class.declaredMemberProperties.any { property ->
property.isLateinit && property.javaField?.get(this) != null
}
fun main() {
val test = Test()
println(test.isAnyEntityInitialized()) // prints false
test.s = "test"
println(test.isAnyEntityInitialized()) // prints true
}
Since Kotlin 1.2, there is already a function for that.
You can use the function: isInitialized docs
Code example:
lateinit var key: String
fun useKey() {
check(::key.isInitialized) { "The field 'key' must be initialized" }
// use key safely
}
Note: check will throw an IllegalStateException if the variable is not initialized.

kotlin-test: How to test for a specific type like: "is y instance of X"

How to test if a val/var is of an expected type?
Is there something I am missing in Kotlin Test, like:
value shouldBe instanceOf<ExpectedType>()
Here is how I implemented it:
inline fun <reified T> instanceOf(): Matcher<Any> {
return object : Matcher<Any> {
override fun test(value: Any) =
Result(value is T, "Expected an instance of type: ${T::class} \n Got: ${value::class}", "")
}
}
In KotlinTest, a lot is about proper spacing :)
You can use should to get access to a variety of built-in matchers.
import io.kotlintest.matchers.beInstanceOf
import io.kotlintest.should
value should beInstanceOf<Type>()
There is also an alternative syntax:
value.shouldBeInstanceOf<Type>()
See here for more information.
Since Kotlin 1.5 there is a nice solution included in kotlin-test:
assertIs<TypeExpected>(value)
This will not only assert that value is of type TypeExpected, it will also smart cast value, so that you can access all methods of TypeExpected. Just include the dependency, e.g:
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5:1.7.10")
And you can do stuff like this
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
class AssertIsTests {
#Test
fun `test for list`() {
val list = Collector.List.collect(1, 1, 2, 2, 3)
assertEquals(5, list.size)
// assertEquals(1, list[0]) won't compile: list is of type Collection<Int> which doesn't support []
assertIs<List<Int>>(list) // from now on list is of type List<Int>!
assertEquals(4, list.indexOf(3)) // now there are all list methods
assertEquals(1, list[0]) // including indexed getters
}
#Test
fun `test for set`() {
val set = Collector.Set.collect(1, 1, 2, 2, 3)
assertEquals(3, set.size) // Set with duplicates removed
assertIs<Set<Int>>(set) // from now on set is of Type Set<Int>
}
}
enum class Collector {
List {
override fun collect(vararg args: Int) = args.toList()
},
Set {
override fun collect(vararg args: Int) = args.toSet()
};
abstract fun collect(vararg args: Int): Collection<Int>
}

Mockito when clause not working in kotlin

I am trying to use mockito in kotlin. I created the following test:
class HeroesDataSourceTest {
#Mock
lateinit var heroesRepository: HeroesRepository
#Mock
lateinit var params: PageKeyedDataSource.LoadInitialParams<Int>
#Mock
lateinit var callback: PageKeyedDataSource.LoadInitialCallback<Int, Heroes.Hero>
val hero = Heroes.Hero(1, "superman", "holasuperman", 1, null, null)
val results = Arrays.asList(hero)
val data = Heroes.Data(results)
val dataResult = Heroes.DataResult(data)
val compositeDisposable = CompositeDisposable()
lateinit var heroesDataSource: HeroesDataSource
private val heroesPublishSubject = PublishSubject.create<Heroes.DataResult>()
#Before
fun initTest(){
MockitoAnnotations.initMocks(this)
}
#Test
fun testLoadInitialSuccess(){
`when`(heroesRepository.getHeroes(ArgumentMatchers.anyInt())).thenReturn(heroesPublishSubject.singleOrError())
heroesDataSource = HeroesDataSource(heroesRepository, compositeDisposable)
val testObserver = TestObserver<Heroes.DataResult>()
heroesDataSource.loadInitial(params, callback)
heroesPublishSubject.onNext(dataResult)
testObserver.assertComplete()
}
}
But when I execute it in the line when(heroesRepository.getHeroes(ArgumentMatchers.anyInt())).thenReturn(heroesPublishSubject.singleOrError()) it just enter to getHeroes method instead of mocking it (and for sure since heroesRepository is not initialized because is mocket the method fails). I use this tons of times in java and it never gave me a single problem. What I have to do in kotlin to mock it properly?
EDIT
Here I put also HeroesRepository class
open class HeroesRepository {
val privateKey = "5009bb73066f50f127907511e70f691cd3f2bb2c"
val publicKey = "51ef4d355f513641b490a80d32503852"
val apiDataSource = DataModule.create()
val pageSize = 20
fun getHeroes(page: Int): Single<Heroes.DataResult> {
val now = Date().time.toString()
val hash = generateHash(now + privateKey + publicKey)
val offset: Int = page * pageSize
return apiDataSource.getHeroes(now, publicKey, hash, offset, pageSize)
}
fun generateHash(variable: String): String {
val md = MessageDigest.getInstance("MD5")
val digested = md.digest(variable.toByteArray())
return digested.joinToString("") {
String.format("%02x", it)
}
}
}
Without adding another dependency, you can replace using the #Mock annotation with a helper function somewhere:
inline fun <reified T> mock(): T =
Mockito.mock(T::class.java)
// To avoid having to use backticks for "when"
fun <T> whenever(methodCall: T): OngoingStubbing<T> =
Mockito.`when`(methodCall)
Then in your test:
val heroesRepository: HeroesRepository = mock()
#Test
fun yourTest() {
whenever(heroesRepository.getHeroes(ArgumentMatchers.anyInt()))
.thenReturn(heroesPublishSubject.singleOrError())
}
Like you had before. This should work, because you're not expecting Mockito to deal with #Mock lateinit var, which it seems to be struggling with, and instead instantiating the mock yourself.
FWIW, the reason that the when statement is just calling the actual function is because the function itself (getHeroes) is not marked as open.
So even though the class is non-final the method is final and not mocked.
Mockito is not quite compatible with kotlin, you can use mockito-kotlin resource instead.
Check out this reference:
https://github.com/nhaarman/mockito-kotlin
You can easily mock objects like so:
val heroesRepository = mock<HeroesRepository>()
Then you can use it as you use mockito

Wrong inference for reified type parameter in Kotlin

Given the following code in Kotlin:
import com.fasterxml.jackson.module.kotlin.*
data class MyReply<R> (
val results : Array<R>? = null
)
class ErrorClient() {
val JSON = jacksonObjectMapper()
inline fun<reified R> request(): Array<R>? {
val json_in = """{"results": [2]}"""
val res: MyReply<R> = JSON.readValue(json_in)
return res.results
}
fun read(): Array<Int>? {
val res: Array<Int>? = request()
return res
}
}
and the following tests:
import org.junit.Test
class ErrorTest {
val client = ErrorClient()
#Test
fun `direct`() {
val res: Array<Int>? = client.request()
println(res)
}
#Test
fun `indirect`() {
val res : Array<Int>? = client.read()
println(res)
}
}
Short story: The first test passes and the second fails. Why?
Long story: I am experiencing a wrong type inference of the reified parameter R when calling the inline function via the read() class method, but the direct call to request() works. In the indirect case the type is erronously inferred to be java.lang.Object and thus the test fails with
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
at ErrorClient.read(Error.kt:17)
at ErrorTest.indirect(ErrorTest.kt:14)
This is not about reified. I test the code with
val res: MyReply<R> = MyReply()
It does not throw any errors. This problem is your JSON.readValue return an Object instead of Integer. Kotlin try to cast it to Integer but it fails.