Mockk: Bug: StackOverflowError when mocking ArrayList on Android 9

Created on 6 Aug 2019  路  4Comments  路  Source: mockk/mockk

The following snippets cause StackOverflowError on Android 9. The problem doesn't occur on lower API versions.

val mock = mockk<ArrayList<String>>()
 val mock = mockk<Class_With_ArrayList>()
 every { mock.myArrayList } returns ArrayList()

Expected Behavior

I am able to mock an ArrayList or get a clear exception why it's not possible
I am able to mock Class_With_ArrayList and stub it's property access

Current Behavior

The processes crashes with a StackOverflowError

Failure Information (for bugs)

Steps to Reproduce

  1. Create a new project in AS
  2. Add mockk-android 1.9.3 to android test
  3. Add class with a single field of type ArrayList
  4. Use the snippets above in your android instrumented test

Context

  • MockK version: 1.9.3
  • OS: MacOS
  • Kotlin version: 1.3.31
  • JDK version: default for AS 3.4
  • JUnit version: N/A
  • Type of test: android instrumented test

Stack trace

// -----------------------[ YOUR STACK STARTS HERE ] -----------------------
2019-08-06 13:33:27.641 27929-27938/com.example.mockkarraylist E/System: java.lang.StackOverflowError: stack size 1041KB
        at java.lang.ref.PhantomReference.<init>(PhantomReference.java:80)
        at sun.misc.Cleaner.<init>(Cleaner.java:115)
        at sun.misc.Cleaner.create(Cleaner.java:133)
        at libcore.util.NativeAllocationRegistry.registerNativeAllocation(NativeAllocationRegistry.java:130)
        at java.util.regex.Matcher.usePattern(Matcher.java:242)
        at java.util.regex.Matcher.<init>(Matcher.java:186)
        at java.util.regex.Pattern.matcher(Pattern.java:1010)
        at kotlin.text.Regex.matchEntire(Regex.kt:136)
        at io.mockk.proxy.android.MethodDescriptor.<init>(MethodDescriptor.kt:8)
        at io.mockk.proxy.android.advice.Advice.getOrigin(Advice.kt:28)
        at java.lang.reflect.Method.invoke(Native Method)
        at io.mockk.proxy.android.AndroidMockKDispatcher.getOrigin(AndroidMockKDispatcher.java:117)
        at java.util.AbstractCollection.isEmpty(Unknown Source:14)
        at io.mockk.proxy.android.MethodDescriptor.<init>(MethodDescriptor.kt:90)
        at io.mockk.proxy.android.advice.Advice.getOrigin(Advice.kt:28)
        at java.lang.reflect.Method.invoke(Native Method)
        at io.mockk.proxy.android.AndroidMockKDispatcher.getOrigin(AndroidMockKDispatcher.java:117)
(...)
        at java.util.ArrayList.iterator(Unknown Source:14)
        at android.support.test.internal.runner.TestExecutor.reportRunEnded(TestExecutor.java:89)
        at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:65)
        at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)
// -----------------------[ YOUR STACK TRACE ENDS HERE ] -----------------------

Minimal reproducible code (the gist of this issue)

// -----------------------[ GRADLE DEFINITIONS ] -----------------------
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    androidTestImplementation "io.mockk:mockk-android:1.9.3"
}
// -----------------------[ YOUR CODE STARTS HERE ] -----------------------
package com.example.mockkarraylist

import android.support.test.runner.AndroidJUnit4
import io.mockk.every
import io.mockk.mockk
import org.junit.Test
import org.junit.runner.RunWith

class Class_With_ArrayList {
    val myArrayList = ArrayList<String>()
}

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    @Test
    fun mock_array_list() {
        val mock = mockk<ArrayList<String>>()
    }

    @Test
    fun mock_object_with_array_list() {
        val mock = mockk<Class_With_ArrayList>()

        every { mock.myArrayList } returns ArrayList()
    }
}
---------------[ YOUR CODE ENDS HERE ] -----------------------

https://github.com/Jedyny/mockk-array-list <- sample project to demonstrate the issue

important

Most helpful comment

It's clearly a bug and I don't think it should be closed.

All 4 comments

Also seeing this for

val pagedList: PagedList<T> = mockk(relaxed = true)
val index = slot<Int>()
every { pagedList.get(index = capture(index)) } answers { list[index.captured] }

on Android Q.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. If you are sure that this issue is important and should not be marked as stale just ask to put an important label.

It's clearly a bug and I don't think it should be closed.

The same issue occurs while mocking a LinkedHashSet.

Was this page helpful?
0 / 5 - 0 ratings